您的当前位置:首页正文

Vue项目中使用better-scroll实现菜单映射功能方法

2020-11-27 来源:帮我找美食网

组件全部代码

<template>

<div class="goods">
 <!--左侧区域-->
 <div class="menu-wrapper" ref="left">
 <ul class="menu">
 <li class="menu-item border-bottom"
 :class="{'current':currentIndex===index}"
 v-for="(item,index) in dataLlist.goods"
 :key="index"
 @click="selectIndex(index,$event)"
 ref="menuList"
 >
 <div class="text">
 <goods-icon v-show="item.type>0" :index="item.type" class="text-ico"></goods-icon>
 {{item.name}}
 </div>
 </li>
 </ul>
 </div>
 <!--右侧区域-->
 <div class="foods-wrapper" ref="right">
 <ul>
 <li class="food-list food-list-hook"
 v-for="(item,index) in dataLlist.goods"
 :key="index">
 <!--标题区域-->
 <h1 class="border-left">{{item.name}}</h1>
 <ul>
 <li class="food-item border-bottom"
 v-for="(foodItem,index) in item.foods"
 >
 <div class="food-image">
 <img :src="foodItem.icon" alt="foodItem.name">
 </div>
 <div class="food-desc">
 <div class="title">{{foodItem.name}}</div>
 <div class="desc">{{foodItem.description}}</div>
 <div class="num">
 <div class="sellCount">月售{{foodItem.sellCount}}份</div>
 <div class="rating">好评率{{foodItem.rating}}%</div>
 </div>
 <div class="price">
 <div class="new-price">¥{{foodItem.price}}</div>
 <div class="old-price border-bottom" v-show="foodItem.oldPrice">¥{{foodItem.oldPrice}}</div>
 </div>
 </div>

 </li>
 </ul>
 </li>
 </ul>
 </div>
</div>
</template>

<script>

import Icon from '../../common/iconType/Icon';
import BScroll from 'better-scroll'

export default {
 name: "Goods",
 props:['dataLlist'],
 data(){
 return{
 listHeight:[],
 scrollY:0 ,//为了实现左右区域映射
 }
 },
 computed:{
 currentIndex(){ //这个返回的是下标,当这个currentIndex的值与goods的下标一致的时候,
 // 左侧区域就会呈现高亮现象
 for (let i = 0; i < this.listHeight.length; i++) {
 let height1 = this.listHeight[i];
 let height2 = this.listHeight[i + 1];
 if (!height2 || (this.scrollY >= height1 && this.scrollY < height2)) {
 this._followScroll(i) //实现当滑动的时候,左侧隐藏的食物类型显示
 return i;
 }
 }
 return 0;
 }
 },
 created(){
 //dataLlist数据是异步加载,直接用new BScroll时,dom可能还没有更新
 this.$nextTick(()=>{ //this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行,使用$nextTick异步初始化Bscroll
 this.meunScroll=new BScroll(this.$refs.left,{
 click:true
 });
 this.foodScroll=new BScroll(this.$refs.right,{
 probeType: 3 //可以派发scroll事件,检测到实时滚动的位置
 });
 this.foodScroll.on('scroll',(pos) =>{
 //参数pos就是在右侧区域滑动的实时位置
 //Math.round()取整数,Math.abs取绝对值
 this.scrollY =Math.abs( Math.round(pos.y));
 });
 this._calculateHeight(); //这个方法为了获取每个商品类的最大区间的高度
 })
 },
 methods:{
 _followScroll(index) {
 if(index > 0 ){
 let menuList = this.$refs.menuList;
 let el = menuList[index];
 this.meunScroll.scrollToElement(el, 300, 0, -100);//better-scroll的scrollToElement方法滚动到指定位置
 }
 },
 _calculateHeight(){ //这个方法为了获取每个商品类的最大区间的高度
 let height = 0;
 let foodLsit = this.$refs.right.getElementsByClassName('food-list-hook');
 this.listHeight.push(height); //listHeight这个数组是用来存放右侧商品中每个类型商品的最大区间高度的集合
 for(var i=0;i<foodLsit.length;i++){
 let item = foodLsit[i];
 //clientHeight代表元素的高度
 height += item.clientHeight; //每个元素的高度等于自身高度加上上一个元素的高度
 this.listHeight.push(height); //最终listHeight集合了所有li[类为food-list-hook]到最顶部的高度
 }
 },
 selectIndex(index,ele){
 //better-scroll 会禁止移动端的点击事件,需要重新派发,同时在PC端会点击两次,此处需要做判断
 if(!ele._constructed){
 //better-scroll的派发事件scroll的event和pc端浏览器的点击事件的event有个
 // 属性区别_constructed,pc端浏览器的点击事件的event中是没有这个属性的
 return;
 }
 let rightItem =this.$refs.right.getElementsByClassName('food-list-hook');
 let item = rightItem[index]; //找到相应的li
 this.foodScroll.scrollToElement(item, 250) //better-scroll的scrollToElement方法滚动到指定位置
 }
 // scrollToElement(el, time, offsetX, offsetY, easing) //第一个值接收目标元素,第二个是滚动时间,第三第四个是相对于目标元素的偏移量。
},

 components:{
 'goods-icon': Icon
 }

}
</script>

