refactor(Home): 优化步骤箭头显示逻辑,改为内嵌式显示
移除全局跟随箭头逻辑,改为在步骤内直接显示箭头 简化窗口尺寸变化处理,仅更新装饰线位置 调整底部留白以适应新箭头布局
Showing
1 changed file
with
20 additions
and
71 deletions
| ... | @@ -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 | /* 隐藏移动端滚动条以优化视觉 */ | ... | ... |
-
Please register or login to post a comment