import { ref, onMounted, onBeforeUnmount, watch, nextTick } from '@common/utils/vueTools' import { scrollXRTo } from '@common/utils/renderer' import { lyric } from '@lyric/store/lyric' import { isPlay, setting } from '@lyric/store/state' import { setWindowBounds } from '@lyric/utils/ipc' const getOffsetTop = (contentWidth, lineWidth) => { switch (setting['desktopLyric.scrollAlign']) { case 'top': return contentWidth - lineWidth default: return contentWidth * 0.5 - lineWidth / 2 } } export default () => { const dom_lyric = ref(null) const dom_lyric_text = ref(null) const isMsDown = ref(false) let isStopScroll = false const winEvent = { isMsDown: false, msDownX: 0, msDownY: 0, } let msDownX = 0 let msDownScrollX = 0 let timeout = null let cancelScrollFn let dom_lines let isSetedLines = false const handleScrollLrc = (duration = 300) => { if (!dom_lines?.length || !dom_lyric.value) return if (cancelScrollFn) { cancelScrollFn() cancelScrollFn = null } if (isStopScroll) return let dom_p = dom_lines[lyric.line] cancelScrollFn = scrollXRTo(dom_lyric.value, dom_p ? (dom_p.offsetLeft - getOffsetTop(dom_lyric.value.clientWidth, dom_p.clientWidth)) : 0, duration) } const clearLyricScrollTimeout = () => { if (!timeout) return clearTimeout(timeout) timeout = null } const startLyricScrollTimeout = () => { clearLyricScrollTimeout() timeout = setTimeout(() => { timeout = null isStopScroll = false if (!isPlay.value) return handleScrollLrc() }, 3000) } const handleLyricDown = (target, x, y) => { if (target.classList.contains('font-lrc') || target.parentNode.classList.contains('font-lrc') || target.classList.contains('extended') || target.parentNode.classList.contains('extended') ) { if (delayScrollTimeout) { clearTimeout(delayScrollTimeout) delayScrollTimeout = null } isMsDown.value = true msDownX = x msDownScrollX = dom_lyric.value.scrollLeft } else { winEvent.isMsDown = true winEvent.msDownX = x winEvent.msDownY = y } } const handleLyricMouseDown = event => { handleLyricDown(event.target, event.clientX, event.clientY) } const handleLyricTouchStart = event => { if (event.changedTouches.length) { const touch = event.changedTouches[0] handleLyricDown(event.target, touch.clientX, touch.clientY) } } const handleMouseMsUp = () => { isMsDown.value = false winEvent.isMsDown = false } const handleMove = (x, y) => { if (isMsDown.value) { isStopScroll ||= true if (cancelScrollFn) { cancelScrollFn() cancelScrollFn = null } dom_lyric.value.scrollLeft = msDownScrollX + msDownX - x startLyricScrollTimeout() } else if (winEvent.isMsDown) { setWindowBounds({ x: x - winEvent.msDownX, y: y - winEvent.msDownY, w: window.innerWidth, h: window.innerHeight, }) } } const handleMouseMsMove = event => { handleMove(event.clientX, event.clientY) } const handleTouchMove = (e) => { if (e.changedTouches.length) { const touch = e.changedTouches[0] handleMove(touch.clientX, touch.clientY) } } const handleWheel = (event) => { console.log(event.deltaY) if (cancelScrollFn) { cancelScrollFn() cancelScrollFn = null } dom_lyric.value.scrollLeft = dom_lyric.value.scrollLeft - event.deltaY startLyricScrollTimeout() } const setLyric = (lines) => { const dom_line_content = document.createDocumentFragment() for (const line of lines) { dom_line_content.appendChild(line.dom_line) } dom_lyric_text.value.textContent = '' dom_lyric_text.value.appendChild(dom_line_content) nextTick(() => { dom_lines = dom_lyric.value.querySelectorAll('.line-content') handleScrollLrc() }) } const initLrc = (lines, oLines) => { isSetedLines = true if (oLines) { if (lines.length) { setLyric(lines) } else { if (cancelScrollFn) { cancelScrollFn() cancelScrollFn = null } cancelScrollFn = scrollXRTo(dom_lyric.value, 0, 300, () => { if (lyric.lines !== lines) return setLyric(lines) }, 50) } } else { setLyric(lines) } } let delayScrollTimeout const scrollLine = (line, oldLine) => { if (line < 0) return if (line == 0 && isSetedLines) return isSetedLines = false isSetedLines &&= false if (oldLine == null || line - oldLine != 1) return handleScrollLrc() if (setting['desktopLyric.isDelayScroll']) { delayScrollTimeout = setTimeout(() => { delayScrollTimeout = null handleScrollLrc(600) }, 600) } else { handleScrollLrc() } } watch(() => lyric.lines, initLrc) watch(() => lyric.line, scrollLine) onMounted(() => { document.addEventListener('mousemove', handleMouseMsMove) document.addEventListener('mouseup', handleMouseMsUp) document.addEventListener('touchmove', handleTouchMove) document.addEventListener('touchend', handleMouseMsUp) initLrc(lyric.lines, null) nextTick(() => { scrollLine(lyric.line) }) }) onBeforeUnmount(() => { document.removeEventListener('mousemove', handleMouseMsMove) document.removeEventListener('mouseup', handleMouseMsUp) document.removeEventListener('touchmove', handleTouchMove) document.removeEventListener('touchend', handleMouseMsUp) }) return { dom_lyric, dom_lyric_text, isMsDown, handleLyricMouseDown, handleLyricTouchStart, handleWheel, } }