204 lines
4.6 KiB
Vue
204 lines
4.6 KiB
Vue
<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>
|