Vue项目中使用betterscroll实现菜单映射功能

32次阅读

共计 5460 个字符,预计需要花费 14 分钟才能阅读完成。

组件全部代码

<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 实现菜单滑动功能

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

 npm install better-scroll --save
引入 import BScroll from 'better-scroll'【在组件中引入,在后续的 export default 中就可以直接使用封装好的 better-scroll 功能了】
  1. 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.on('scroll',(pos) =>{
                // 参数 pos 就是在右侧区域滑动的实时位置
                //Math.round()取整数,Math.abs 取绝对值
                this.scrollY =Math.abs(Math.round(pos.y));
            });
            this._calculateHeight(); // 这个方法为了获取每个商品类的最大区间的高度})
       






正文完
 0