hookehuyr

fix(bookDetail): 优化书籍详情页简介展开折叠检测逻辑

改用ResizeObserver替代原有的setTimeout与hasEllipsis检测方式,实现更精准的文本溢出判断;添加书籍简介内容变化监听,同步更新展开状态;在组件失活与卸载时正确清理观察者与动画帧计时器。
......@@ -16,7 +16,7 @@
</div>
<div class="book-intro">
<p class="book-post">{{ bookInfo.name }}</p>
<div id="book-intro" :class="{ 'van-multi-ellipsis--l3': isToggle }" v-html="bookInfo.note"></div>
<div id="book-intro" ref="bookIntroRef" :class="{ 'van-multi-ellipsis--l3': isToggle }" v-html="bookInfo.note"></div>
<template v-if="hasToggle">
<div v-if="isToggle" class="book-toggle-icon" @click="isToggle = false">
展开&nbsp;
......@@ -121,9 +121,9 @@
</template>
<script setup>
import { ref, onActivated, onMounted } from 'vue'
import { ref, watch, nextTick, onActivated, onMounted, onDeactivated, onBeforeUnmount } from 'vue'
import { useRoute, useRouter, onBeforeRouteLeave } from 'vue-router'
import { _, storeToRefs, mainStore, showSuccessToast, hasEllipsis } from '@/utils/generatePackage'
import { _, storeToRefs, mainStore, showSuccessToast } from '@/utils/generatePackage'
import { MyButton, VideoCard, NoticeOverlayModule, DonateFlower, ShortcutFixed } from '@/utils/generateModules'
import { icon_video, icon_up, icon_down, icon_subscribed, icon_unsubscribe, no_image } from '@/utils/generateIcons'
import { JSJ_FORM_MANDARIN, JSJ_FORM_LOCALISM } from '@/constant'
......@@ -157,13 +157,76 @@ const customStyle = ref({
})
const donateInfo = ref({})
const bookIntroRef = ref(null)
const hasToggle = ref(false); // 判断是否有展开文字,默认没有
const isToggle = ref(true); // 判断展开状态,默认展开
let introResizeObserver = null
let introMeasureTimer = null
const getIntroToggleStatus = () => {
const el = bookIntroRef.value;
if (!el || !el.clientWidth) {
return false;
}
const clone = el.cloneNode(true);
clone.removeAttribute('id');
clone.style.position = 'fixed';
clone.style.left = '-99999px';
clone.style.top = '-99999px';
clone.style.zIndex = '-1';
clone.style.visibility = 'hidden';
clone.style.pointerEvents = 'none';
clone.style.height = 'auto';
clone.style.maxHeight = 'none';
clone.style.width = `${el.clientWidth}px`;
clone.classList.add('van-multi-ellipsis--l3');
document.body.appendChild(clone);
const flag = clone.scrollHeight > clone.clientHeight;
document.body.removeChild(clone);
return flag;
}
const updateHasToggle = async () => {
await nextTick();
if (introMeasureTimer) {
cancelAnimationFrame(introMeasureTimer);
}
introMeasureTimer = requestAnimationFrame(() => {
hasToggle.value = getIntroToggleStatus();
});
}
const bindIntroObserver = () => {
if (!window.ResizeObserver || introResizeObserver || !bookIntroRef.value) return;
introResizeObserver = new ResizeObserver(() => {
updateHasToggle();
});
introResizeObserver.observe(bookIntroRef.value);
}
const clearIntroObserver = () => {
if (introResizeObserver) {
introResizeObserver.disconnect();
introResizeObserver = null;
}
if (introMeasureTimer) {
cancelAnimationFrame(introMeasureTimer);
introMeasureTimer = null;
}
}
onMounted(async () => {
const { data } = await prepareDonateAPI();
donateInfo.value = data;
setTimeout(() => {
// 判断是否显示简介的展开图标
hasToggle.value = hasEllipsis(`book-intro`);
}, 500);
bindIntroObserver();
updateHasToggle();
// TAG: 监听滚动到底部
// 快捷访问组件高度动态调整
// window.onscroll = function () {
......@@ -202,9 +265,10 @@ window.onscroll = function () {
}
}
// 判断是否显示简介的展开图标
const hasToggle = ref(false); // 判断是否有展开文字,默认没有
const isToggle = ref(true); // 判断展开状态,默认展开
watch(() => bookInfo.value?.note, () => {
isToggle.value = true;
updateHasToggle();
});
/**
* 书籍订阅
......@@ -327,6 +391,16 @@ onActivated(() => { // keepAlive 重置后执行回调
// 更新是否实名认证和儿童信息
const data = useDefaultPerf($route.query.id);
userInfo = data.userInfo;
bindIntroObserver();
updateHasToggle();
});
onDeactivated(() => {
clearIntroObserver();
});
onBeforeUnmount(() => {
clearIntroObserver();
});
onBeforeRouteLeave(() => {
......