Files
RyRh 69734f36b4
Test Runner / hello (push) Failing after 32s
修复商品列表滚动错误
2026-08-25 14:25:43 +08:00

204 lines
4.6 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<!-- 4步开始你的按需定制生意 - Figma 1433:1295 -->
<view class="steps-section">
<text class="section-title">4步开始你的按需定制生意</text>
<!-- 步骤卡片横向滚动
受控模式active 由父组件管理scroll-left 跟随 active 把选中卡片尽量滚到左边 -->
<scroll-view
scroll-x
class="steps-scroll"
show-scrollbar="false"
:scroll-left="stepsScrollLeft"
:scroll-with-animation="true"
>
<view class="steps-list">
<view
class="step-card"
:class="{ active: active === index }"
v-for="(item, index) in steps"
:key="index"
@tap="onStepTap(index)"
>
<text class="step-num">{{ item.step }}</text>
<view class="step-text">
<text class="step-title">{{ item.title }}</text>
<text class="step-desc">{{ item.desc }}</text>
</view>
</view>
</view>
</scroll-view>
<!-- 预览大图 - image 25 370x370 6px圆角
跟随 active 联动切换4 步分别对应一张图占位时同图设计师供图后改 mock.js -->
<view class="preview-wrap">
<image
class="preview-img"
:src="previewImg"
mode="widthFix"
></image>
</view>
</view>
</template>
<script>
// 卡片尺寸常量,用于计算 scroll-left(与 CSS 保持一致)
// CSS: .step-card { width:332rpx }, .steps-list gap:16rpx
// 1rpx = 0.5px → 单卡步长 = (332 + 16) * 0.5 = 174px
const CARD_STEP_PX = (332 + 16) * 0.5 // 174
export default {
name: 'StepsFlow',
props: {
steps: {
type: Array,
default: () => []
},
// 受控 active:由父组件(index.vue 的统一轮播定时器)传入
active: {
type: Number,
default: 0
}
},
data() {
return {
stepsScrollLeft: 0
}
},
computed: {
previewImg() {
const s = this.steps[this.active]
return (s && s.img) || ''
}
},
watch: {
active(idx) {
// active 变化(无论是自动轮播还是手动点击)都把选中卡片尽量滚到左边
this.scrollToCard(idx)
}
},
methods: {
onStepTap(index) {
// 子组件不再自管 state,只 emit 给父组件
this.$emit('change', index)
},
/**
* 把第 idx 张卡片「尽量」滚到左边贴边。
* scroll-view 的 scroll-left 超出最大可滚值时会自动截断,
* 因此最后几张卡片虽然无法真正贴左,但已经是「最接近左侧」的位置。
*/
scrollToCard(idx) {
const target = Math.max(0, idx) * CARD_STEP_PX
// 处理 0→0 无变化不触发滚动的情况
if (this.stepsScrollLeft === target) {
this.stepsScrollLeft = target + 0.001
this.$nextTick(() => {
this.stepsScrollLeft = target
})
} else {
this.stepsScrollLeft = target
}
}
}
}
</script>
<style scoped>
.steps-section {
width: 100%;
padding: 0;
background: #ffffff;
}
/* 区块标题 - 20px Heavy #1A1A1A 居中 */
.section-title {
display: block;
text-align: center;
font-size: 40rpx;
font-weight: 900;
color: #1a1a1a;
line-height: 1.45;
margin-top: 96rpx;
margin-bottom: 64rpx;
}
/* 步骤卡片横向滚动 */
.steps-scroll {
width: 100%;
white-space: nowrap;
padding: 0 20rpx;
box-sizing: border-box;
}
.steps-list {
display: inline-flex;
gap: 16rpx;
}
/* 卡片 - 166x80 圆角6px (332rpx × 160rpx) */
.step-card {
flex-shrink: 0;
width: 332rpx;
height: 160rpx;
padding: 20rpx;
background: #f2f2f2;
border-radius: 12rpx;
box-sizing: border-box;
display: flex;
align-items: flex-start;
gap: 16rpx;
}
.step-card.active {
background: #ff6800;
}
/* 步骤编号 - 16px Black weight 900 */
.step-num {
font-size: 32rpx;
font-weight: 900;
color: #ff6800;
line-height: 52rpx;
}
.step-card.active .step-num {
color: #ffffff;
}
.step-text {
flex: 1;
display: flex;
flex-direction: column;
}
/* 步骤标题 - 16px Medium */
.step-title {
font-size: 32rpx;
font-weight: 500;
color: #000000;
line-height: 44rpx;
}
.step-card.active .step-title {
color: #ffffff;
}
/* 步骤描述 - 10px Regular opacity 0.6 */
.step-desc {
margin-top: 6rpx;
font-size: 20rpx;
color: #000000;
opacity: 0.6;
line-height: 1.45;
white-space: normal;
}
.step-card.active .step-desc {
color: #ffffff;
opacity: 1;
}
/* 预览大图 - 370x370 6px圆角 */
.preview-wrap {
margin-top: 20rpx;
padding: 0 20rpx;
box-sizing: border-box;
}
.preview-img {
width: 100%;
border-radius: 12rpx;
display: block;
}
</style>