饿了么项目---8、关于iscoll的扩展 better scroll的使用----左右菜单联动(2)

来源:互联网 发布:爆菊 知乎 编辑:程序博客网 时间:2024/06/08 04:09

本章重点:
- 如何使用better scroll的事件派发
- better scroll的滚动监听事件、如何滚动元素、如何实现左右联动的巧妙逻辑

一、效果图

image

二、需求分析

  1. 分块: good.vue组件主要分为左侧菜单区、右侧内容区、底部购物车区
  2. 单侧联动之当右侧内容区滚动时需要滑动到左侧相应菜单块.
    • 使用better scroll 滚动监听事件,监听当前滚动的y轴坐标scrollY
    • 内容区每个块顶部的y轴坐标,组成数组 listHeight,与左侧的index一一对应上
    • 左侧菜单的index等于当前滑动内容的currentIndex时,currentMenu高亮css类生效。currentIndex为计算属性,根据scrollY与listHeight数组的当前与下一个坐标做对比,判断滚动在哪个区间,则currentIndex为listHeight数组的当前坐标的index。
  3. 单侧联动之点击左侧菜单区,右侧内容区滚动到相应区块
    • 使用better scroll为左侧 菜单派发click点击事件,事件函数传递当前菜单的index
    • 为右侧内容区注册节点==ref=’foodsWrapper’==,获取每个内容区的DOM对象==this.$refs.foodsWrapper.getElementsByClassName(‘food-list-hook’);==
    • 使用better scroll的APIthis.foodsScroll.scrollToElement(el, duration),直接滚动到当前内容区index的DOM对象

三、完整的该模块的代码如下:

