223 lines
6.2 KiB
JavaScript
223 lines
6.2 KiB
JavaScript
import { ref, onMounted, onBeforeUnmount, watch, nextTick } from '@common/utils/vueTools'
|
|
import { scrollTo } from '@common/utils/renderer'
|
|
import { lyric } from '@lyric/store/lyric'
|
|
import { isPlay, setting } from '@lyric/store/state'
|
|
import { invalidateShadow, setWindowBounds } from '@lyric/utils/ipc'
|
|
|
|
const getOffsetTop = (contentHeight, lineHeight) => {
|
|
switch (setting['desktopLyric.scrollAlign']) {
|
|
case 'top': return 0
|
|
default: return contentHeight * 0.5 - lineHeight / 2
|
|
}
|
|
}
|
|
|
|
export default (isComputeHeight) => {
|
|
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 msDownY = 0
|
|
let msDownScrollY = 0
|
|
let timeout = null
|
|
let cancelScrollFn
|
|
let dom_lines
|
|
let line_heights
|
|
let isSetedLines = false
|
|
let prevActiveLine = 0
|
|
|
|
|
|
const handleScrollLrc = (duration = 300) => {
|
|
if (!dom_lines?.length || !dom_lyric.value) return
|
|
if (isStopScroll) return
|
|
let dom_p = dom_lines[lyric.line]
|
|
|
|
if (dom_p) {
|
|
let offset = 0
|
|
if (isComputeHeight.value) {
|
|
let prevLineHeight = line_heights[prevActiveLine] ?? 0
|
|
offset = prevActiveLine < lyric.line ? ((dom_lines[prevActiveLine]?.clientHeight ?? 0) - prevLineHeight) : 0
|
|
// console.log(prevActiveLine, dom_lines[prevActiveLine]?.clientHeight ?? 0, prevLineHeight, offset)
|
|
}
|
|
cancelScrollFn = scrollTo(dom_lyric.value, dom_p ? (dom_p.offsetTop - offset - getOffsetTop(dom_lyric.value.clientHeight, dom_p.clientHeight)) : 0, duration, () => {
|
|
invalidateShadow()
|
|
})
|
|
} else {
|
|
cancelScrollFn = scrollTo(dom_lyric.value, 0, duration, () => {
|
|
invalidateShadow()
|
|
})
|
|
}
|
|
}
|
|
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
|
|
msDownY = y
|
|
msDownScrollY = dom_lyric.value.scrollTop
|
|
} 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.scrollTop = msDownScrollY + msDownY - y
|
|
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.scrollTop = dom_lyric.value.scrollTop + 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')
|
|
line_heights = Array.from(dom_lines).map(l => l.clientHeight)
|
|
handleScrollLrc()
|
|
})
|
|
}
|
|
|
|
const initLrc = (lines, oLines) => {
|
|
prevActiveLine = 0
|
|
isSetedLines = true
|
|
if (oLines) {
|
|
if (lines.length) {
|
|
setLyric(lines)
|
|
} else {
|
|
cancelScrollFn = scrollTo(dom_lyric.value, 0, 300, () => {
|
|
invalidateShadow()
|
|
if (lyric.lines !== lines) return
|
|
setLyric(lines)
|
|
}, 50)
|
|
}
|
|
} else {
|
|
setLyric(lines)
|
|
}
|
|
}
|
|
|
|
let delayScrollTimeout
|
|
const scrollLine = (line, oldLine) => {
|
|
setImmediate(() => {
|
|
prevActiveLine = line
|
|
})
|
|
if (line < 0 || !lyric.lines.length) 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)
|
|
})
|
|
|
|
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,
|
|
}
|
|
}
|