美文网首页Vue.js学习Vue.jsVue.js开发技巧
十、Vue如何使用better-scroll插件

十、Vue如何使用better-scroll插件

作者: 陈楠酒肆 | 来源:发表于2017-08-29 12:46 被阅读470次

    在我们移动项目开发中,经常会处理滚动列表的功能,有的是横向滚动列表,有的是纵向滚动列表。我们在实现这类滚动效果的时候,一般会使用better-scroll插件。
    better-scroll是基于移动端滚动的解决方案,它是基于iscroll重写。better-scroll很强大,不仅可以做普通的滚动列表,还可以做轮播图、Picker等等。
    今天我就以“饿了么”来讲解如何使用better-scroll。先看“饿了么”动图:

    饿了么

    今天我们主要实现以下几个功能:

    1、左右侧页面滑动,并且不显示滚动条
    2、根据左侧的商品类别对应到右侧相应的选择区间,并且高亮标题
    3、根据右侧用户滑动的区间,能够对应到左侧的商品类别,并且高亮选择标题

    安装插件

    这个很简单,一句话就搞定。

    npm install--save better-scroll
    

    以下我们就直接上代码,需要注意的地方我们会说明

    样式代码

    [v-cloak] {
                display: none;
            }
    
            .goods {
                position: absolute;
                width: 100%;
                top: 174px;
                bottom: 46px;
                display: flex;
                overflow: hidden;
            }
    
            .goods .menu-wrapper {
                flex: 0 0 80px;
                width: 80px;
                background: #f3f5f7;
            }
    
            .goods .menu-wrapper .current {
                position: relative;
                z-index: 10;
                margin-top: -1px;
                background: #FFFFFF;
                font-weight: 700;
                font-size: 14px;
            }
    
            .goods .menu-wrapper .menu-item {
                display: table;
                height: 54px;
                width: 80px;
                line-height: 14px;
                padding: 0 12px;
                border-bottom: 1px solid rgba(7, 17, 27, .1);
                box-sizing: border-box;
            }
    
            .goods .menu-wrapper .menu-item .icon {
                display: inline-block;
                width: 12px;
                height: 12px;
                margin-right: 2px;
                -webkit-background-size: 12px 12px;
                background-size: 12px 12px;
                background-repeat: no-repeat;
                vertical-align: top;
            }
    
            .goods .menu-wrapper .menu-item .text {
                display: table-cell;
                width: 56px;
                vertical-align: middle;
                font-size: 12px;
                text-align: center;
            }
    
            .goods .menu-wrapper .menu-item .decrease {
                background-image: url(img/decrease_2@2x.png);
            }
    
            .goods .menu-wrapper .menu-item .discount {
                background-image: url(img/decrease_2@2x.png);
            }
    
            .goods .menu-wrapper .menu-item .guarantee {
                background-image: url(img/decrease_2@2x.png);
            }
    
            .goods .menu-wrapper .menu-item .invoice {
                background-image: url(img/decrease_2@2x.png);
            }
    
            .goods .menu-wrapper .menu-item .special {
                background-image: url(img/decrease_2@2x.png);
            }
    
            .goods .foods-wrapper {
                flex: 1;
            }
    
            .goods .foods-wrapper .title {
                padding-left: 14px;
                height: 26px;
                line-height: 26px;
                border-left: 2px solid #d9dde1;
                font-size: 12px;
                color: rgb(147, 153, 159);
                background: #F3F5F7;
            }
    
            .goods .foods-wrapper .current {
                color: #42B983;
                font-size: 14px;
                transition: all .5s;
                line-height: 27px;
            }
    
            .goods .foods-wrapper .food-item {
                display: flex;
                margin: 18px 0 18px 0;
                border-bottom: 1px solid rgba(7, 17, 27, .1);
                padding-bottom: 18px;
            }
    
            .goods .foods-wrapper .food-item:last-child {
                border-bottom: 0px solid rgba(7, 17, 27, .1);
                margin-bottom: 0;
            }
    
            .goods .foods-wrapper .food-item .icon {
                flex: 0 0 57px;
                margin-right: 10px;
                margin-left: 10px;
            }
    
            .goods .foods-wrapper .food-item .content {
                position: relative;
                flex: 1;
            }
    
            .goods .foods-wrapper .food-item .content .name {
                margin: 2px 0 8px 0;
                height: 14px;
                line-height: 14px;
                font-size: 14px;
                color: rgb(7, 17, 27);
            }
    
            .goods .foods-wrapper .food-item .content .desc {
                margin-bottom: 8px;
                line-height: 10px;
                font-size: 10px;
                color: rgb(147, 153, 159);
            }
    
            .goods .foods-wrapper .food-item .content .extra {
                font-size: 10px;
                color: rgb(147, 153, 159);
                line-height: 10px;
            }
    
            .goods .foods-wrapper .food-item .content .extra .count {
                margin-right: 12px;
            }
    
            .goods .foods-wrapper .food-item .content .price {
                font-weight: 700;
                line-height: 24px;
            }
    
            .goods .foods-wrapper .food-item .content .price .now {
                margin-right: 8px;
                font-size: 14px;
                color: rgb(240, 20, 20);
            }
    
            .goods .foods-wrapper .food-item .content .price .old {
                text-decoration: line-through;
                font-size: 10px;
                color: rgb(147, 153, 159);
            }
    
            .goods .foods-wrapper .food-item .content .cartcontrol-wrapper {
                position: absolute;
                right: 6px;
                bottom: 12px;
            }
    

    页面布局

    <template>
    <div class="goods" v-cloak>
                <div class="menu-wrapper" ref="menuwrapper">
                    <ul>
                        <!--当currentIndex与index相等的时候,设置高亮-->
                        <li v-for="(item,index) in goods" class="menu-item" :class="{'current':currentIndex === index}" @click="selectMenu(index,$event)" v-cloak>
                            <span class="text">
                                    <span v-show="item.type>0" class="icon" :class="classMap[item.type]" v-cloak></span> {{item.name}}
                            </span>
                        </li>
                    </ul>
                </div>
                <div class="foods-wrapper" ref="foodwrapper">
                    <ul>
                        <!--food-list-hook用于dom操作,获取整体容器的高度-->
                        <li v-for="(item,index) in goods" class="food-list food-list-hook" v-cloak>
                            <h2 class="title" :class="{'current':currentIndex === index}">{{item.name}}</h2>
                            <ul>
                                <li @click="selectfood(food,$event)" v-for="food in item.foods" class="food-item">
                                    <div class="icon">
                                        ![](food.icon)
                                    </div>
                                    <div class="content">
                                        <h2 class="name">{{food.name}}</h2>
                                        <p class="desc">{{food.description}}</p>
                                        <div class="extra">
                                            <span class="count">月售{{food.sellCount}}份</span>
                                            <span>好评率{{food.rating}}%</span>
                                        </div>
                                        <div class="price">
                                            <span class="now">¥{{food.price}}</span>
                                            <span v-show="food.oldPrice" class="old">¥{{food.oldPrice}}</span>
                                        </div>
                                    </div>
                                </li>
                            </ul>
                        </li>
                    </ul>
                </div>
            </div>  
    </template>
    

    JS代码

    <script>
    export default {
     data() {
          return {
           msg: 'goods',
                    goods: [],
                    listHeight: [],
                    scrollY: 0,
          }
        },
    created() {
                    this.classMap = ['decrease', 'discount', 'guarantee', 'invoice', 'special'];
                    this.$http.get('./data.json').then((res) => {
                        if(res.status === ERR_OK) {
                            res = res.body.goods;
                            this.goods = res;
                            //dom结构加载结束
                            this.$nextTick(() => {
                                this._initScroll();
                                //计算高度
                                this._calculateHeight();
                            })
                        }
                    });
                },
    computed: {
                    currentIndex() {
                        for(let i = 0; i < this.listHeight.length; i++) {
                            //判断当currentIndex在height1和height2之间的时候显示
                            let height1 = this.listHeight[i];
                            let height2 = this.listHeight[i + 1];
                            //          console.log('height1:'+height1+','+'height2:'+height2)
                            //最后一个区间没有height2
                            if(!height2 || (this.scrollY >= height1 && this.scrollY < height2)) {
                                return i;
                            }
                        }
                        return 0;
                    }
                },
    methods: {
                    selectMenu(index, event) {
                        //      自己默认派发事件时候(BScroll),_constructed被置为true,但是浏览器原生并没有这个属性
                        if(!event._constructed) {
                            return;
                        }
                        //运用BScroll接口,滚动到相应位置
                        let foodList = this.$refs.foodwrapper.getElementsByClassName('food-list-hook');
                        //获取对应元素的列表
                        let el = foodList[index];
                        this.foodScroll.scrollToElement(el, 300);
                    },
                     /*
                      _initScroll的函数,主要用来对左右两侧dom结构进行初始化 
                     用better-scroll的方法初始化需要滚动的dom结构,
                    vue为我们提供了一个方法可以便利的获取到 dom结构,
                    我们在需要获取dom结构的父容器内添加ref="foodwrapper" ,
                   然后在函数内用this.$refs.menuwrapper获取到dom
                    */
                    _initScroll() {
                        this.meunScroll = new BScroll(this.$refs.menuwrapper, {
                            click: true
                        });
                        this.foodScroll = new BScroll(this.$refs.foodwrapper, {
                            click: true,
                            //探针作用,实时监测滚动位置
                            probeType: 3
                        });
                        //设置监听滚动位置
                        this.foodScroll.on('scroll', (pos) => {
                            //scrollY接收变量
                            this.scrollY = Math.abs(Math.round(pos.y));
                        })
                    },
                    _calculateHeight() {
                        let foodList = this.$refs.foodwrapper.getElementsByClassName('food-list-hook');
                        let height = 0;
                        //把第一个高度送入数组
                        this.listHeight.push(height);
                        //通过循环foodList下的dom结构,将每一个li的高度依次送入数组
                        for(let i = 0; i < foodList.length; i++) {
                            let item = foodList[i]
                            height += item.clientHeight
                            this.listHeight.push(height);
                        }
                    },
                }
    }
    </script>
    

    最后完整的效果图如下:

    最终效果图
    感兴趣的朋友可以去试试。
    为了更好的服务大家,请加入我们的技术交流群:(511387930),同时您也可以扫描下方的二维码关注我们的公众号,每天我们都会分享经验,谢谢大家。

    相关文章

      网友评论

        本文标题:十、Vue如何使用better-scroll插件

        本文链接:https://www.haomeiwen.com/subject/qyjodxtx.html