(八)在vue中使用better-scroll,实现内容区域的滚动效果,以及右边与左边内容相对应,左边呈现高亮状态

本文主要是介绍(八)在vue中使用better-scroll,实现内容区域的滚动效果,以及右边与左边内容相对应,左边呈现高亮状态,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

better-scroll.js是对isScroll.js的重构,isScroll.js的github地址是:isScroll,better-scroll.js的文档手册地址是:better-scroll。

下面讲讲如何在项目中使用better-scroll

1、首先在项目的根目录下安装better-scroll,better-scroll是支持npm安装的,在cmd中输入下面的语句

npm install better-scroll --save

安装好之后会在package.json文件的dependencies里面多了个better-scroll,表示安装成功,如下图所示


2、在要引用该插件的.vue文件的<script>标签的开头将该插件引进来,然后就可以在项目的任何文件里面引用该插件提供的一些方法以及属性了

import BScroll from 'better-scroll'


在开发的时候可以参照better-scroll的文档手册进行开发相应的功能,地址是:better-scroll文档手册


一:下面讲个实例:文件名是goods.vue,在固定高度的区间内实现内容的上下滑动,下图是效果图



1、下面是goods.vue文件里面的<template>代码,我们要对.menu-wrapper对应上图红圈部分和.food-wrapper的内容对应黄圈部分,实现可以上下滑动的效果

<template><div class="goods"><div class="menu-wrapper" ref="menuWrapper"><ul><li v-for="(item,index) in goods" class="menu-item"><span class="text border-1px"><span v-show="item.type > 0" class="icon" :class="classMap[item.type]"></span>{{item.name}}</span></li></ul></div><div class="foods-wrapper" ref="foodsWrapper"><ul><li v-for="item in goods" class="food-list"><h1 class="title">{{item.name}}</h1><ul><li v-for="food in item.foods" class="food-item border-1px"><div class="icon"><img :src="food.icon" width="57" height="57"></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>

2、下面是goods.vue文件中的<style>内容,在这里要注意几点

1)要给父容器一个固定的高度,当子元素的高度超过父元素的高度的时候就可以实现上下滑动的效果了,这里给父元素.goods设置的高度是采用设置display:absolute;top:174px;bottom:46px从而实现固定高度的

2)给父元素设置一个overflow:hidden属性,当子元素的内容的高度超过父元素的高度的时候,就会把超出的部分给隐藏起来

3)给父元素设定一个固定的宽度

<style lang="stylus">@import '../../common/stylus/mixin.styl'.goodsdisplay:flex    /*设置弹性布局*/position:absolute /*设定absolute+top+bottom那么该元素就是一个固定高度的容器了*/top:174px  /*这个是header+tab组件的高度*/width:100%overflow:hiddenbottom:46px /*这个是给底部的购物车留出来的高度*/.menu-wrapperflex:0 0 80px  /*设置左边的元素的宽度为固定值*/width:80pxbackground: #f3f5f7.menu-itemdisplay:tableheight:54pxwidth:56pxpadding:0 12pxline-height:14px.icondisplay: inline-blockvertical-align:topwidth:12pxheight:12pxmargin-right :2pxbackground-size:12px 12pxbackground-repeat :no-repeat&.decreasebg-image('decrease_3')&.discountbg-image('discount_3')&.guaranteebg-image('guarantee_3')&.invoicebg-image('invoice_3')&.specialbg-image('special_3').textdisplay:table-cellwidth:56pxfont-size:12pxvertical-align: middleborder-1px(rgba(7,17,27,0.1)).foods-wrapperflex:1    /*右边的元素的宽度是一个自适应的*/.titlepadding-left:14pxheight:26pxline-height:26pxborder-left: 2px solid #d9dde1font-size:12pxcolor:rgb(147,153,159)background:#f3f5f7.food-itemdisplay:flexmargin:18pxpadding-bottom:18pxborder-1px(rgba(7,17,27,0.1))&:last-childborder-none()margin-bottom:0.iconflex:0 0 57pxmargin-right:10px.contentflex:1.namemargin:2px 0 8px 0height:14pxline-height:14pxfont-size:14pxcolor:rgb(7,17,27).desc,.extraline-height:10pxfont-size:10pxcolor:rgb(147,153,159).descmargin-bottom:8pxline-height:12px.extra.countmargin-right:12px.pricefont-weight:700line-height:24px.nowmargin-right:8pxfont-size:14pxcolor:rgb(240,20,20).oldtext-decoration:line-throughfont-size:10pxcolor:rgb(147,153,159)
</style>

