Files
vtsuru.live/message_render_content.txt
Megghy 8b908f5ac9 feat: 添加歌曲列表分页功能和键盘快捷键支持
- 在 SongList 组件中实现分页功能,支持上一页和下一页操作
- 添加键盘快捷键,允许用户通过方向键进行翻页
- 优化组件结构,增强可读性和用户体验
2025-04-28 04:04:21 +08:00

679 lines
45 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<yt-live-chat-renderer
class="style-scope yt-live-chat-app"
style="--scrollbar-width:11px;"
hide-timestamps
@mousemove="refreshCantScrollStartTime"
>
<ticker
v-model:messages="paidMessages"
class="style-scope yt-live-chat-renderer"
:show-gift-name="showGiftName || undefined"
/>
<yt-live-chat-item-list-renderer
class="style-scope yt-live-chat-renderer"
allow-scroll
>
<div
id="item-scroller"
ref="scroller"
class="style-scope yt-live-chat-item-list-renderer animated"
@scroll="onScroll"
>
<div
id="item-offset"
ref="itemOffset"
class="style-scope yt-live-chat-item-list-renderer"
>
<div
id="items"
ref="items"
class="style-scope yt-live-chat-item-list-renderer"
style="overflow: hidden"
:style="{ transform: `translateY(${Math.floor(scrollPixelsRemaining)}px)` }"
>
<template
v-for="message in messages"
:key="message.id"
>
<text-message
v-if="message.type === MESSAGE_TYPE_TEXT"
class="style-scope yt-live-chat-item-list-renderer"
:time="message.time"
:avatar-url="message.avatarUrl"
:author-name="message.authorName"
:author-type="message.authorType"
:privilege-type="message.privilegeType"
:content-parts="getShowContentParts(message)"
:repeated="message.repeated"
/>
<paid-message
v-else-if="message.type === MESSAGE_TYPE_GIFT"
class="style-scope yt-live-chat-item-list-renderer"
:time="message.time"
:avatar-url="message.avatarUrl"
:author-name="getShowAuthorName(message)"
:price="message.price"
:price-text="message.price <= 0 ? getGiftShowNameAndNum(message) : ''"
:content="message.price <= 0 ? '' : getGiftShowContent(message, showGiftName)"
/>
<membership-item
v-else-if="message.type === MESSAGE_TYPE_MEMBER"
class="style-scope yt-live-chat-item-list-renderer"
:time="message.time"
:avatar-url="message.avatarUrl"
:author-name="getShowAuthorName(message)"
:privilege-type="message.privilegeType"
:title="message.title"
/>
<paid-message
v-else-if="message.type === MESSAGE_TYPE_SUPER_CHAT"
class="style-scope yt-live-chat-item-list-renderer"
:time="message.time"
:avatar-url="message.avatarUrl"
:author-name="getShowAuthorName(message)"
:price="message.price"
:content="getShowContent(message)"
/>
</template>
</div>
</div>
</div>
</yt-live-chat-item-list-renderer>
</yt-live-chat-renderer>
</template>
<script>
import _ from 'lodash'
import Ticker from './Ticker.vue'
import TextMessage from './TextMessage.vue'
import MembershipItem from './MembershipItem.vue'
import PaidMessage from './PaidMessage.vue'
import * as constants from './constants'
import { defineComponent } from 'vue'
import { useDebounceFn } from '@vueuse/core'
// 瑕佹坊鍔犵殑娑堟伅绫诲瀷
const ADD_MESSAGE_TYPES = [
constants.MESSAGE_TYPE_TEXT,
constants.MESSAGE_TYPE_GIFT,
constants.MESSAGE_TYPE_MEMBER,
constants.MESSAGE_TYPE_SUPER_CHAT,
]
// 鍙戦€佹秷鎭椂闂撮棿闅旇寖鍥?
const MESSAGE_MIN_INTERVAL = 80
const MESSAGE_MAX_INTERVAL = 1000
// 姣忔鍙戦€佹秷鎭悗澧炲姞鐨勫姩鐢绘椂闂达紝瑕佹瘮MESSAGE_MIN_INTERVAL绋嶅井澶т竴鐐癸紝澶皬浜嗗姩鐢讳笉杩炵画锛屽お澶т簡鍙戦€佹秷鎭椂浼氫腑鏂姩鐢?
// 84 = ceil((1000 / 60) * 5)
const CHAT_SMOOTH_ANIMATION_TIME_MS = 84
// 婊氬姩鏉¤窛绂诲簳閮ㄥ皬浜庡灏戝儚绱犲垯璁や负鍦ㄥ簳閮?
const SCROLLED_TO_BOTTOM_EPSILON = 15
export default defineComponent({
name: 'ChatRenderer',
components: {
Ticker,
TextMessage,
MembershipItem,
PaidMessage
},
props: {
maxNumber: {
type: Number,
default: 60
},
showGiftName: {
type: Boolean,
default: false
},
customCss: {
type: String,
default: ''
},
},
data() {
let customStyleElement = document.createElement('style')
document.head.appendChild(customStyleElement)
const setCssDebounce = useDebounceFn(() => {
customStyleElement.innerHTML = this.customCss ?? ''
console.log('[blivechat] 宸茶缃嚜瀹氫箟鏍峰紡')
}, 1000)
return {
MESSAGE_TYPE_TEXT: constants.MESSAGE_TYPE_TEXT,
MESSAGE_TYPE_GIFT: constants.MESSAGE_TYPE_GIFT,
MESSAGE_TYPE_MEMBER: constants.MESSAGE_TYPE_MEMBER,
MESSAGE_TYPE_SUPER_CHAT: constants.MESSAGE_TYPE_SUPER_CHAT,
messages: [], // 鏄剧ず鐨勬秷鎭?
paidMessages: [], // 鍥哄畾鍦ㄤ笂鏂圭殑娑堟伅
smoothedMessageQueue: [], // 骞虫粦娑堟伅闃熷垪锛岀敱澶栭儴璋冪敤addMessages绛夋柟娉曟坊鍔?
emitSmoothedMessageTimerId: null, // 娑堣垂骞虫粦娑堟伅闃熷垪鐨勫畾鏃跺櫒ID
enqueueIntervals: [], // 鏈€杩戣繘闃熷垪鐨勬椂闂撮棿闅旓紝鐢ㄦ潵浼拌涓嬫杩涢槦鍒楃殑鏃堕棿
lastEnqueueTime: null, // 涓婃杩涢槦鍒楃殑鏃堕棿
estimatedEnqueueInterval: null, // 浼拌鐨勪笅娆¤繘闃熷垪鏃堕棿闂撮殧
messagesBuffer: [], // 鏆傛椂鏈樉绀虹殑娑堟伅锛屽綋涓嶈兘鑷姩婊氬姩鏃朵細绉帇鍦ㄨ繖
preinsertHeight: 0, // 鎻掑叆鏂版秷鎭箣鍓峣tems鐨勯珮搴?
isSmoothed: true, // 鏄惁骞虫粦婊氬姩锛屽綋娑堟伅澶揩鏃朵笉骞虫粦婊氬姩
chatRateMs: 1000, // 鐢ㄦ潵璁$畻娑堟伅閫熷害
scrollPixelsRemaining: 0, // 骞虫粦婊氬姩鍓╀綑鍍忕礌
scrollTimeRemainingMs: 0, // 骞虫粦婊氬姩鍓╀綑鏃堕棿
lastSmoothChatMessageAddMs: null, // 涓婃showNewMessages鏃堕棿
smoothScrollRafHandle: null, // 骞虫粦婊氬姩requestAnimationFrame鍙ユ焺
lastSmoothScrollUpdate: null, // 骞虫粦婊氬姩涓婁竴甯ф椂闂?
atBottom: true, // 婊氬姩鍒板簳閮紝鐢ㄦ潵鍒ゆ柇鑳藉惁鑷姩婊氬姩
cantScrollStartTime: null, // 寮€濮嬩笉鑳借嚜鍔ㄦ粴鍔ㄧ殑鏃堕棿锛岀敤鏉ラ槻姝㈠崱浣?
customStyleElement,
setCssDebounce,
}
},
computed: {
canScrollToBottom() {
return this.atBottom/* || this.allowScroll */
}
},
watch: {
canScrollToBottom(val) {
this.cantScrollStartTime = val ? null : new Date()
},
watchCustomCss: {
immediate: true,
handler(val, oldVal) {
this.setCssDebounce(val)
}
}
},
mounted() {
this.scrollToBottom()
},
beforeUnmount() {
if (this.emitSmoothedMessageTimerId) {
window.clearTimeout(this.emitSmoothedMessageTimerId)
this.emitSmoothedMessageTimerId = null
}
this.clearMessages()
document.head.removeChild(this.customStyleElement)
},
methods: {
getGiftShowContent(message) {
return constants.getGiftShowContent(message, this.showGiftName)
},
getGiftShowNameAndNum: constants.getGiftShowNameAndNum,
getShowContent: constants.getShowContent,
getShowContentParts: constants.getShowContentParts,
getShowAuthorName: constants.getShowAuthorName,
addMessage(message) {
this.addMessages([message])
},
addMessages(messages) {
this.enqueueMessages(messages)
},
setCss(css) {
this.setCssDebounce(css)
},
// 鍚庢倲鍔犺繖涓姛鑳戒簡
mergeSimilarText(content) {
content = content.trim().toLowerCase()
for (let message of this.iterRecentMessages(5)) {
if (message.type !== constants.MESSAGE_TYPE_TEXT) {
continue
}
let messageContent = message.content.trim().toLowerCase()
let longer, shorter
if (messageContent.length > content.length) {
longer = messageContent
shorter = content
} else {
longer = content
shorter = messageContent
}
if (
longer.indexOf(shorter) !== -1 // 闀跨殑鍖呭惈鐭殑
&& longer.length - shorter.length < shorter.length // 闀垮害宸緝灏?
) {
this.updateMessage(message.id, {
$add: {
repeated: 1
}
})
return true
}
}
return false
},
mergeSimilarGift(authorName, price, _freePrice, giftName, num) {
for (let message of this.iterRecentMessages(5)) {
if (
message.type === constants.MESSAGE_TYPE_GIFT
&& message.authorName === authorName
&& message.giftName === giftName
) {
this.updateMessage(message.id, {
$add: {
price: price,
// freePrice: freePrice, // 鏆傛椂娌$敤鍒?
num: num
}
})
return true
}
}
return false
},
// 浠庢柊鍒拌€佽凯浠um鏉℃秷鎭紝娉ㄦ剰浼氳凯浠moothedMessageQueue锛屼笉浼氳凯浠aidMessages
*iterRecentMessages(num, onlyCountAddMessages = true) {
if (num <= 0) {
return
}
for (let arr of this.iterMessageArrs()) {
for (let i = arr.length - 1; i >= 0 && num > 0; i--) {
let message = arr[i]
yield message
if (!onlyCountAddMessages || this.isAddMessage(message)) {
num--
}
}
if (num <= 0) {
break
}
}
},
// 浠庢柊鍒拌€佽凯浠f秷鎭殑鏁扮粍
*iterMessageArrs() {
for (let i = this.smoothedMessageQueue.length - 1; i >= 0; i--) {
yield this.smoothedMessageQueue[i]
}
yield this.messagesBuffer
yield this.messages
},
delMessage(id) {
this.delMessages([id])
},
delMessages(ids) {
this.enqueueMessages(ids.map(
id => ({
type: constants.MESSAGE_TYPE_DEL,
id
})
))
},
clearMessages() {
this.messages = []
this.paidMessages = []
this.smoothedMessageQueue = []
this.messagesBuffer = []
this.isSmoothed = true
this.lastSmoothChatMessageAddMs = null
this.chatRateMs = 1000
this.lastSmoothScrollUpdate = null
this.scrollTimeRemainingMs = this.scrollPixelsRemaining = 0
this.smoothScrollRafHandle = null
this.preinsertHeight = 0
this.maybeResizeScrollContainer()
if (!this.atBottom) {
this.scrollToBottom()
}
},
updateMessage(id, newValuesObj) {
this.enqueueMessages([{
type: constants.MESSAGE_TYPE_UPDATE,
id,
newValuesObj
}])
},
enqueueMessages(messages) {
// 浼拌杩涢槦鍒楁椂闂撮棿闅?
if (!this.lastEnqueueTime) {
this.lastEnqueueTime = new Date()
} else {
let curTime = new Date()
let interval = curTime - this.lastEnqueueTime
// 鐪熷疄鐨勮繘闃熷垪鏃堕棿闂撮殧妯″紡澶ф鏄繖鏍凤細2500, 300, 300, 300, 2500, 300, ...
// B绔欐秷鎭湁缂撳啿锛屼細涓€娆″彂澶氭潯娑堟伅銆傝繖閲屾妸娉㈠嘲瑙嗕负鍙戦€佷簡涓€娆湡瀹炵殑WS娑堟伅锛屾墍浠ヨ杩囨护鎺夐棿闅斿お灏忕殑
if (interval > 1000 || this.enqueueIntervals.length < 5) {
this.enqueueIntervals.push(interval)
if (this.enqueueIntervals.length > 5) {
this.enqueueIntervals.splice(0, this.enqueueIntervals.length - 5)
}
// 杩欒竟浼拌寰楀敖閲忓ぇ锛屽彧瑕佷笉澶棭鎶婃秷鎭紦鍐插彂瀹屽氨鏄钩婊戠殑銆傛湁MESSAGE_MAX_INTERVAL淇濆簳锛屼笉浼氳娑堟伅寤惰繜澶ぇ
// 鍏跺疄鍙互鐢ㄥ崟璋冮槦鍒楁眰鏈€澶у€硷紝鍋锋噿涓嶅啓浜?
this.estimatedEnqueueInterval = Math.max(...this.enqueueIntervals)
}
// 涓婃鍏ラ槦鏃堕棿杩樻槸瑕佽缃紝鍚﹀垯浼氬お鏃╂妸娑堟伅缂撳啿鍙戝畬锛岀劧鍚庤緝闀挎椂闂存病鏈夋柊娑堟伅
this.lastEnqueueTime = curTime
}
// 鎶妋essages鍒嗘垚messageGroup锛屾瘡涓粍閲屾渶澶氭湁1涓渶瑕佸钩婊戠殑娑堟伅
let messageGroup = []
for (let message of messages) {
messageGroup.push(message)
if (this.isAddMessage(message)) {
this.smoothedMessageQueue.push(messageGroup)
messageGroup = []
}
}
// 杩樺墿涓嬩笉闇€瑕佸钩婊戠殑娑堟伅
if (messageGroup.length > 0) {
if (this.smoothedMessageQueue.length > 0) {
// 鍜屼笂涓€缁勫悎骞?
let lastMessageGroup = this.smoothedMessageQueue[this.smoothedMessageQueue.length - 1]
for (let message of messageGroup) {
lastMessageGroup.push(message)
}
} else {
// 鑷繁涓€涓粍
this.smoothedMessageQueue.push(messageGroup)
}
}
if (!this.emitSmoothedMessageTimerId) {
this.emitSmoothedMessageTimerId = window.setTimeout(this.emitSmoothedMessages)
}
},
isAddMessage({ type }) {
return ADD_MESSAGE_TYPES.indexOf(type) !== -1
},
emitSmoothedMessages() {
this.emitSmoothedMessageTimerId = null
if (this.smoothedMessageQueue.length <= 0) {
return
}
// 浼拌鐨勪笅娆¤繘闃熷垪鍓╀綑鏃堕棿
let estimatedNextEnqueueRemainTime = 10 * 1000
if (this.estimatedEnqueueInterval) {
estimatedNextEnqueueRemainTime = Math.max(this.lastEnqueueTime - new Date() + this.estimatedEnqueueInterval, 1)
}
// 璁$畻鍙戦€佺殑娑堟伅鏁帮紝淇濊瘉鍦ㄤ笅娆¤繘闃熷垪涔嬪墠鍙戝畬
// 涓嬫杩涢槦鍒椾箣鍓嶅簲璇ュ彂澶氬皯鏉℃秷鎭?
let shouldEmitGroupNum = Math.max(this.smoothedMessageQueue.length, 0)
// 涓嬫杩涢槦鍒椾箣鍓嶆渶澶氳兘鍙戝灏戞
let maxCanEmitCount = estimatedNextEnqueueRemainTime / MESSAGE_MIN_INTERVAL
// 杩欐鍙戝灏戞潯娑堟伅
let groupNumToEmit
if (shouldEmitGroupNum < maxCanEmitCount) {
// 闃熷垪涓秷鎭暟寰堝皯锛屾瘡娆″彂1鏉篃鑳藉彂瀹?
groupNumToEmit = 1
} else {
// 姣忔鍙?鏉′互涓婏紝淇濊瘉鎸夋渶蹇€熷害鑳藉彂瀹?
groupNumToEmit = Math.ceil(shouldEmitGroupNum / maxCanEmitCount)
}
// 鍙戞秷鎭?
let messageGroups = this.smoothedMessageQueue.splice(0, groupNumToEmit)
let mergedGroup = []
for (let messageGroup of messageGroups) {
for (let message of messageGroup) {
mergedGroup.push(message)
}
}
this.handleMessageGroup(mergedGroup)
if (this.smoothedMessageQueue.length <= 0) {
return
}
// 娑堟伅娌″彂瀹岋紝璁$畻涓嬫鍙戞秷鎭椂闂?
let sleepTime
if (groupNumToEmit === 1) {
// 闃熷垪涓秷鎭暟寰堝皯锛岄殢渚垮畾涓猍MESSAGE_MIN_INTERVAL, MESSAGE_MAX_INTERVAL]鐨勬椂闂?
sleepTime = estimatedNextEnqueueRemainTime / this.smoothedMessageQueue.length
sleepTime *= 0.5 + Math.random()
if (sleepTime > MESSAGE_MAX_INTERVAL) {
sleepTime = MESSAGE_MAX_INTERVAL
} else if (sleepTime < MESSAGE_MIN_INTERVAL) {
sleepTime = MESSAGE_MIN_INTERVAL
}
} else {
// 鎸夋渶蹇€熷害鍙?
sleepTime = MESSAGE_MIN_INTERVAL
}
this.emitSmoothedMessageTimerId = window.setTimeout(this.emitSmoothedMessages, sleepTime)
},
handleMessageGroup(messageGroup) {
if (messageGroup.length <= 0) {
return
}
for (let message of messageGroup) {
switch (message.type) {
case constants.MESSAGE_TYPE_TEXT:
case constants.MESSAGE_TYPE_GIFT:
case constants.MESSAGE_TYPE_MEMBER:
case constants.MESSAGE_TYPE_SUPER_CHAT:
// 杩欓噷澶勭悊鐨勭被鍨嬭鍜?ADD_MESSAGE_TYPES 涓€鑷?
this.handleAddMessage(message)
break
case constants.MESSAGE_TYPE_DEL:
this.handleDelMessage(message)
break
case constants.MESSAGE_TYPE_UPDATE:
this.handleUpdateMessage(message)
break
}
}
this.maybeResizeScrollContainer()
this.flushMessagesBuffer()
this.$nextTick(this.maybeScrollToBottom)
},
handleAddMessage(message) {
// 娣诲姞涓€涓湰鍦版椂闂寸粰Ticker鐢紝闃叉鏈湴鏃堕棿鍜屾湇鍔″櫒鏃堕棿鐩稿樊寰堝ぇ鐨勬儏鍐?
message.addTime = new Date()
if (message.type !== constants.MESSAGE_TYPE_TEXT) {
this.paidMessages.unshift(_.cloneDeep(message))
const MAX_PAID_MESSAGE_NUM = 100
if (this.paidMessages.length > MAX_PAID_MESSAGE_NUM) {
this.paidMessages.splice(MAX_PAID_MESSAGE_NUM, this.paidMessages.length - MAX_PAID_MESSAGE_NUM)
}
}
// 涓嶇煡閬揷loneDeep鎷疯礉Vue鐨勫搷搴斿紡瀵硅薄浼氫笉浼氭湁闂锛屼繚闄╄捣瑙佹妸杩欏彞鏀惧湪鍚庨潰
this.messagesBuffer.push(message)
},
handleDelMessage({ id }) {
let arrs = [this.messages, this.paidMessages, this.messagesBuffer]
let needResetSmoothScroll = false
for (let arr of arrs) {
for (let i = 0; i < arr.length; i++) {
if (arr[i].id !== id) {
continue
}
arr.splice(i, 1)
if (arr === this.messages) {
needResetSmoothScroll = true
}
break
}
}
if (needResetSmoothScroll) {
this.resetSmoothScroll()
}
},
handleUpdateMessage({ id, newValuesObj }) {
let arrs = [this.messages, this.paidMessages, this.messagesBuffer]
let needResetSmoothScroll = false
for (let arr of arrs) {
for (let message of arr) {
if (message.id !== id) {
continue
}
this.doUpdateMessage(message, newValuesObj)
if (arr === this.messages) {
needResetSmoothScroll = true
}
break
}
}
if (needResetSmoothScroll) {
this.resetSmoothScroll()
}
},
doUpdateMessage(message, newValuesObj) {
// +=
let addValuesObj = newValuesObj.$add
if (addValuesObj !== undefined) {
for (let name in addValuesObj) {
message[name] += addValuesObj[name]
}
}
// =
for (let name in newValuesObj) {
if (!name.startsWith('$')) {
message[name] = newValuesObj[name]
}
}
},
async flushMessagesBuffer() {
if (this.messagesBuffer.length <= 0) {
return
}
if (!this.canScrollToBottomOrTimedOut()) {
if (this.messagesBuffer.length > this.maxNumber) {
// 鏈樉绀烘秷鎭暟 > 鏈€澶у彲鏄剧ず鏁帮紝涓㈠純
this.messagesBuffer.splice(0, this.messagesBuffer.length - this.maxNumber)
}
return
}
let removeNum = Math.max(this.messages.length + this.messagesBuffer.length - this.maxNumber, 0)
if (removeNum > 0) {
this.messages.splice(0, removeNum)
// 闃叉鍚屾椂娣诲姞鍜屽垹闄ら」鐩椂鎵€鏈夌殑椤圭洰閲嶆柊娓叉煋 https://github.com/vuejs/vue/issues/6857
await this.$nextTick()
}
this.preinsertHeight = this.$refs.items.clientHeight
for (let message of this.messagesBuffer) {
this.messages.push(message)
}
this.messagesBuffer = []
// 绛塱tems楂樺害鍙樺寲
await this.$nextTick()
this.showNewMessages()
},
showNewMessages() {
let hasScrollBar = this.$refs.items.clientHeight > this.$refs.scroller.clientHeight
this.$refs.itemOffset.style.height = `${this.$refs.items.clientHeight}px`
if (!this.canScrollToBottomOrTimedOut() || !hasScrollBar) {
return
}
// 璁$畻鍓╀綑鍍忕礌
this.scrollPixelsRemaining += this.$refs.items.clientHeight - this.preinsertHeight
this.scrollToBottom()
// 璁$畻鏄惁骞虫粦婊氬姩銆佸墿浣欐椂闂?
if (!this.lastSmoothChatMessageAddMs) {
this.lastSmoothChatMessageAddMs = performance.now()
}
let interval = performance.now() - this.lastSmoothChatMessageAddMs
this.chatRateMs = (0.9 * this.chatRateMs) + (0.1 * interval)
if (this.isSmoothed) {
if (this.chatRateMs < 400) {
this.isSmoothed = false
}
} else {
if (this.chatRateMs > 450) {
this.isSmoothed = true
}
}
this.scrollTimeRemainingMs += this.isSmoothed ? CHAT_SMOOTH_ANIMATION_TIME_MS : 0
if (!this.smoothScrollRafHandle) {
this.smoothScrollRafHandle = window.requestAnimationFrame(this.smoothScroll)
}
this.lastSmoothChatMessageAddMs = performance.now()
},
smoothScroll(time) {
if (!this.lastSmoothScrollUpdate) {
// 绗竴甯?
this.lastSmoothScrollUpdate = time
this.smoothScrollRafHandle = window.requestAnimationFrame(this.smoothScroll)
return
}
let interval = time - this.lastSmoothScrollUpdate
if (
this.scrollPixelsRemaining <= 0 || this.scrollPixelsRemaining >= 400 // 宸茬粡婊氬姩鍒板簳閮ㄦ垨鑰呯搴曢儴澶繙鍒欑粨鏉?
|| interval >= 1000 // 绂讳笂涓€甯ф椂闂村お涔咃紝鍙兘鐢ㄦ埛鍒囨崲鍒板叾浠栫綉椤?
|| this.scrollTimeRemainingMs <= 0 // 鏃堕棿宸茬粨鏉?
) {
this.resetSmoothScroll()
return
}
let pixelsToScroll = interval / this.scrollTimeRemainingMs * this.scrollPixelsRemaining
this.scrollPixelsRemaining -= pixelsToScroll
if (this.scrollPixelsRemaining < 0) {
this.scrollPixelsRemaining = 0
}
this.scrollTimeRemainingMs -= interval
if (this.scrollTimeRemainingMs < 0) {
this.scrollTimeRemainingMs = 0
}
this.lastSmoothScrollUpdate = time
this.smoothScrollRafHandle = window.requestAnimationFrame(this.smoothScroll)
},
resetSmoothScroll() {
this.scrollTimeRemainingMs = this.scrollPixelsRemaining = 0
this.lastSmoothScrollUpdate = null
if (this.smoothScrollRafHandle) {
window.cancelAnimationFrame(this.smoothScrollRafHandle)
this.smoothScrollRafHandle = null
}
},
maybeResizeScrollContainer() {
this.$refs.itemOffset.style.height = `${this.$refs.items.clientHeight}px`
this.$refs.itemOffset.style.minHeight = `${this.$refs.scroller.clientHeight}px`
this.maybeScrollToBottom()
},
maybeScrollToBottom() {
if (this.canScrollToBottomOrTimedOut()) {
this.scrollToBottom()
}
},
scrollToBottom() {
this.$refs.scroller.scrollTop = Math.pow(2, 24)
this.atBottom = true
},
onScroll() {
this.refreshCantScrollStartTime()
let scroller = this.$refs.scroller
this.atBottom = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight < SCROLLED_TO_BOTTOM_EPSILON
this.flushMessagesBuffer()
},
canScrollToBottomOrTimedOut() {
if (this.canScrollToBottom) {
return true
}
// 闃叉鍦BS涓崱浣忥紝瓒呰繃涓€瀹氭椂闂翠篃鍙互鑷姩婊氬姩
return new Date() - this.cantScrollStartTime >= 5 * 1000
},
refreshCantScrollStartTime() {
// 鏈夐紶鏍囦簨浠舵椂鍒锋柊锛岄槻姝㈢敤鎴风湅寮瑰箷鏃惰嚜鍔ㄦ粴鍔?
if (this.cantScrollStartTime) {
this.cantScrollStartTime = new Date()
}
}
}
})
</script>
<style src="@/assets/css/youtube/yt-html.css"></style>
<style src="@/assets/css/youtube/yt-live-chat-renderer.css"></style>
<style src="@/assets/css/youtube/yt-live-chat-item-list-renderer.css"></style>