@@ -4,7 +4,7 @@
|
||||
<text class="section-title">用强大的功能,开启盈利快车道</text>
|
||||
|
||||
<!-- 功能卡片横向滚动
|
||||
:scroll-left 绑定 featScrollLeft,activeFeat 变化时尽量把选中项滚到左侧 -->
|
||||
受控模式:active 由父组件统一管理;scroll-left 跟随 active -->
|
||||
<scroll-view
|
||||
scroll-x
|
||||
class="feat-scroll"
|
||||
@@ -15,7 +15,7 @@
|
||||
<view class="feat-list">
|
||||
<view
|
||||
class="feat-card"
|
||||
:class="{ active: activeFeat === index }"
|
||||
:class="{ active: active === index }"
|
||||
v-for="(item, index) in features"
|
||||
:key="index"
|
||||
@tap="onFeatTap(index)"
|
||||
@@ -30,7 +30,7 @@
|
||||
</scroll-view>
|
||||
|
||||
<!-- 集成平台大图 - 370x257 8px圆角
|
||||
图片来源:features[activeFeat].img(4张卡片分别对应一张大图;占位时 4 张同图,设计师供图后换 mock.js 即可) -->
|
||||
跟随 active 联动切换 -->
|
||||
<view class="integration-wrap">
|
||||
<image
|
||||
class="integration-img"
|
||||
@@ -42,14 +42,10 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
// 功能卡片尺寸(与 CSS 保持一致,用于计算「选中卡片滚到左边」的 scrollLeft)
|
||||
// 卡片尺寸常量,用于计算 scroll-left(与 CSS 保持一致)
|
||||
// CSS: .feat-card { width:332rpx }, .feat-list gap:16rpx
|
||||
// 1rpx = 0.5px,所以 1 张卡片+gap = (332 + 16) * 0.5 = 174px
|
||||
const CARD_WIDTH_PX = 332 * 0.5 // 166
|
||||
const CARD_GAP_PX = 16 * 0.5 // 8
|
||||
const CARD_STEP_PX = CARD_WIDTH_PX + CARD_GAP_PX // 174
|
||||
|
||||
const AUTO_PLAY_INTERVAL = 3000 // 3 秒自动轮播一次
|
||||
// 1rpx = 0.5px → 单卡步长 = (332 + 16) * 0.5 = 174px
|
||||
const CARD_STEP_PX = (332 + 16) * 0.5 // 174
|
||||
|
||||
export default {
|
||||
name: 'PlatformFeatures',
|
||||
@@ -57,53 +53,44 @@ export default {
|
||||
features: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
// 受控 active:由父组件(index.vue 的统一轮播定时器)传入
|
||||
active: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
activeFeat: 0, // 默认从第一张开始轮播
|
||||
featScrollLeft: 0, // scroll-view 的 scroll-left(px)
|
||||
_timer: null
|
||||
featScrollLeft: 0
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
integrationImg() {
|
||||
const f = this.features[this.activeFeat]
|
||||
const f = this.features[this.active]
|
||||
return (f && f.img) || ''
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
activeFeat(idx) {
|
||||
// 选中项变化时:把选中卡片「尽量滚到左边」
|
||||
// index * step = 选中卡片起始 x
|
||||
active(idx) {
|
||||
// active 变化(无论是自动轮播还是手动点击)都把选中卡片尽量滚到左边
|
||||
this.scrollToCard(idx)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.startAutoPlay()
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.stopAutoPlay()
|
||||
},
|
||||
methods: {
|
||||
onFeatTap(index) {
|
||||
// 用户手动点击:切换 + 先停轮播,再隔 3 秒重启(避免刚点完又被立即切走)
|
||||
this.stopAutoPlay()
|
||||
this.activeFeat = index
|
||||
// 子组件不再自管 state,只 emit 给父组件
|
||||
this.$emit('change', index)
|
||||
this.startAutoPlay()
|
||||
},
|
||||
|
||||
/**
|
||||
* 让横滚容器把第 idx 张卡片「尽量」滚到左边贴边。
|
||||
* scroll-view 的 scroll-left 有最大上限(内容总长 - 视口宽度),
|
||||
* 当 idx 是最后几张时,scroll-left 超过最大值,scroll-view 会自动截断到可滚的最大值,
|
||||
* 因此卡片虽无法真的贴左,但已经是「滚到最接近左侧」的位置了。
|
||||
* 把第 idx 张卡片「尽量」滚到左边贴边。
|
||||
* scroll-view 的 scroll-left 超过最大可滚值时会自动截断,
|
||||
* 因此最后几张卡片虽无法真正贴左,但已经是「最接近左侧」的位置。
|
||||
*/
|
||||
scrollToCard(idx) {
|
||||
const target = Math.max(0, idx) * CARD_STEP_PX
|
||||
// 先赋值一个不同的值,保证 uni-app scroll-view 每次都能识别到属性变化
|
||||
// (否则从 0 → 0 这种无变化赋值不触发滚动)
|
||||
// 处理 0→0 无变化不触发滚动的情况
|
||||
if (this.featScrollLeft === target) {
|
||||
this.featScrollLeft = target + 0.001
|
||||
this.$nextTick(() => {
|
||||
@@ -112,24 +99,6 @@ export default {
|
||||
} else {
|
||||
this.featScrollLeft = target
|
||||
}
|
||||
},
|
||||
|
||||
startAutoPlay() {
|
||||
this.stopAutoPlay()
|
||||
if (!this.features || this.features.length <= 1) return
|
||||
this._timer = setInterval(() => {
|
||||
const total = this.features.length
|
||||
const next = (this.activeFeat + 1) % total
|
||||
this.activeFeat = next
|
||||
this.$emit('change', next)
|
||||
}, AUTO_PLAY_INTERVAL)
|
||||
},
|
||||
|
||||
stopAutoPlay() {
|
||||
if (this._timer) {
|
||||
clearInterval(this._timer)
|
||||
this._timer = null
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user