JavaScript

超轻量级php框架startmvc

vue.js2.0 实现better-scroll的滚动效果实例详解

更新时间:2020-07-20 23:12:01 作者:startmvc
什么是better-scrollbetter-scroll是一个移动端滚动的解决方案,它是基于iscroll的重写,它和iscrol

什么是 better-scroll

better-scroll 是一个移动端滚动的解决方案,它是基于 iscroll 的重写,它和 iscroll 的主要区别在这里 。better-scroll 也很强大,不仅可以做普通的滚动列表,还可以做轮播图、picker 等等。


<template>
 <div>
 <div class="goods">
 <div class="menu-wrapper" ref="menuWrapper">
 </div>
 <div class="food-wrapper" ref="foodWrapper">
 </div>
 </div>
 </div>
</template>

与1.0版本不同的是,我们使用的是ref


<script type="text/ecmascript-6">
 import BScroll from "better-scroll";
 export default {
 data(){
 return {
 currentIndex:1,
 goods:[]
 } 
 },
 created(){
 this.classMap=['decrease','discount','special','invoice','guarantee'];
 this.$http.get('/api/goods').then((response)=>{
 response=response.body;
 if (response.errno===ERR_OK) {
 this.goods=response.data;
 }
 //dom结构加载结束(nextTick这个接口是计算dom相关的,要确保原生dom已经渲染了)
 this.$nextTick(()=>{
 this._initScroll();
 });
 });
 },
 methods:{
 _initScroll(){
 // 使用better-scroll实现的关键代码
 this.menuScroll=new BScroll(this.$refs.menuWrapper,{click:true});
 this.foodScroll=new BScroll(this.$refs.foodWrapper,{click:true});
 }
 }
 };
</script>

很简单这样页面就可以滚动了,如下图

但是,这样左右两个页面并没有联动起来,需要我们再定义一个方法来计算滚动的高度,以及在计算属性中计算左侧当前索引在哪里

从而定义左侧边栏的位置


 computed:{
 //用来计算左侧当前索引在哪,从而定位到左侧边栏的位置
 currentIndex(){
 for (let i = 0; i < this.listHeight.length; i++) {
 var height1=this.listHeight[i] ;
 var height2=this.listHeight[i+1];
 if(!height2||(this.scrollY >= height1 && this.scrollY < height2)){
 return i;
 }
 }
 return 0;
 }
 },
 methods:{
 _initScroll(){
 // 使用better-scroll实现的关键代码
 this.menuScroll=new BScroll(this.$refs.menuWrapper,{click:true});
 this.foodScroll=new BScroll(this.$refs.foodWrapper,{
 click: true,
 //探针作用,实时监测滚动位置
 probeType: 3
 });
 this.foodScroll.on('scroll',(pos)=>{
 this.scrollY=Math.abs(Math.round(pos.y))
 });
 },
 _calculateHeight(){
 let foodList=this.$refs.foodWrapper.getElementsByClassName('food-list-hook');
 let height=0;
 this.listHeight.push(height);
 for (var i = 0; i < foodList.length; i++) {
 let item=foodList[i];
 height+=item.clientHeight;
 this.listHeight.push(height);
 }
 }
 }
//dom结构加载结束(nextTick这个接口是计算dom相关的,要确保原生dom已经渲染了)
 this.$nextTick(()=>{
 this._initScroll();
 this._calculateHeight();
 });

在dom渲染后,也是需要计算高度的.

滑动右边,实现左边联动已经实现了,接下来就是,点击左边的菜单,右边的食物相应滚动到具体的位置

给左边菜单绑定一个事件:@click="selectMenu(index,$event)"


/左边的菜单项的点击事件
selectMenu(index,event){
//自己默认派发事件时(BScroll),_constructed默认为true.但原生的浏览器并没有这个属性
 if (!event._constructed) {
 return;
 }
 //运用BScroll滚动到相应位置
 //运用index去找到对应的右侧位置
 let foodList=this.$refs.foodWrapper.getElementsByClassName('food-list-hook');
 //滚动到相应的位置
 let el=foodList[index];
 //设置滚动时间
 this.foodScroll.scrollToElement(el,2000);
}

至此,整个联动实现的,完整代码如下


<template>
 <div>
 <div class="goods">
 <div class="menu-wrapper" ref="menuWrapper">
 <ul>
 <li v-for="(item,index) in goods" class="menu-item" :class="{'current':currentIndex===index}" @click="selectMenu(index,$event)">
 <span class="text border-1px">
 <span v-show="item.type>0" class="icon" :class="classMap[item.type]"></span>{{item.name}}
 </span>
 </li>
 </ul>
 </div>
 <div class="food-wrapper" ref="foodWrapper">
 <ul>
 <li v-for="(item,index) in goods" class="food-list food-list-hook">
 <h1 class="title">{{item.name}}</h1>
 <ul>
 <li v-for="food in item.foods" class="food-item border-1px">
 <div class="icon">
 <img :src="food.icon" width="57" height="57" alt="">
 </div>
 <div class="content">
 <h2 class="name">{{food.name}}</h2>
 <p class="desc">{{food.description}}</p>
 <div class="extra">
 <span class="count">月售{{food.sellCount}}份</span>
 <span>好评率{{food.rating}}%</span>
 </div>
 <div class="price">
 <span class="now">¥{{food.price}}</span><span class="old" v-show="food.oldPrice">¥{{food.oldPrice}}</span>
 </div>
 </div>
 </li>
 </ul>
 </li>
 </ul>
 </div>
 </div>
 </div>
