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

本章重点:
- 如何使用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>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue是一种用于构建用户界面的渐进式JavaScript框架,它可以帮助开发者更高效地构建单页面应用程序。而vue-better-scroll是基于Vue的一款优秀的滚动插件,它能够实现更流畅的滚动效果,并且支持上下左右的滚动和联动效果。 如果需要实现左右菜单联动效果,我们可以通过使用vue-better-scrollscrollToElement方法来实现。首先,我们需要在Vue中引入vue-better-scroll插件并进行配置。 在Vue实例的data中,我们可以定义左右两个菜单的数据,例如leftMenu和rightMenu,并在created生命周期中初始化数据。然后,在mounted生命周期中,我们可以通过refs属性获取到两个菜单容器的DOM元素。 接下来,我们需要监听左边菜单的点击事件,当点击左边菜单的某个选项时,我们可以通过调用vue-better-scrollscrollToElement方法,将右边菜单滚动到对应的位置。通过传递目标元素的选择器或具体的DOM元素,我们可以实现左右菜单联动效果。 具体实现时,我们可以在左边菜单的点击事件中,使用this.$refs来访问右边菜单容器,并调用scrollToElement方法,将目标元素滚动到可视区域。通过传递选择器或具体DOM元素作为参数,我们可以精确控制滚动的位置。 同时,为了视觉上更好的效果,我们还可以给目标元素添加样式,如高亮当前选中项,以提升用户体验。 最后,通过一系列的事件处理和样式设置,我们就可以实现左右菜单联动demo了。 以上就是使用Vue和vue-better-scroll实现左右菜单联动demo的大致思路和步骤。通过合理运用这两个工具,我们可以轻松地实现出一个流畅、友好的用户界面效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值