<style scoped lang="stylus">

@import "../../assets/stylus/mixin.styl"
.goods

position absolute
top 3.6rem
bottom .92rem
display flex
width: 100%
overflow: hidden
.menu-wrapper
 flex 0 0 1.6rem
 width 1.6rem
 background-color #f3f5f7
 .menu-item
 height 1.08rem
 display flex
 align-items center
 justify-content left
 &.border-bottom::before
 color rgba(7,17,27,.1)
 .text
 font-weight 200
 font-size .24rem
 line-height .28rem
 margin 0 .24rem
 .text-ico
 margin-right -.08rem
 vertical-align top;
 &.current
 font-size .24rem
 line-height .28rem
 color rgb(240,20,20)
 background-color #ffffff
.foods-wrapper
 flex 1
 .food-list
 h1
 width 100%
 height .52rem
 line-height .52rem
 padding-left .28rem
 background-color #f3f5f7
 font-size .24rem
 color rgb(147,153,159)
 &.border-left::before
 border-color #d9dde1
 border-width .1rem


 .food-item
 display flex
 padding .36rem
 &:last-child.border-bottom
 border none
 .food-desc
 margin-left .2rem
 font-size .2rem
 color rgb(147,153,159)
 .title
 font-size:.28rem
 color rgb(7,17,27)
 margin-top .04rem
 line-height .28rem
 .desc
 margin .15rem auto
 line-height:.28rem
 .num
 display flex
 margin 0 0 .16rem 0
 .sellCount
 margin-right .24rem

 .price
 display flex
 align-items center
 .new-price
 color rgb(220,20,60)
 font-weight 700
 line-height .48rem
 margin-right .16rem
 font-size .28rem

 .old-price
 &.border-bottom::before
 position absolute
 top: 25%;
 border-width: 0.08rem;

</style>

Vue项目中使用better-scroll实现菜单滑动功能

安装和在组件中引入better-scroll

npm install better-scroll --save

引入import BScroll from 'better-scroll' 【在组件中引入,在后续的export default中就可以直接使用封装好的better-scroll功能了】

better-scroll实现的下面功能

在菜单中要实现点击左侧菜单的食品类型名称,右侧就会自动滑动到此食品类型下的所有食品;在右侧区域中滑动到食品类型下的所有食品区域下的时候,左侧菜单会出现相应的高亮效果

如何实现上面的功能:

第一:需要知道要在哪些区域间实现滑动

第二:通过new BScroll()获取要实现滑动的区域

this.meunScroll=new BScroll(this.$refs.left);
this.foodScroll=new BScroll(this.$refs.right);

第三:上面代码在理论上应该在相应的区域都应该能滑动了,但是现实是并不能滑动

原因是:数据的获取是异步获取的,在定义滑动区域的时候,也许数据还没有更新,这是this.meunScroll的高度可能就没有高度外部类goods的高度,这样就不会滑动。

解决的方法:this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行,使用$nextTick异步初始化Bscroll

 this.$nextTick(()=>{ //this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行,使用$nextTick异步初始化Bscroll
 this.meunScroll=new BScroll(this.$refs.left,{
 click:true //左侧菜单可以进行点击事件
 });
 this.foodScroll=new BScroll(this.$refs.right,{
 probeType: 3 //可以派发scroll事件,检测到实时滚动的位置
 });
 【this.foodScroll中必须有 probeType: 3后才能进行下面的scroll事件】
 this.foodScroll.on('scroll',(pos) =>{
 //参数pos就是在右侧区域滑动的实时位置
 //Math.round()取整数,Math.abs取绝对值
 this.scrollY =Math.abs( Math.round(pos.y));
 });
 this._calculateHeight(); //这个方法为了获取每个商品类的最大区间的高度
 })

获取每个右侧区域的 <li class="food-list food-list-hook">的高度

在data中定义一个空listHeight数组;数组中的元素代表了每个li到this.foodScroll最顶部的区域高度;

_calculateHeight(){ //这个方法为了获取每个商品类的最大区间的高度

 let height = 0;
 let foodLsit = this.$refs.right.getElementsByClassName('food-list-hook');
 this.listHeight.push(height); //listHeight这个数组是用来存放右侧商品中每个类型商品的最大区间高度的集合
 for(var i=0;i<foodLsit.length;i++){
 let item = foodLsit[i];
 //clientHeight代表元素的高度
 height += item.clientHeight; //每个元素的高度等于自身高度加上上一个元素的高度
 this.listHeight.push(height); //最终listHeight集合了所有li[类为food-list-hook]到最顶部的高度
 }
 },
let foodLsit = this.$refs.right.getElementsByClassName('food-list-hook');

foodLsit表示所有li【 <li class="food-list food-list-hook">】dom集合;

显示全文