better-scroll
ps:商品详情联动效果, 当滑动到某个位置时出现
tab
标签栏, 点击tab项
时滑动到对应位置并激活当前类。
滑动元素吸顶.可参考
效果图
安装better-scroll
- 安装:
npm i better-scroll -S
- 组件中引入:
import BScroll from 'better-scroll'
- better-scroll官网
template
注意
content
的高度不超过父容器
的高度,是不能滚动
的哦。
<template>
<div class='goodsWrap'>
<div class="contentList" ref="right">
<div>
<ul ref="r_item">
<li class="right-item-hook">
<div class="bannerBox">
<img src="uploads/banner/20200420/e3cd62c7c283c4e25f372bc80c446cfd.jpeg" alt="">
</div>
<div class="goodsDescBox" ref="boxItem">
商品描述
<!-- 添加测试数据撑开高度 -->
</div>
</li>
<li class="right-item-hook">
<div class="goods-detail-wrap">
商品详情
<!-- 添加测试数据撑开高度 -->
</div>
</li>
</ul>
</div>
</div>
<!-- 滑动到某个点出现置顶 tab标签 -->
<div class="fixedBar" :style="`opacity: ${backgroundColor}`" v-show="hiddenTopBar" :class="hiddenTopBar == true ? 'isFixed' : ''">
<div class="goBack" @click="back">
<img src="../../assets/images/goBack_black.png" alt="">
</div>
<div ref="left">
<ul class="ul" ref="l_item">
<li v-for="(item, index) in categoryList" :key="index" :class="{active: currentIndex == index}" @click="selectItem(index, $event)">
{{item.name}}
</li>
</ul>
</div>
</div>
</div>
</template>
使用better-scroll
<script>
import BScroll from "better-scroll";
export default {
name: "goodsDetail",
data() {
return {
backgroundColor: "", //背景颜色
hiddenTopBar: false, //是否显示tab
categoryList: [{ name: "商品" }, { name: "详情" }], //tab标签
currentIndex: 0, //当前元素下标
};
},
mounted() {
this.$nextTick(() => {
// 实例化 BScroll
this._initScrollY();
//获取右侧tops
this._initTops();
})
},
destroyed() {
this.$refs.listScroll && this.$refs.listScroll.destroy();
},
methods: {
back() {
this.$router.go(-1);
},
// 初始化better-scroll
_initScrollY() {
// 创建左侧滑动
this.lefts = new BScroll(this.$refs.left, {
probeType: 3, // 是否会截流scroll事件
scrollY: true, // 是否开启Y轴滚动方向
click: true, // 是否开启点击事件
useTransition: false, // 防止iphone微信滑动卡顿
bounce: true, // 是否启用回弹动画效果
momentumLimitDistance: 5 // 符合惯性拖动的最小拖动距离
});
//创建右侧滑动
this.rights = new BScroll(this.$refs.right, {
probeType: 2, //这里可以取4个值,具体参考官方文档
click: true,
useTransition: false // 防止iphone微信滑动卡顿
});
// 给右侧绑定的BScroll绑定监听事件,获取滑动过程中的位置
this.rights.on("scroll", pos => {
this.scrollY = Math.abs(Math.round(pos.y));
// 是否显示标题
let tops = this.$refs.boxItem.offsetTop;
if (this.scrollY >= tops) {
this.hiddenTopBar = true;
} else {
this.hiddenTopBar = false;
}
//设置背景颜色的透明度
if (tops && this.scrollY) {
// this.backgroundColor = `rgba(250, 252, 255, ${this.scrollY / (this.scrollY + 44)})`;
this.backgroundColor = `${this.scrollY / (this.scrollY + 10)}`;
} else if (this.scrollY == 0) {
this.backgroundColor = "transparent";
}
});
//获取停下来的位置
// 给右侧绑定的BScroll绑定监听事件,获取滑动结束时的位置
this.rights.on("scrollEnd", pos => {
this.scrollY = Math.abs(Math.round(pos.y));
console.log(this.scrollY);
for (let i = 0; i < this.tops.length; i++) {
if (this.scrollY > this.tops[i] && this.scrollY < this.tops[i + 1]) {
// this.currentIndex = i;
if (!this.clickEvent) { //handle是否选中当前元素
this.currentIndex = i;
}
if (i > this.$refs.l_item.children.length - 3) {
var tmp =
i - (this.$refs.l_item.children.length - 3);
//当滚动到倒数第2个位置时左侧列表向上滚动一个距离
this.lefts.scrollToElement(
this.$refs.l_item.children[tmp], 100, 0, 0
);
}
if (i < this.$refs.l_item.children.length - 3) {
//当滚动到第3个位置时左侧列表向下滚动一个距离
this.lefts.scrollToElement(
this.$refs.l_item.children[0], 100, 0, 0
);
}
this.clickEvent = false; //handle
}
}
});
},
//获取当前li的top
_initTops() {
var tops = []; //定义一个空数组
let top = 0;
tops[0] = 0; //第一个li的坐标为0
var lis = this.$refs.r_item.children; //获取到了每个li
//Array.protoype.slice.call(lis) 将具有length属性的对象转成数组 lis可能是个对象
Array.prototype.slice.call(lis).forEach((li, index) => {
// top = top + li.clientHeight; //当前的位置=上一个的位置+这个的高度
top = top + li.clientHeight + 40; //【根据需要调整】
tops.push(top);
});
this.tops = tops;
},
// 滑动某个点联动tab项
selectItem(index, event) {
this.currentIndex = index;
this.clickEvent = true;
if (!event._constructed) {
return;
} else {
let rightItems = this.$refs.right.getElementsByClassName(
"right-item-hook"
);
let el = rightItems[index];
this.rights.scrollToElement(el, 300, 0, -40); //-40:【根据需要调整:标题高度】
}
},
}
};
</script>
style
<style lang='scss' scoped>
@import '../../assets/style/mixin';
.goodsWrap {
@include bg($f5);
@include wh(100%, 100%);
overflow: hidden;
.bannerBox {
@include wh(100%, 705px);
margin: 0 auto;
img {
@include wh(100%, 100%);
}
}
.goodsDescBox {
padding: 10px 30px 20px;
@include bg($white);
}
.goods-detail-wrap {
@include bg($white);
}
.contentList {
position: absolute;
width: 100%;
height: 100%;
top: 0px;
left: 0;
right: 0;
bottom: 0;
overflow: hidden;
-webkit-overflow-scrolling: touch;
}
.isFixed {
position: fixed;
top: 0;
// transition: all .5s;
background: linear-gradient(0deg,
#ffffff 0%,
#f5f5f5 100%);
}
.fixedBar {
@include fcc;
z-index: 10;
position: absolute;
@include wh(100%, 82px);
.goBack {
@include ct;
left: 8px;
@include wh(60px, 60px);
@include fcc;
img {
@include wh(34px, 34px);
}
}
.ul {
@include fc;
li {
@include sc(30px, $fc);
position: relative;
padding-bottom: 8px;
&:not(:first-of-type) {
margin-left: 60px;
}
}
.active {
color: $main;
&::after {
content: '';
@include cl;
bottom: 0;
@include wh(54px, 6px);
@include bg($main);
@include borderRadius(3px);
}
}
}
}
}
</style>