3、下面是goods.vue文件中的<script>标签里面的内容

主要是有两步:在methods属性里面定义一个better-scroll的实例初始化函数;在created()函数里面用vm.$nextTick()中初始化这个实例

1)在methods属性里面定义一个better-scroll的实例初始化函数

methods:{_initScroll(){//初始化需要滚动的对象,通过vm.$refs可以获取到在<template>中设置ref=menuWrapper属性的元素节点this.menuScroll = new BScroll(this.$refs.menuWrapper,{});this.foodsScroll = new BScroll(this.$refs.foodsWrapper,{});} 
}

2)在created()函数里面用vm.$nextTick()中初始化这个实例

created(){//在这个时刻向后台请求数据this.$http.get('/api/goods').then((res) => {res = res.body;if( res.errno === ERR_OK ){this.goods = res.data;// DOM未更新完成this.$nextTick(() => {  //better-scroll的实例初始化要放在vm.$nextTick()里面才生效// DOM已经更新完成this._initScroll();});}});
}

完整的<script>标签里面的内容如下

<script>import BScroll from 'better-scroll'; //引进这个实现上下滑动的插件const ERR_OK = 0;export default {props:{seller:{type:Object}},data(){return {goods:[],}},created(){//在这个时刻向后台请求数据this.$http.get('/api/goods').then((res) => {res = res.body;if( res.errno === ERR_OK ){this.goods = res.data;// DOM未更新完成this.$nextTick(() => {  //better-scroll的实例初始化要放在vm.$nextTick()里面才生效// DOM已经更新完成this._initScroll();});}});//定义一个变量this.classMap = ['decrease','discount','special','invoice','guarantee'];},methods:{_initScroll(){//初始化需要滚动的对象this.menuScroll = new BScroll(this.$refs.menuWrapper,{});this.foodsScroll = new BScroll(this.$refs.foodsWrapper,{});} }}
</script>

经过上述的操作,就可以实现在.menu-wrapper和.foods-wrapper内容区域的滚动了


二、实现左边内容和右边内容的联动效果,并且左边选中的.menu-wrapper是呈高亮的状态(接着上面的代码实现),右边.foods-wrapper区域的滚动会对应左边的menu区呈高亮状态。

主要原理是依赖右边.foods-wrapper滚动时的实时y值,也就是y轴落到那个区间,就对应到.menu-wrapper的那个区间。

那么就需要计算.foods-wrapper中每个li的区间的高度(如下图所示)放到一个数组里面,然后去对比实时滚动的y值,从而得到对应的.menu-wrapper中的元素的索引值,然后利用vue的class的绑定,将高亮的效果实现出来。


1、<template>的内容如下

<template><div class="goods"><div class="menu-wrapper" ref="menuWrapper"><ul><!--currentIndex()在computed里面定义,当计算出来的索引等于index的时候就显示高亮的样式.current--><!--selectMenu(index,$event)实现点击左边的menu,右边滚动到相应的区间,index就是区间索引,$event属性表示原生DOM事件--><li v-for="(item,index) in goods" class="menu-item" :class="{'current':currentIndex === index}" @click="selectMenu(index,$event)"><span class="text border-1px"><span v-show="item.type > 0" class="icon" :class="classMap[item.type]"></span>{{item.name}}</span></li></ul></div><div class="foods-wrapper" ref="foodsWrapper"><ul><li v-for="item in goods" class="food-list" ref="foodList"><h1 class="title">{{item.name}}</h1><ul><li v-for="food in item.foods" class="food-item border-1px"><div class="icon"><img :src="food.icon" width="57" height="57"></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>

