hookehuyr

refactor(Home): 优化步骤箭头显示逻辑,改为内嵌式显示

移除全局跟随箭头逻辑,改为在步骤内直接显示箭头
简化窗口尺寸变化处理,仅更新装饰线位置
调整底部留白以适应新箭头布局
...@@ -64,11 +64,12 @@ ...@@ -64,11 +64,12 @@
64 <div class="step-content"> 64 <div class="step-content">
65 <span class="step-text">{{ step.name }}</span> 65 <span class="step-text">{{ step.name }}</span>
66 </div> 66 </div>
67 +
68 + <!-- 点击或默认选中后显示在步骤下方的箭头(使用 v-show 减少渲染延迟) -->
69 + <div v-show="arrow_visible && step.active && !step.is_placeholder" class="bottom-arrow">
70 + <img src="https://cdn.ipadbiz.cn/stdj/images/home/%E7%82%B9@2x.png" alt="选中" />
67 </div> 71 </div>
68 </div> 72 </div>
69 - <!-- 全局底部箭头:跟随选中项移动 -->
70 - <div v-show="processSteps.length" class="bottom-arrow moving-arrow" :style="arrowStyle">
71 - <img src="https://cdn.ipadbiz.cn/stdj/images/home/%E7%82%B9@2x.png" alt="选中" />
72 </div> 73 </div>
73 </div> 74 </div>
74 </div> 75 </div>
...@@ -200,18 +201,19 @@ const videoOptions = ref({ ...@@ -200,18 +201,19 @@ const videoOptions = ref({
200 const processSteps = ref([]) 201 const processSteps = ref([])
201 // 流程步骤容器引用 202 // 流程步骤容器引用
202 const processStepsRef = ref(null) 203 const processStepsRef = ref(null)
203 -// 底部箭头的动态样式(保持在容器内,避免被裁剪) 204 +/**
204 -const arrowStyle = ref({ left: '50%', bottom: '0.25rem', transform: 'translateX(-50%)' }) 205 + * 是否显示箭头
205 -// 底部箭头在不同屏幕下的rem偏移值 206 + * 说明:默认不显示,用户点击步骤后显示在该步骤下方
206 -const arrowBottomRem = ref(0.25) 207 + * @type {import('vue').Ref<boolean>}
208 + */
209 +const arrow_visible = ref(false)
207 210
208 /** 211 /**
209 - * 处理窗口尺寸变化:更新箭头bottom并重新定位箭头 212 + * 处理窗口尺寸变化:仅更新装饰线位置
210 * @returns {void} 213 * @returns {void}
211 */ 214 */
212 const handleResize = () => { 215 const handleResize = () => {
213 - updateArrowBottomByScreen() 216 + calculateLinePosition()
214 - updateArrowPosition()
215 } 217 }
216 218
217 // 每页显示的步骤数量(移动端要求最多7个) 219 // 每页显示的步骤数量(移动端要求最多7个)
...@@ -317,7 +319,7 @@ const ensurePageScrollTop = () => { ...@@ -317,7 +319,7 @@ const ensurePageScrollTop = () => {
317 } 319 }
318 320
319 /** 321 /**
320 - * 点击切换步骤状态并更新底部箭头位置 322 + * 点击切换步骤状态并显示箭头
321 * @param {number} index 选中步骤索引 323 * @param {number} index 选中步骤索引
322 */ 324 */
323 const selectStep = (index) => { 325 const selectStep = (index) => {
...@@ -329,8 +331,8 @@ const selectStep = (index) => { ...@@ -329,8 +331,8 @@ const selectStep = (index) => {
329 scrollToPage(pageIndex) 331 scrollToPage(pageIndex)
330 // 切换步骤后重新计算装饰线位置 332 // 切换步骤后重新计算装饰线位置
331 calculateLinePosition() 333 calculateLinePosition()
332 - // 切换步骤后更新底部箭头位置 334 + // 用户点击后显示箭头
333 - updateArrowPosition() 335 + arrow_visible.value = true
334 } 336 }
335 337
336 /** 338 /**
...@@ -362,8 +364,7 @@ onMounted(async () => { ...@@ -362,8 +364,7 @@ onMounted(async () => {
362 el.addEventListener('scroll', dismissSwipeHint, { passive: true }) 364 el.addEventListener('scroll', dismissSwipeHint, { passive: true })
363 } 365 }
364 }) 366 })
365 - // 初始化不同屏幕下箭头bottom适配并监听resize 367 + // 监听窗口尺寸变化,仅用于更新装饰线位置
366 - updateArrowBottomByScreen()
367 if (typeof window !== 'undefined') { 368 if (typeof window !== 'undefined') {
368 window.addEventListener('resize', handleResize) 369 window.addEventListener('resize', handleResize)
369 } 370 }
...@@ -381,6 +382,8 @@ onMounted(async () => { ...@@ -381,6 +382,8 @@ onMounted(async () => {
381 category_link: item.category_link || '', 382 category_link: item.category_link || '',
382 })) || []; 383 })) || [];
383 processSteps.value[0].active = true; 384 processSteps.value[0].active = true;
385 + // 首次默认选中,立即显示箭头,避免首次点击前不显示
386 + arrow_visible.value = true;
384 // 三师七证 387 // 三师七证
385 mastersList.value = list?.STDJSSQZ?.map(item => ({ 388 mastersList.value = list?.STDJSSQZ?.map(item => ({
386 id: item.id, 389 id: item.id,
...@@ -402,8 +405,6 @@ onMounted(async () => { ...@@ -402,8 +405,6 @@ onMounted(async () => {
402 // 初始化轮播位置 405 // 初始化轮播位置
403 nextTick(() => { 406 nextTick(() => {
404 updateCarouselPosition(false) 407 updateCarouselPosition(false)
405 - // 初始化底部箭头位置
406 - updateArrowPosition()
407 // 列表内容渲染后再兜底回顶一次,避免外部干扰 408 // 列表内容渲染后再兜底回顶一次,避免外部干扰
408 ensurePageScrollTop() 409 ensurePageScrollTop()
409 }) 410 })
...@@ -430,7 +431,6 @@ onUnmounted(() => { ...@@ -430,7 +431,6 @@ onUnmounted(() => {
430 // 监听当前步骤变化,重新计算装饰线位置 431 // 监听当前步骤变化,重新计算装饰线位置
431 watch(currentStep, () => { 432 watch(currentStep, () => {
432 calculateLinePosition() 433 calculateLinePosition()
433 - updateArrowPosition()
434 }, { deep: true }) 434 }, { deep: true })
435 435
436 // 查看更多按钮点击事件 436 // 查看更多按钮点击事件
...@@ -624,58 +624,7 @@ const handleNewsClick = (item) => { ...@@ -624,58 +624,7 @@ const handleNewsClick = (item) => {
624 } 624 }
625 } 625 }
626 626
627 -/** 627 +// 原全局跟随箭头逻辑已移除:箭头改为嵌入步骤内,仅在点击后显示
628 - * 更新底部箭头的位置,使其移动到当前选中步骤下方
629 - */
630 -/**
631 - * 更新底部箭头的位置,使其移动到当前选中步骤下方
632 - * @returns {void}
633 - */
634 -const updateArrowPosition = () => {
635 - const containerEl = processStepsRef.value
636 - if (!containerEl) return
637 -
638 - const stepsEls = containerEl.querySelectorAll('.process-step')
639 - const activeIndex = processSteps.value.findIndex(s => s.active)
640 - if (activeIndex < 0 || !stepsEls[activeIndex]) return
641 -
642 - const activeEl = stepsEls[activeIndex]
643 - const containerRect = containerEl.getBoundingClientRect()
644 - const activeRect = activeEl.getBoundingClientRect()
645 -
646 - // 计算选中项中心点相对容器的left位置
647 - const centerX = activeRect.left + activeRect.width / 2 - containerRect.left
648 -
649 - // 使用px进行精确定位(移动端rem布局下,定位需要像素计算)
650 - arrowStyle.value = {
651 - left: `${centerX}px`,
652 - // 不同屏幕下适配底部偏移(rem单位)
653 - bottom: `${arrowBottomRem.value}rem`,
654 - transform: 'translateX(-50%)'
655 - }
656 -}
657 -
658 -/**
659 - * 依据屏幕宽度适配箭头bottom值
660 - * 说明:遵循项目rem基准16px,将窗口宽度转换为rem做断点判断
661 - * - ≤30rem(约≤480px):0.25rem
662 - * - ≤48rem(约≤768px):0.3rem
663 - * - >48rem:0.5rem
664 - * @returns {void}
665 - */
666 -const updateArrowBottomByScreen = () => {
667 - let wRem = 48
668 - if (typeof window !== 'undefined') {
669 - wRem = (window.innerWidth || 768) / 16
670 - }
671 - if (wRem <= 30) {
672 - arrowBottomRem.value = 0
673 - } else if (wRem <= 48) {
674 - arrowBottomRem.value = -0.25
675 - } else {
676 - arrowBottomRem.value = -0.5
677 - }
678 -}
679 628
680 // 是否显示横向滑动提示 629 // 是否显示横向滑动提示
681 const showSwipeHint = ref(true) 630 const showSwipeHint = ref(true)
...@@ -1109,7 +1058,7 @@ const dismissSwipeHint = () => { ...@@ -1109,7 +1058,7 @@ const dismissSwipeHint = () => {
1109 -webkit-overflow-scrolling: touch; 1058 -webkit-overflow-scrolling: touch;
1110 /* 底部留白,确保容器高度包含箭头展示空间 */ 1059 /* 底部留白,确保容器高度包含箭头展示空间 */
1111 padding-top: 0.5rem; 1060 padding-top: 0.5rem;
1112 - padding-bottom: 1rem; 1061 + padding-bottom: 1.5rem;
1113 } 1062 }
1114 1063
1115 /* 隐藏移动端滚动条以优化视觉 */ 1064 /* 隐藏移动端滚动条以优化视觉 */
......