懒癌发作……
本篇有关于列表滚动的内容,有点复杂,好好分析
0. 其它
vue实战(1):准备与资料整理
vue实战(2):初始化项目、搭建底部导航路由
vue实战(3):底部导航显示、搭建各模块静态页面、添加登录页页面与路由
vue实战(4):postman测试数据、封装ajax、使用vuex管理状态
vue实战(5):总结一
vue实战(6):异步显示数据、开发Star组件
vue实战(7):完整开发登录页面(一)
vue实战(8):完整开发登录页面(二)
vue实战(9):总结二
vue实战(10):开发店铺详情(一)
vue实战(11):开发店铺详情(二)
1. 分析与引入相关库
- 静态页面效果
- 需要实现的效果
ID | 效果 |
---|---|
1 | 左右两边列表可以滑动,有回弹效果 |
2 | 当滑动右侧列表时,更新当前分类(即对应左侧列表类型) |
3 | 点击左侧某个分类时,右侧列表滑动到对应类型位置 |
-
类名:
current
标识当前分类(用于颜色变换等) -
计算属性:
currentIndex
————scrollY
: 右侧滑动的Y轴坐标
————tops
: 所有右侧分类li
的top
组成的数组 -
代码实现
ID | 需实现内容 |
---|---|
1 | 在滑动过程中,实时收集 scrollY |
2 | 列表第一次加载显示后,收集 tops |
3 | 实现currentIndex 计算逻辑 |
- 关于滑动
ID | 滑动情况(移动端) |
---|---|
1 | 手指一直滑动,手指不脱离屏幕 |
2 | 惯性滑动,手指滑动后列表惯性滑动 |
3 | 编码滑动,如点击事件,点击类型滑动到相关位置 |
-
BetterScroll
这边的滑动就借助 BetterScroll ,挺好用的
链接:betterscroll官网
链接:better-scroll 作者文章《当 better-scroll 遇见 Vue》
链接:better-scroll 社区地址 -
安装 BetterScroll
根据官网,进行安装与引用
npm install better-scroll --save
在需要的页面引用:import BScroll from 'better-scroll'
2. 获取并计算相关数据
- 引入组件
引用 BetterScroll 滑动组件与前面引用 Swiper 轮播组件的方式如出一辙,需要进行数据监测,获取的数据加载完成后再加载组件
methods: {
...mapActions('msite', ['getShopGoods']),
// 使用组件
_scrollY () {
// 左侧类型列表
new BScroll('.menu-wrapper', {
})
// 右侧食物列表
new BScroll('.foods-wrapper', {
})
}
},
computed: {
...mapState('msite', ['goods']),
// 计算
currentIndex () {
}
},
watch: { // 监测
goods (value) {
this.$nextTick(() => { // 数据加载完后执行
this._scrollY()
})
}
}
- 定义收集右侧列表滑动的Y轴坐标
scrollY
的方法
—— 看官网文档,需要使用on
方法去进行绑定事件
—— 为on
方法绑定scroll
事件
- 滑动的方式
有三种方式,可以都试一下,看看效果,然后选择适用的
- 分析选择
根据打印效果选择,选择第二种方式最合适
methods: {
...mapActions('msite', ['getShopGoods']),
// 使用组件
_scrollY () {
// 左侧类型列表
new BScroll('.menu-wrapper', {
})
// 右侧食物列表
const foodscroll = new BScroll('.foods-wrapper', {
probeType: 2 // 惯性滑动不会触发
})
// 操作食物列表
foodscroll.on('scroll', ({ x, y }) => {
console.log('横坐标:' + x, '纵坐标:' + y)
this.scrollY = Math.abs(y) // y轴的值转换为绝对值
})
}
},
computed: {
...mapState('msite', ['goods']),
// 计算
currentIndex () {
}
},
watch: { // 监测
goods (value) {
this.$nextTick(() => { // 数据加载完后执行
this._scrollY()
})
}
}
方式1 | 效果1 | 效果2 |
---|---|---|
probeType: 1 |
在滑动时有输出,但数据不是实时输出 | 惯性滑动时不输出 |
方式2 | 效果1 | 效果2 |
---|---|---|
probeType: 2 |
在缓慢滑动时有输出,数据实时输出 | 惯性滑动时不输出 |
方式3 | 效果1 | 效果2 |
---|---|---|
probeType: 3 |
轻微滑动,数据输出迅速,数据实时输出 | 惯性滑动时同样输出 |
3. 收集 tops
收集右侧列表滑动的Y轴坐标,选择第二种滑动方式
- 初始化时收集
tops
// 收集tops
_initTops () {
// 初始化,定义最上头的位置为0
const toplis = []
let top = 0
toplis.push(top)
// 收集
// $refs 用于操作dom , foodsUl 为 ref='foodsUl' 设置在 ul 节点上,children 为取其下的 li
const lis = this.$refs.foodsUl.children
Array.prototype.slice.call(lis).forEach(li => {
top += li.clientHeight
toplis.push(top)
})
// 更新数据
this.tops = toplis
console.log(toplis)
}
4. 计算当前分类的下标
// 计算当前分类的下标
currentIndex () {
// 条件
const { scrollY, tops } = this
// 计算,取区间返回上一个值
const index = tops.findIndex((top, index) => {
console.log(top, index)
// 返回结果: scrollY >= 当前top && scrollY < 下一个top
return scrollY >= top && scrollY < tops[index + 1]
})
return index
}
-
解决惯性滑动的 bug
惯性滑动的时候左侧分类不随着更新
解决办法:查看 BetterScroll 官网,添加滑动结束的监听
// 监听滑动结束
foodscroll.on('scrollEnd', ({ x, y }) => {
// console.log('横坐标:' + x, '纵坐标:' + y)
this.scrollY = Math.abs(y) // 转换为绝对值
})
5. 点击左侧分类滑动
-
添加点击事件
<li class="menu-item " v-for="(good, index) in goods" :key="index" :class="{current:index === currentIndex}" @click="clickMenuItem(index)">
-
查看 BetterScroll 官网,找到相关方法
scrollTo
-
方法
// 左侧分类列表点击事件
clickMenuItem (index) {
console.log(index)
// 得到目标位置的scrollY
const scrollY = this.tops[ index ]
// 立即更新scrollY(让点击的分类项成为当前分类)
this.scrollY = scrollY
// 平滑滑动右侧列表
this.foodscroll.scrollTo(0, -scrollY, 400)
}
6. 结束
这个滑动的功能看起来不难,但是分析起来感觉还是有些道道的;
前段时间有点生病,电脑又坏了,最坑爹的是刚过保修期维修花了500,真是花钱容易赚钱难,加之最近很浮躁,导致根本无心学习;
拖到现在,这个星期这个项目必结束。