vue外卖十六:商家-食物列表:用滑动库better-scroll滑动列表、收集列表位移、各子列表top值

45 篇文章 2 订阅

一、基础页面+基本滑动功能

1)基础页面+逻辑(见附件)

2)滑动库:better-scroll

  1. 官方文档:https://better-scroll.github.io/docs/zh-CN/guide
  2. git :https://github.com/ustbhuangyi/better-scroll

2.1安装

cnpm install @better-scroll/core --save
// or
yarn add @better-scroll/core

2.2使用shop/goods/goods.vue

  1. 动态展现列表数据
  2. 基本滑动:
    使用better-scroll
    理解其基本原理
    创建BScroll对象的时机
    watch + $nextTick()
    callback + $nextTick
<script>
  import {mapState} from 'vuex'
  //【1】引入库
  import BScroll from '@better-scroll/core'

	export default{
    mounted(){
    /*【2】用action触发请求获取食物列表后:再调用nextTick,
    *相当于vue的watch监听
    *要配合vuex中actions.js中的callback即:getShopGoods({commit},callback)
    */
      this.$store.dispatch('getShopGoods',()=>{
      //【3】将回调延迟到下次 DOM 更新循环之后执行
        this.$nextTick(()=>{
        //【4】新建一个滚动实例参数是要滚动的DOM的类名
          new BScroll('.menu-wrapper')
          //【5】另一个要滚动的DOM
          new BScroll('.foods-wrapper')
        })
      })
    },
    computed:{
      ...mapState(['goods'])
    },
  }
</script>

效果:http://localhost:8080/#/shop/goods

按住都可滑动
在这里插入图片描述

二、滑动右侧左侧分类显示当前样式

1.分析+图解

  1. 滑动右侧列表, 左侧同步更新
    better-scroll禁用了原生的dom事件, 使用的是自定义事件
    绑定监听: scroll/scrollEnd
    滚动监听的类型: probeType
    列表滑动的3种类型
    手指触摸
    惯性
    编码
    3.1 分析:
    类名: current 标识当前分类
    设计一个计算属性: currentIndex
    根据哪些数据计算?
    scrollY: 右侧滑动的Y轴坐标 (滑动过程时实时变化)
    tops: 所有右侧分类li的top组成的数组 (列表第一次显示后就不再变化)
    3.2编码:
    1). 在滑动过程中, 实时收集scrollY
    2). 列表第一次显示后, 收集tops
    3). 实现currentIndex的计算逻辑
  2. 点击左侧列表项, 右侧滑动到对应位置
    如图:
    在这里插入图片描述

2.收集食物列表相对于顶点滑动后的实时位移:scrollY

mounted(){
      this.$store.dispatch('getShopGoods',()=>{//数据更新后执行
        this.$nextTick(()=>{//列表显示之后创建:
          //新建一个滚动对象:第一个参数是类选择器,第二个参数:配置项
          const menuScorll=new BScroll('.menu-wrapper')
          const foodsScorll=new BScroll('.foods-wrapper',{
            probeType:2 //【1】滑动触发具体条件,惯性滑动不记录:文档>配置项>probeType
          })
          /*【2】给食物列表绑定滚动监听:以收集滚动y坐标
          *参数:scroll:文档api的事件的scroll:文档>api>事件>scroll
          */
          foodsScorll.on('scroll',({x,y})=>{
            console.log(x,y)//输出一下滑动坐标看看
            //收集坐标的绝对值y到数据中
            this.scrollY=Math.abs(y)
            console.log(this.scrollY) //输出看看
           })
        })

      })
    }

效果:滚动食物列表,控制台输出:

0 -183
183
0 -734
734
0 -722
722
0 -708
708
0 -687
687
0 -655
655
0 -624
624
0 -585
585

2.1 _initScroll()收集实时位移,单独写成一个方法

mounted(){
      this.$store.dispatch('getShopGoods',()=>{//数据更新后执行
        this.$nextTick(()=>{//列表显示之后创建:
          this._initY() //调用滑动右侧列表,并收集Y位移
          this._initTop() //调用滑动左侧列表,并收集li的值
        })

      })
    },
    computed:{
      ...mapState(['goods']),
      //计算得到当前分类的下标
      currentIndex(){

      }
    },
    methods:{
      //【1】收集滑动时top的实时位移数值
      _initY(){
        //新建一个滚动对象:第一个参数是类选择器,第二个参数:配置项
        new BScroll('.menu-wrapper',{})
        const foodsScorll=new BScroll('.foods-wrapper',{
          probeType:2 //滑动触发具体条件,惯性滑动不记录:文档>配置项>probeType
        })
        /*给食物列表绑定滚动监听:以收集滚动y移位
        *参数:scroll:文档api的事件的scroll:文档>api>事件>scroll
        */
        foodsScorll.on('scroll',({x,y})=>{
          // console.log(x,y)
          this.scrollY=Math.abs(y)
          console.log(this.scrollY)
         })
      },
      //收集li的值
      _initTop(){

      }
    }