</template>
<script type="text/ecmascript-6">
 import BScroll from "better-scroll";
 const ERR_OK=0;
 export default {
 props:{
 seller:{
 type:Object
 }
 },
 data(){
 return {
 goods:[],
 listHeight:[],
 scrollY:0
 } 
 },
 created(){
 this.classMap=['decrease','discount','special','invoice','guarantee'];
 this.$http.get('/api/goods').then((response)=>{
 response=response.body;
 if (response.errno===ERR_OK) {
 this.goods=response.data;
 }
 //dom结构加载结束(nextTick这个接口是计算dom相关的,要确保原生dom已经渲染了)
 this.$nextTick(()=>{
 this._initScroll();
 this._calculateHeight();
 });
 });
 },
 computed:{
 //用来计算左侧当前索引在哪,从而定位到左侧边栏的位置
 currentIndex(){
 for (let i = 0; i < this.listHeight.length; i++) {
 var height1=this.listHeight[i] ;
 var height2=this.listHeight[i+1];
 if(!height2||(this.scrollY >= height1 && this.scrollY < height2)){
 return i;
 }
 }
 return 0;
 }
 },
 methods:{
 _initScroll(){
 // 使用better-scroll实现的关键代码
 this.menuScroll=new BScroll(this.$refs.menuWrapper,{click:true});
 this.foodScroll=new BScroll(this.$refs.foodWrapper,{
 click: true,
 //探针作用,实时监测滚动位置
 probeType: 3
 });
 this.foodScroll.on('scroll',(pos)=>{
 this.scrollY=Math.abs(Math.round(pos.y))
 });
 },
 _calculateHeight(){
 let foodList=this.$refs.foodWrapper.getElementsByClassName('food-list-hook');
 let height=0;
 this.listHeight.push(height);
 for (var i = 0; i < foodList.length; i++) {
 let item=foodList[i];
 height+=item.clientHeight;
 this.listHeight.push(height);
 }
 },
 //左边的菜单项的点击事件
 selectMenu(index,event){
 //自己默认派发事件时(BScroll),_constructed默认为true.但原生的浏览器并没有这个属性
 if (!event._constructed) {
 return;
 }
 //运用BScroll滚动到相应位置
 //运用index去找到对应的右侧位置
 let foodList=this.$refs.foodWrapper.getElementsByClassName('food-list-hook');
 //滚动到相应的位置
 let el=foodList[index];
 //设置滚动时间
 this.foodScroll.scrollToElement(el,2000);
 }
 }
 };
</script>
<style lang="stylus" rel="stylesheet/stylus">
 @import "../../common/stylus/mixin.styl";
 
 .goods
 display:flex
 position:absolute
 top:174px
 bottom:46px
 width:100%
 overflow:hidden
 .menu-wrapper
 flex:0 0 80px
 width: 80px
 background:#f3f5f7
 .menu-item
 display:table
 height:54px
 width:56px
 padding:0 12px
 line-height:14px
 &.current
 position:relative
 z-index:10
 margin-top:-1px
 background:#fff
 font-weight:700
 .text
 border-none()
 .icon
 display:inline-block
 vertical-align:top
 margin-right:2px
 width:12px
 height:12px
 background-size:12px 12px
 background-repeat:no-repeat
 &.decrease
 bg-image('decrease_3')
 &.discount
 bg-image('discount_3') 
 &.guarantee
 bg-image('guarantee_3') 
 &.invoice
 bg-image('invoice_3')
 &.special
 bg-image('special_3')
 .text
 display:table-cell
 vertical-align:middle
 width:56px
 border-1px(rgba(7,17,27,0.1))
 font-size:12px
 .food-wrapper
 flex:1
 .title
 padding-left:14px
 font-size:12px
 color:rgb(147,153,159)
 height:26px
 border-left:2px solid #d9dde1
 line-height:26px
 background:#f3f5f7
 .food-item
 display:flex
 margin:18px
 padding-bottom:18px
 border-1px(rgba(7,17,27,0.1))
 &:last-child
 border-none()
 margin-bottom:0
 .icon
 flex:0 0 57px
 margin-right:10px
 .content
 flex:1
 .name
 margin:2px 0 8px 0
 height:14px
 line-height:14px
 font-size:14px
 color:rgb(7,17,27) 
 .desc,.extra
 line-height:10px
 font-size:10px
 color:rgb(147,153,159)
 .desc 
 margin-bottom:8px
 line-height:12px
 .extra
 .count
 margin-right:12px
 .price
 font-weight:700
 line-height:24px
 .now
 margin-right:8px
 font-size:14px
 color:rgb(240,20,20)
 .old
 text-decoration:line-through
 font-size:10px
 color:rgb(147,153,159)
</style>

总结

以上所述是小编给大家介绍的vue.js2.0 实现better-scroll的滚动效果实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

vue.js2.0 better-scrol vue.js 滚动