mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-08-27 11:10:12 +08:00
feat: add force scroll option to intelligent message scrolling in ShortcutBar and MessageView
This commit is contained in:
@@ -11,6 +11,10 @@ type MessageViewExpose = {
|
|||||||
refreshLatestMessages?: () => Promise<void> | void
|
refreshLatestMessages?: () => Promise<void> | void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MessageScrollPayload = {
|
||||||
|
force?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
// 国际化
|
// 国际化
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
@@ -165,14 +169,19 @@ async function openMessageDialog() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 智能滚动到底部(只有用户在底部附近时才滚动)
|
// 智能滚动到底部:首次打开时允许强制滚动,后续实时消息尊重用户当前位置。
|
||||||
function scrollMessageToEnd() {
|
function scrollMessageToEnd(payload?: MessageScrollPayload) {
|
||||||
// 使用更长的延迟确保DOM已更新
|
// 使用更长的延迟确保DOM已更新
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
try {
|
try {
|
||||||
// 查找消息弹窗的滚动容器
|
// 查找消息弹窗的滚动容器
|
||||||
const cardText = document.querySelector('.v-dialog .v-card-text')
|
const cardText = document.querySelector('.v-dialog .v-card-text')
|
||||||
if (cardText) {
|
if (cardText) {
|
||||||
|
if (payload?.force) {
|
||||||
|
cardText.scrollTop = cardText.scrollHeight
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const { scrollTop, scrollHeight, clientHeight } = cardText
|
const { scrollTop, scrollHeight, clientHeight } = cardText
|
||||||
// 计算距离底部的距离
|
// 计算距离底部的距离
|
||||||
const distanceFromBottom = scrollHeight - scrollTop - clientHeight
|
const distanceFromBottom = scrollHeight - scrollTop - clientHeight
|
||||||
|
|||||||
@@ -9,8 +9,14 @@ import { useBackgroundOptimization } from '@/composables/useBackgroundOptimizati
|
|||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const { useSSE } = useBackgroundOptimization()
|
const { useSSE } = useBackgroundOptimization()
|
||||||
|
|
||||||
|
type ScrollPayload = {
|
||||||
|
force?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
// 定义事件
|
// 定义事件
|
||||||
const emit = defineEmits(['scroll'])
|
const emit = defineEmits<{
|
||||||
|
(e: 'scroll', payload?: ScrollPayload): void
|
||||||
|
}>()
|
||||||
|
|
||||||
// 消息列表
|
// 消息列表
|
||||||
const messages = ref<Message[]>([])
|
const messages = ref<Message[]>([])
|
||||||
@@ -66,6 +72,13 @@ function updateLastTime(message: Message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 请求父组件滚动,首屏历史消息需要强制到底,实时消息继续使用智能滚动。
|
||||||
|
function requestScrollToEnd(force = false) {
|
||||||
|
nextTick(() => {
|
||||||
|
emit('scroll', { force })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 合并消息到当前列表
|
// 合并消息到当前列表
|
||||||
function mergeMessages(items: Message[]) {
|
function mergeMessages(items: Message[]) {
|
||||||
let hasNewMessage = false
|
let hasNewMessage = false
|
||||||
@@ -95,9 +108,7 @@ function handleSSEMessage(event: MessageEvent) {
|
|||||||
if (message) {
|
if (message) {
|
||||||
const object = JSON.parse(message)
|
const object = JSON.parse(message)
|
||||||
if (mergeMessages([object])) {
|
if (mergeMessages([object])) {
|
||||||
nextTick(() => {
|
requestScrollToEnd() // 新消息到达时触发智能滚动
|
||||||
emit('scroll') // 新消息到达时触发智能滚动
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -137,9 +148,7 @@ async function loadMessages({ done }: { done: any }) {
|
|||||||
|
|
||||||
// 首次加载时滚动到底部
|
// 首次加载时滚动到底部
|
||||||
if (page.value === 1 && hasNewMessage) {
|
if (page.value === 1 && hasNewMessage) {
|
||||||
nextTick(() => {
|
requestScrollToEnd(true)
|
||||||
emit('scroll')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
// 页码+1
|
// 页码+1
|
||||||
page.value++
|
page.value++
|
||||||
@@ -168,9 +177,7 @@ async function refreshLatestMessages() {
|
|||||||
})) as Message[]
|
})) as Message[]
|
||||||
|
|
||||||
if (mergeMessages(latestMessages)) {
|
if (mergeMessages(latestMessages)) {
|
||||||
nextTick(() => {
|
requestScrollToEnd()
|
||||||
emit('scroll')
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('刷新最新消息失败:', error)
|
console.error('刷新最新消息失败:', error)
|
||||||
@@ -206,7 +213,7 @@ function compareTime(time1: string, time2: string) {
|
|||||||
|
|
||||||
// 图片加载完成时触发智能滚动
|
// 图片加载完成时触发智能滚动
|
||||||
function handleImageLoad() {
|
function handleImageLoad() {
|
||||||
emit('scroll')
|
requestScrollToEnd()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 暂停SSE连接
|
// 暂停SSE连接
|
||||||
@@ -236,9 +243,7 @@ defineExpose({
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 组件挂载后触发一次滚动事件
|
// 组件挂载后触发一次滚动事件
|
||||||
nextTick(() => {
|
requestScrollToEnd()
|
||||||
emit('scroll')
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user