3. _initTop():收集食物列表的tops值

即各个食物子分类top2,top3的Y值

methods:{
//收集li的高度值为数组
      _initTop(){
        const tops=[]
        let top=0
        tops.push(top)
        /*结合ul的标识ref=topui,找到所有类名为food-list-hook的元素即
        *li对象组成的多层对象(此对象含lenght属性)
        *li内部有一个叫clientHeight记录此li的高度
        */
        const lis=this.$refs.topUi.getElementsByClassName('food-list-hook')
        // console.log(lis) //打印一下收集到的li们对象组成的数组
        // console.log(typeof(lis)) //看看其类型
        
        // 把lis转换成一个数组,然后逐个读取其高度,并累加计算出每个li的顶部位置传入tops里
        // Array.prototype.slice.call用法详见:
        Array.prototype.slice.call(lis).forEach(li=>{
          // console.log(li)
          top+=li.clientHeight
          tops.push(top)
        })
        this.tops=tops
        console.log(tops)
      },
}

4.计算出scrollY位移所处的top在tops中对应的下标

//【2】:class="{current:k===currentIndex}
<li class="menu-item" v-for="(v,k) in goods" :key=k 
          :class="{current:k===currentIndex}" >

computed:{
      ...mapState(['goods']),
      //【1】计算得到当前位移scrollY,所处分类top在tops中的下标
      currentIndex(){
        // 取得top0当前位移scrollY,和各食物分类top(n)组成的数组tops[]
        const {scrollY,tops}=this
        /* 用findIndex(参数1:当前计算的top值,参数2:当前top的下标)返回
        *  符合要求的下标
        */
        const index=tops.findIndex((top,index)=>{
          // 返回下标满足的条件:scrollY>=top,且<下一个top
          return scrollY>=top && scrollY< tops[index+1]
        })
        // 返回符合的下标(即当前scrollY位移所处的top在tops中对应的下标)
        console.log('index:'+index)
        return index
      }
    }

效果:右侧滑动到对应分类,左侧跟着变

在这里插入图片描述

5. 惯性滑动时左侧当前分类不变+变化不准

methods:{
      //收集滑动食物列表时,列表顶点相对于原位置,在Y轴位移的实时数值
      _initY(){
        //新建一个滚动对象:第一个参数是类选择器,第二个参数:配置项
        new BScroll('.menu-wrapper',{})
        this.foodsScroll=new BScroll('.foods-wrapper',{
          probeType:2 //滑动触发具体条件,惯性滑动不记录:文档>配置项>probeType
        })
        /*给食物列表绑定滚动监听:以收集滚动y移位
        *参数:scroll:文档api的事件的scroll:文档>api>事件>scroll
        */
        this.foodsScroll.on('scroll',({x,y})=>{
          // console.log(x,y)
          this.scrollY=Math.abs(y)
          console.log('scrollY:'+this.scrollY)
         })

        //【2】只收集惯性滚动结束时的y值
        // 给右侧列表绑定scroll结束的监听
        this.foodsScroll.on('scrollEnd', ({x, y}) => {
          console.log('scrollEnd', x, y)
          this.scrollY = Math.abs(y)
        })
      }
}

6.点左侧右侧自动滚动

//@click="clickMenuItem(k) 点击并传值给对应函数
<li class="menu-item" v-for="(v,k) in goods" :key=k 
          :class="{current:k===currentIndex}" @click="clickMenuItem(k)">


methods:{
clickMenuItem(index) {
        // console.log(index)
        // 使用右侧列表滑动到对应的位置

        // 得到目标位置的scrollY
        const scrollY = this.tops[index]
        // 立即更新scrollY(让点击的分类项成为当前分类)
        this.scrollY = scrollY
        // 平滑滑动右侧列表 需要2.1步时用this.foodsScroll把它传入this中
        this.foodsScroll.scrollTo(0, -scrollY, 300)
      }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值