2、<style>标签里面的内容

在例一的css基础上,当当前的的索引等于计算出来的索引的时候,就给.menu-item加上.current样式,如下图所示


完整的css如下

<style lang="stylus">@import '../../common/stylus/mixin.styl'.goodsdisplay:flex    /*设置弹性布局*/position:absolute /*设定absolute+top+bottom那么该元素就是一个固定高度的容器了*/top:174px  /*这个是header+tab组件的高度*/width:100%overflow:hiddenbottom:46px /*这个是给底部的购物车留出来的高度*/.menu-wrapperflex:0 0 80px  /*设置左边的元素的宽度为固定值*/width:80pxbackground: #f3f5f7.menu-itemdisplay:tableheight:54pxwidth:56pxpadding:0 12pxline-height:14px&.current          /*当计算出来的索引等于当前索引,就给相应的menu-item加上.current*/position: relativemargin-top: -1pxz-index: 10background:#ffffont-weight:700.textborder-none().icondisplay: inline-blockvertical-align:topwidth:12pxheight:12pxmargin-right :2pxbackground-size:12px 12pxbackground-repeat :no-repeat&.decreasebg-image('decrease_3')&.discountbg-image('discount_3')&.guaranteebg-image('guarantee_3')&.invoicebg-image('invoice_3')&.specialbg-image('special_3').textdisplay:table-cellwidth:56pxfont-size:12pxvertical-align: middleborder-1px(rgba(7,17,27,0.1)).foods-wrapperflex:1    /*右边的元素的宽度是一个自适应的*/.titlepadding-left:14pxheight:26pxline-height:26pxborder-left: 2px solid #d9dde1font-size:12pxcolor:rgb(147,153,159)background:#f3f5f7.food-itemdisplay:flexmargin:18pxpadding-bottom:18pxborder-1px(rgba(7,17,27,0.1))&:last-childborder-none()margin-bottom:0.iconflex:0 0 57pxmargin-right:10px.contentflex:1.namemargin:2px 0 8px 0height:14pxline-height:14pxfont-size:14pxcolor:rgb(7,17,27).desc,.extraline-height:10pxfont-size:10pxcolor:rgb(147,153,159).descmargin-bottom:8pxline-height:12px.extra.countmargin-right:12px.pricefont-weight:700line-height:24px.nowmargin-right:8pxfont-size:14pxcolor:rgb(240,20,20).oldtext-decoration:line-throughfont-size:10pxcolor:rgb(147,153,159)
</style>

3、<script>标签里面的内容

1)左边点击menu实现相应的menu呈高亮的状态,并且右边跳到相应的food区,在menu-wrapper下面的li修改成

<li v-for="(item,index) in goods" class="menu-item" :class="{'current':currentIndex === index}" @click="selectMenu(index,$event)">

currentIndex()在computed里面定义,实现v-bind:class

computed:{//利用vue中的计算属性computed实时计算,对listHeight遍历,返回当前的左边mune-wrapper的li//对应的index,从而让其显示高亮的属性.currentcurrentIndex(){for( let i = 0;i<this.listHeight.length;i++ ){let height1 = this.listHeight[i];let height2 = this.listHeight[i+1];//当遍历到listHeight最后一个元素的时候,height2的值为undefined,如果是//最后一个元素的话!height2为真,后面就不需要判断了if( !height2 || (this.scrollY >= height1 && this.scrollY<height2)){return i;}}//默认情况下是返回第一个元素return 0;}}
}

selectMenu(index,$event)在methods里面定义,实现点击左边的menu,右边跳到相应的food区

        //点击左边的menu,跳到右边相应的liselectMenu(index,event){//浏览器的事件对象是没有_constructed属性,当是浏览器触发的时候就return//而用better-scroll自定义的事件触发的时候有这个属性,为true//用这个属性,就是避免在浏览器点击的时候,触发两次点击的效果if( !event._constructed ){return;}//点击左侧的菜单项的时候,右边跳到相应的内容区域let foodList = this.$refs.foodList; //获取到右边li对象let el = foodList[index];//根据index,获取到右边具体滚动到的lithis.foodsScroll.scrollToElement(el,300);//要滑动到右边的对象,300完成动作的时间}