<template> <div class="goods">    <div ref='menuWrapper'>        <div class='goodsMenu'>            <div v-for='(item,index) in goods' class='Menu-item' :class='{currentMenu:currentIndex===index}' @click='menuClick(index,$event)'>                <span class='itemText'><span v-show='item.type>0' class='h-iconJ' :class='classMap[item.type]'></span>{{item.name}}</span>            </div>         </div>     </div>    <div ref='foodsWrapper'>        <div class='goodsLists'>           <div class='listOne food-list-hook' v-for='item in goods'>               <h1 class='listOneTitle'>{{item.name}}</h1>               <div class='foodsOne' :class='{boderBottom:item.foods.length>1}' v-for='list in item.foods'>                    <cartcontrol :food ='list'></cartcontrol>                    <div class='listImg'>                        <img :src="list.image">                    </div>                    <div class='goodInfo'>                        <div class='goodsName'>{{list.name}}</div>                        <div class='goodsDesc'>{{list.description}}</div>                        <div class='goodsxs'><span>月售{{list.sellCount}}</span><span>好评率{{list.rating}}%</span></div>                        <div class='foodsPrice'><span>{{list.price}}</span><span class='old' v-show='list.oldPrice!=""'>{{list.oldPrice}}</span>                        </div>                    </div>                </div>            </div>        </div>    </div>    <cartshop :minPrice = 'seller.minPrice' :deliveryPrice = 'seller.deliveryPrice'></cartshop></div></template><script>import BScroll from 'better-scroll';import cartcontrol from '../cartcontrol/cartcontrol.vue';import cartshop from '../cartcontrol/cartshop.vue';export default {    name: 'goods',    components:{cartcontrol,cartshop},    props: {        seller:{            type:Object        }    },    data(){        return{       goods:[],//商品信息       listHeight:[],//每个菜单将要滑动的height       scrollY:0        }    },    computed:{         currentIndex:function(){            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)){                    return i                }            }        }    },    created(){        //左侧菜单图标信息        this.classMap=['decrease_3','discount_3','guarantee_3','invoice_3','special_3'],        //goods商品数据请求        this.$http.get('/api/goods').then((response)=>{          response = response.body;          if(response.errno){            this.goods =response.data;            this.$nextTick(()=>{              this._initScroll();              this._calculateHeight();            })           }        },(response)=>{          console.log(response)        });    },    methods:{        //点击菜单显示右侧相应菜单        menuClick(index,event){            if(!event._constructed) return false;            let foodLists = this.$refs.foodsWrapper.getElementsByClassName('food-list-hook');            let el =foodLists[index];            this.foodsScroll.scrollToElement(el, 500)        },        //初始化better-scroll        _initScroll() {            //获取better-scroll实例            this.meunScroll = new BScroll(this.$refs.menuWrapper, {                click:true            });            this.foodsScroll = new BScroll(this.$refs.foodsWrapper, {                click:true,                probeType:3            });            this.foodsScroll.on('scroll',(pos)=>{                this.scrollY =Math.abs(Math.round(pos.y));            })        },          //获取右侧商品每个列表的y坐标,组成数组listHeight        _calculateHeight() {            let foodLists = this.$refs.foodsWrapper.getElementsByClassName('food-list-hook');            //第一个列表坐标            let height=0;            this.listHeight.push(height);            for(let i=0,len=foodLists.length;i<len;i++){                let item =foodLists[i];                height += item.clientHeight;                this.listHeight.push(height);            }        }    }}</script><style scope>    .goods{        position:absolute;        display: flex;        width:100%;        bottom:46px;        top:176.4px;        overflow: hidden;    }    .goodsMenu{        flex: 0,0,80px;        width:80px;        padding:0 12px;        background-color:#f3f5f7;        box-sizing:border-box;    }    .Menu-item{        position:relative;        display: table;        width:100%;        height:54px;        font-size:0;    }    .Menu-item:after,    .boderBottom:after{        position:absolute;        content: '';        width:100%;        bottom:0;        left:0;        border-top: 1px solid rgba(7,17,27,0.1);         -webkit-transform: scaleY(0.5);        transform: scaleY(0.5);    }    .Menu-item:last-child:after,    .boderBottom:last-child:after{        border-top:none;    }    .currentMenu{        background-color:#fff;        color:#000;        padding: 0 12px;        margin: -1px 0 0 -12px;        border:none;    }    .itemText{        display: table-cell;        font-size:12px;        color:#07111B;        font-weight: 200;        line-height: 14px;        vertical-align: middle;    }    .Menu-item .h-iconJ{        display: inline-block;        width:14px;        height:14px;        margin-right:4px;        background-size:14px 14px;    }    .decrease_3{        background-image: url('decrease_3@2x.png');    }    .discount_3{       background-image: url('discount_3@2x.png');   }   .guarantee_3{       background-image: url('guarantee_3@2x.png');   }   .invoice_3{       background-image: url('invoice_3@2x.png');   }   .special_3{       background-image: url('special_3@2x.png');   }   /*右侧商品区*/   .goodsLists{       flex: 1;   }   /*一个菜单分类*/   .listOne{    width:100%;}/*分类名*/.listOneTitle{    width:100%;    height:26px;    line-height: 26px;    border-left:2px solid #d9dde1;    background-color:#f3f5f7;    padding-left:14px;    font-size:12px;    color:rgb(147,153,159);    box-sizing:border-box;}/*商品介绍*/.foodsOne{    position: relative;    display:flex;    margin:18px;    font-size:0px;    box-sizing:border-box;}.boderBottom {    /*border-bottom:1px solid rgba(7,17,27,0.1);*/    padding-bottom: 18px;}.boderBottom:last-child{    /*border-bottom:none;*/    padding-bottom: 0;}.cartcontrol{    position: absolute;    bottom:18px;    right:0;}.listImg{    flex:0,0,58px;    display:inline-block;    width:58px;    height:58px;    vertical-align: top;}.listImg img{    width:100%;    height:100%;}.goodInfo{    flex:1;    display:inline-block;    margin:2px 0 0 10px;}.goodInfo .goodsName{    font-size:14px;    color:rgb(7,17,27);    line-height: 14px;}.goodInfo .goodsDesc,.goodInfo .goodsxs{    font-size:10px;    color:rgb(147,153,159);    line-height: 12px;    margin-top:8px;}.goodInfo .goodsxs span:first-child{    margin-right:12px;}.goodInfo .foodsPrice{    font-size:10px;    color:rgb(240,20,20);    font-weight: normal;    line-height: 14px;    margin-top:8px;}.goodInfo .foodsPrice .old{    text-decoration:line-through;    margin-left:8px;    color:rgb(147,153,159);}        /*.goodCarts{            width:100%;            height:46px;        }*/    </style>
原创粉丝点击