hookehuyr

fix(StudyCoursePage): 修复滚动容器引用和滚动事件处理问题

修复滚动容器引用未正确初始化的bug
将全局滚动事件改为容器内滚动事件
优化标签切换时的滚动行为
......@@ -48,7 +48,7 @@
</div>
<!-- 滚动区域:详情、目录和互动内容 -->
<div class="overflow-y-auto flex-1"
<div ref="scroll_container_ref" class="overflow-y-auto flex-1"
:style="{ paddingTop: topWrapperHeight, height: 'calc(100vh - ' + topWrapperHeight + ')' }">
<!-- 详情区域 -->
<div id="detail" class="py-4 px-4">
......@@ -195,6 +195,9 @@ const currentTabIndex = computed(() => {
const tabs_container_ref = ref(null);
const tabs_container_width = ref(0);
const tabs_resize_observer = ref(null);
const scroll_container_ref = ref(null);
const scroll_container_el = ref(null);
const is_tab_scrolling = ref(false);
/**
* 初始化并监听标签容器宽度
......@@ -325,8 +328,12 @@ onMounted(async () => {
/**
* 初始化时计算topWrapperHeight
*/
// 添加滚动监听
window.addEventListener('scroll', handleScroll);
nextTick(() => {
if (scroll_container_ref.value) {
scroll_container_el.value = scroll_container_ref.value;
scroll_container_el.value.addEventListener('scroll', handleScroll, { passive: true });
}
});
// 添加窗口大小变化监听
window.addEventListener('resize', updateTopWrapperHeight);
// 确保在组件挂载后计算高度
......@@ -337,7 +344,10 @@ onMounted(async () => {
// 在组件卸载时移除监听器
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll);
if (scroll_container_el.value) {
scroll_container_el.value.removeEventListener('scroll', handleScroll);
scroll_container_el.value = null;
}
window.removeEventListener('resize', updateTopWrapperHeight);
// 组件卸载时取消监听
if (resizeObserver.value) {
......@@ -354,19 +364,14 @@ onUnmounted(() => {
// 处理滚动事件
// 在script setup中添加
const isTabFixed = ref(false);
const tabOriginalTop = ref(0);
onMounted(async () => {
setTimeout(() => {
nextTick(() => {
// 记录标签页原始位置
const tabElement = document.querySelector('.py-3.bg-white');
if (tabElement) {
tabOriginalTop.value = tabElement.getBoundingClientRect().top + window.scrollY;
}
})
}, 500);
});
const get_container_relative_top = (el) => {
const container = scroll_container_ref.value;
if (!container || !el) return 0;
const container_rect = container.getBoundingClientRect();
const el_rect = el.getBoundingClientRect();
return el_rect.top - container_rect.top + container.scrollTop;
};
// 防抖函数
const debounce = (fn, delay) => {
......@@ -385,27 +390,27 @@ const debounce = (fn, delay) => {
* 注释:当互动区域不存在时,仅在详情与目录之间联动
*/
const handleScroll = debounce(() => {
if (is_tab_scrolling.value) return;
const detailElement = document.getElementById('detail');
const catalogElement = document.getElementById('catalog');
const interactionElement = document.getElementById('interaction');
const tabElement = document.querySelector('.py-3.bg-white');
if (!detailElement || !catalogElement || !tabElement) return;
const container = scroll_container_ref.value;
if (!detailElement || !catalogElement || !container) return;
const currentScrollY = window.scrollY;
isTabFixed.value = currentScrollY >= tabOriginalTop.value;
isTabFixed.value = false;
const scrollTop = window.scrollY;
const tabHeight = tabElement.offsetHeight;
const buffer = 50; // 缓冲区域
const scrollTop = container.scrollTop;
const buffer = 20; // 缓冲区域
// 计算各区域顶部位置(互动不存在则设为无穷大)
const detailTop = detailElement.offsetTop - tabHeight - buffer;
const catalogTop = catalogElement.offsetTop - tabHeight - buffer;
const interactionTop = interactionElement ? (interactionElement.offsetTop - tabHeight - buffer) : Infinity;
const detailTop = get_container_relative_top(detailElement) - buffer;
const catalogTop = get_container_relative_top(catalogElement) - buffer;
const interactionTop = interactionElement ? (get_container_relative_top(interactionElement) - buffer) : Infinity;
// 页面高度与底部判断
const scrollHeight = document.documentElement.scrollHeight;
const clientHeight = document.documentElement.clientHeight;
const scrollHeight = container.scrollHeight;
const clientHeight = container.clientHeight;
const isAtBottom = scrollTop + clientHeight >= scrollHeight - buffer;
// 联动判断
......@@ -434,15 +439,17 @@ const getTransitionTiming = (current, previous) => {
const handleTabChange = (name) => {
previousTab.value = activeTab.value;
activeTab.value = name; // 立即更新activeTab的值
let offset = 100; // 调整偏移量, 配合目录的高度
is_tab_scrolling.value = true;
nextTick(() => {
const element = document.getElementById(name);
if (element) {
const topOffset = element.offsetTop - offset - parseInt(topWrapperHeight.value);
window.scrollTo({
top: topOffset,
behavior: 'smooth'
});
if (element && scroll_container_ref.value) {
const topOffset = Math.max(0, get_container_relative_top(element) - 10);
scroll_container_ref.value.scrollTo({ top: topOffset, behavior: 'smooth' });
setTimeout(() => {
is_tab_scrolling.value = false;
}, 500);
} else {
is_tab_scrolling.value = false;
}
});
};
......