2)右边food区滚动的时候,左边相应的menu区呈高亮的状态

首先,在data()里面定义两个变量:listHeight和scrollY

      data(){return {goods:[], //用来接收从后台返回的数据listHeight:[],  //存放右边每一个li的高度scrollY:0       //实时滚动的y轴大小,利用better-scroll的onScroll事件监听这个值}}
然后,在methods里面定义个函数_calculateHeight(),实现对右边的food的高度的累加
//将右侧的.foods-wrapper里面的每个li的高度进行累加,存放到数组listHeight里面_calculateHeight(){let foodList = this.$refs.foodList; //获取到所有的ref='foodList'的DOM元素let height = 0;this.listHeight.push(height); //第一个元素的高度是0for( let i =0;i<foodList.length;i++ ){let item = foodList[i];height += item.clientHeight;//通过原生DOM中的js获取到li的高度,并且累加this.listHeight.push(height);}}

接着,在_initScroll()函数中的对ref='foodsWrapper'的对象添加probeType属性

          this.foodsScroll = new BScroll(this.$refs.foodsWrapper,{click:true,probeType:3 //设置实时监听滚动的位置的效果的属性});
同时在_initScroll()函数里面,对this.foodsScroll对象设置滚动监听函数
          //监听右侧滚动区域,左边相应的menu高亮//监听滚动事件scroll,实时改变this.scrollY的值,// pos是元素所处的位置,内部自动传的this.foodsScroll.on('scroll',(pos) => {//scrollY是自定义的变量,用于存储滚动的位置//Math.round(pos.y)是一个负数if( pos.y <= 0 ){this.scrollY = Math.abs( Math.round(pos.y) );}});

然后利用scrollY的值和listHeight里面的 值作比较,实现右边food滚动区域与相应的menu对应,呈现高亮的状态

 computed:{//利用vue中的计算属性computed实时计算,对listHeight遍历,返回当前的左边mune-wrapper的li//对应的index,从而让其显示高亮的属性.currentcurrentIndex(){for( let i = 0;i<this.listHeight.length;i++ ){let height1 = this.listHeight[i];let height2 = this.listHeight[i+1];//当遍历到listHeight最后一个元素的时候,height2的值为undefined,如果是//最后一个元素的话!height2为真,后面就不需要判断了if( !height2 || (this.scrollY >= height1 && this.scrollY<height2)){return i;}}//默认情况下是返回第一个元素return 0;}}
}

完整的<script>代码如下

<script>import BScroll from 'better-scroll'; //引进这个实现上下滑动的插件const ERR_OK = 0;export default {props:{seller:{type:Object}},data(){return {goods:[], //用来接收从后台返回的数据listHeight:[],  //存放右边每一个li的高度scrollY:0       //实时滚动的y轴大小,利用better-scroll的onScroll事件监听这个值}},computed:{//利用vue中的计算属性computed实时计算,对listHeight遍历,返回当前的左边mune-wrapper的li//对应的index,从而让其显示高亮的属性.currentcurrentIndex(){for( let i = 0;i<this.listHeight.length;i++ ){let height1 = this.listHeight[i];let height2 = this.listHeight[i+1];//当遍历到listHeight最后一个元素的时候,height2的值为undefined,如果是//最后一个元素的话!height2为真,后面就不需要判断了if( !height2 || (this.scrollY >= height1 && this.scrollY<height2)){return i;}}//默认情况下是返回第一个元素return 0;}},created(){//在这个时刻向后台请求数据this.$http.get('/api/goods').then((res) => {res = res.body;if( res.errno === ERR_OK ){this.goods = res.data;this.$nextTick(() => {//实例化better-scrollthis._initScroll();//计算右边.foods-wrapper的每个li的累加的高度,存放在listHeight中this._calculateHeight();});}});//定义一个变量this.classMap = ['decrease','discount','special','invoice','guarantee'];},methods:{//点击左边的menu,跳到右边相应的liselectMenu(index,event){//浏览器的事件对象是没有_constructed属性,当是浏览器触发的时候就return//而用better-scroll自定义的事件触发的时候有这个属性,为true//用这个属性,就是避免在浏览器点击的时候,触发两次点击的效果if( !event._constructed ){return;}//点击左侧的菜单项的时候,右边跳到相应的内容区域let foodList = this.$refs.foodList; //获取到右边li对象let el = foodList[index];//根据index,获取到右边具体滚动到的lithis.foodsScroll.scrollToElement(el,300);//要滑动到右边的对象,300完成动作的时间},_initScroll(){//初始化需要滚动的对象this.menuScroll = new BScroll(this.$refs.menuWrapper,{click:true});this.foodsScroll = new BScroll(this.$refs.foodsWrapper,{click:true,probeType:3 //设置实时监听滚动的位置的效果的属性});//监听右侧滚动区域,左边相应的menu高亮//监听滚动事件scroll,实时改变this.scrollY的值,// pos是元素所处的位置,内部自动传的this.foodsScroll.on('scroll',(pos) => {//scrollY是自定义的变量,用于存储滚动的位置//Math.round(pos.y)是一个负数if( pos.y <= 0 ){this.scrollY = Math.abs( Math.round(pos.y) );}});},//将右侧的.foods-wrapper里面的每个li的高度进行累加,存放到数组listHeight里面_calculateHeight(){let foodList = this.$refs.foodList; //获取到所有的ref='foodList'的DOM元素let height = 0;this.listHeight.push(height); //第一个元素的高度是0for( let i =0;i<foodList.length;i++ ){let item = foodList[i];height += item.clientHeight;//通过原生DOM中的js获取到li的高度,并且累加this.listHeight.push(height);}}}}
</script>


















这篇关于(八)在vue中使用better-scroll,实现内容区域的滚动效果,以及右边与左边内容相对应,左边呈现高亮状态的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/809552

相关文章

Java中流式并行操作parallelStream的原理和使用方法

《Java中流式并行操作parallelStream的原理和使用方法》本文详细介绍了Java中的并行流(parallelStream)的原理、正确使用方法以及在实际业务中的应用案例,并指出在使用并行流... 目录Java中流式并行操作parallelStream0. 问题的产生1. 什么是parallelS

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

Linux join命令的使用及说明

《Linuxjoin命令的使用及说明》`join`命令用于在Linux中按字段将两个文件进行连接,类似于SQL的JOIN,它需要两个文件按用于匹配的字段排序,并且第一个文件的换行符必须是LF,`jo... 目录一. 基本语法二. 数据准备三. 指定文件的连接key四.-a输出指定文件的所有行五.-o指定输出

Linux jq命令的使用解读

《Linuxjq命令的使用解读》jq是一个强大的命令行工具,用于处理JSON数据,它可以用来查看、过滤、修改、格式化JSON数据,通过使用各种选项和过滤器,可以实现复杂的JSON处理任务... 目录一. 简介二. 选项2.1.2.2-c2.3-r2.4-R三. 字段提取3.1 普通字段3.2 数组字段四.

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

Linux kill正在执行的后台任务 kill进程组使用详解

《Linuxkill正在执行的后台任务kill进程组使用详解》文章介绍了两个脚本的功能和区别,以及执行这些脚本时遇到的进程管理问题,通过查看进程树、使用`kill`命令和`lsof`命令,分析了子... 目录零. 用到的命令一. 待执行的脚本二. 执行含子进程的脚本,并kill2.1 进程查看2.2 遇到的

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

详解SpringBoot+Ehcache使用示例

《详解SpringBoot+Ehcache使用示例》本文介绍了SpringBoot中配置Ehcache、自定义get/set方式,并实际使用缓存的过程,文中通过示例代码介绍的非常详细,对大家的学习或者... 目录摘要概念内存与磁盘持久化存储:配置灵活性:编码示例引入依赖:配置ehcache.XML文件:配置