Vue 中使用better-scroll实现左右联动的效果
效果图
1. 说明
- 在使用
better-scroll
的时候需要先在全局注册一个实例化的对象this.leftScroll 和 this.rightScroll
,方便在之后的代码中使用 - 在销毁页面的时候要清除掉实例化的对象,避免造成性能的溢出
beforeDestroy() { this.left_Scroll.destroy() this.right_Scroll.destroy() }
- 使用的
better-scroll
的方法和属性
3.1 click,用来开启点击事件
3.2 probeType,用来获得滚动的位置
3.3 scrollTo(x, y, time, easing)方法,滚动到指定的位置
3.4 scrollToElement(el, time, offsetX, offsetY, easing),滚动到指定的目标元素
3.5 scroll事件 滚动过程中,具体时机取决于选项中的 probeType
3.6 事件的绑定通过on
this.rightScroll.on('scroll',() => {})
- 实现左边滚动的方法主要是使用了
scrollToElement(el, time, offsetX, offsetY, easing)
- 右边的联动效果需要考虑到最后一个元素的位置情况
2. 代码
html
代码<!-- 2.分类内容 --> <div class="classify_content"> <!-- 左边的分类tab --> <div class="left_warp" ref="left_warp"> <div class="left_warp_content" ref="left_warp_content"> <div :class="[index == isActive? 'isActive': '', 'left_item']" v-for="(item,index) in 20" :key="index" @click="leftItemClick(index)" >数码{{index}}</div> </div> </div> <!-- 右边的内容 --> <div class="right_warp" ref="right_warp"> <div class="right_warp_content" :style="right_warpPB" ref="right_warp_content"> <div v-for="(item,index) in 20" :key="index" class="right_item"> <div class="title">数码{{index}}</div> <div class="content">{{index}}</div> </div> </div> </div> </div>
- 初始化
better-scroll
import BScroll from 'better-scroll' export default{ mounted() { this.$nextTick(() => { this.init() }) }, data() { return { isActive: 0, // 当前的索引 scrollY: 0, // 右边内容的滚动的高度 rightItemArray: [], // 右边item的高度 right_warpPaddingB: 0 // 设置右边内容的padding-bottom } }, methods: { // 初始化 init() { this._init_left() this._init_right() }, // 初始化左边的 better-scroll _init_left() { let left_wrapper = this.$refs.left_warp // 初始化左边的 better-scroll this.left_Scroll = new BScroll(left_wrapper, { click: true }) }, _init_right(){ let right_warp = this.$refs.right_warp // 初始化右边的 better-scroll this.right_Scroll = new BScroll(right_warp, { click: true, probeType: 3 }) } } }
- 左边点击效果,传递的
index
就是当前点击的那个元素,使用scrollToElement
方法就可以跳转到指定的位置// 左边的点击事件 leftItemClick(index) { if (this.isActive === index) return this.isActive = index this.left_warp_item(index) // 这个方法是在点击左边的时候,右边的内容联动 this.right_Scroll.scrollTo(0,-this.rightItemArray[index],200) }, // 点击的时候左边 滚动 left_warp_item(index) { const getItemElement = this.$refs.left_warp_content.children[index] this.left_Scroll.scrollToElement(getItemElement, 300, 0, true, 'easing') }
- 右边的联动效果,
4.1 在初始化的时候就需要获取到每个item
所在位置的高度
4.2 并且绑定scroll
事件用来监听滚动到的位置
4.3 然后在scroll
事件中触发左边的滚动事件this.left_warp_item(getIndex)
_init_right() { let right_warp = this.$refs.right_warp // 初始化右边的 better-scroll this.right_Scroll = new BScroll(right_warp, { click: true, probeType: 3 }) // 获取右边所有item的高度 let listArray = [] let top = 0 listArray.push(0) // 获取右边所有的 right_item 数组 const itemsEL = this.$refs.right_warp_content.children itemsEL.forEach(item => { top += item.offsetHeight listArray.push(top) }) this.rightItemArray = listArray // 右边内容的滑动事件 this.right_Scroll.on('scroll', pos => { this.scrollY = Math.abs(pos.y) let getIndex = this.rightItemArray.findIndex((item, index) => { return this.scrollY >= item && this.rightItemArray[index + 1] > this.scrollY }) this.isActive = getIndex this.left_warp_item(getIndex) }) }
- 这里在使用的时候考虑的是,如果最后一个的高度比屏幕的高度小的时候,需要给
item
的父容器设置padding-bottom
来撑大item
的父容器,因此,在初始化右边容器的时候,就需要看是否需要添加padding-bottom
// 初始化右边的 better-scroll 并且绑定事件 _init_right() { let right_warp = this.$refs.right_warp // 初始化右边的 better-scroll this.right_Scroll = new BScroll(right_warp, { click: true, probeType: 3 }) // 获取右边所有item的高度 let listArray = [] let top = 0 listArray.push(0) // 获取右边所有的 right_item 数组 const itemsEL = this.$refs.right_warp_content.children itemsEL.forEach(item => { top += item.offsetHeight listArray.push(top) }) this.rightItemArray = listArray // 计算右边内容需要添加的 padding-bottom this.cala_right_warpPaddingB() // 右边内容的滑动事件 this.right_Scroll.on('scroll', pos => { this.scrollY = Math.abs(pos.y) let getIndex = this.rightItemArray.findIndex((item, index) => { return this.scrollY >= item && this.rightItemArray[index + 1] > this.scrollY }) this.isActive = getIndex this.left_warp_item(getIndex) }) }, // 计算右边内容需要添加的 padding-bottom cala_right_warpPaddingB() { // 获取 右边最外面盒子的高度 const right_warpH = this.$refs.right_warp.clientHeight // 获取最后一个元素的高度 const itemsELH = this.$refs.right_warp_content.lastElementChild.clientHeight // 说明最后一个盒子的高度没有屏幕高 需要设置 padding-bottom if(right_warpH > itemsELH) { this.right_warpPaddingB = right_warpH - itemsELH } }
- 动态设置
style
computed: { right_warpPB() { return `padding-bottom: ${this.right_warpPaddingB}px` } }
3. 完整JS
代码
<script>
import BScroll from 'better-scroll'
export default {
computed: {
right_warpPB() {
return `padding-bottom: ${this.right_warpPaddingB}px`
}
},
data() {
return {
isActive: 0, // 当前的索引
scrollY: 0, // 右边内容的滚动的高度
rightItemArray: [], // 右边每个item的高度
right_warpPaddingB: 0 // 设置右边内容的padding-bottom
}
},
mounted() {
this.$nextTick(() => {
this.init()
})
},
methods: {
// 初始化
init() {
this._init_left()
this._init_right()
},
// ------------------------------左边的 scroll 滚动 和 事件
// 初始化左边的 better-scroll
_init_left() {
let left_wrapper = this.$refs.left_warp
// 初始化左边的 better-scroll
this.left_Scroll = new BScroll(left_wrapper, {
click: true
})
},
// 左边的点击事件
leftItemClick(index) {
if (this.isActive === index) return
this.isActive = index
this.left_warp_item(index)
this.right_Scroll.scrollTo(0, -this.rightItemArray[index],200)
},
// 点击的时候左边 滚动
left_warp_item(index) {
const getItemElement = this.$refs.left_warp_content.children[index]
this.left_Scroll.scrollToElement(getItemElement, 300, 0, true, 'easing')
},
// ------------------------------右边的 scroll 滚动 和 事件
// 初始化右边的 better-scroll 并且绑定事件
_init_right() {
let right_warp = this.$refs.right_warp
// 初始化右边的 better-scroll
this.right_Scroll = new BScroll(right_warp, {
click: true,
probeType: 3
})
// 获取右边所有item的高度
let listArray = []
let top = 0
listArray.push(0)
// 获取右边所有的 right_item 数组
const itemsEL = this.$refs.right_warp_content.children
itemsEL.forEach(item => {
top += item.offsetHeight
listArray.push(top)
})
this.rightItemArray = listArray
// 计算右边内容需要添加的 padding-bottom
this.cala_right_warpPaddingB()
// 右边内容的滑动事件
this.right_Scroll.on('scroll', pos => {
this.scrollY = Math.abs(pos.y)
let getIndex = this.rightItemArray.findIndex((item, index) => {
return this.scrollY >= item && this.rightItemArray[index + 1] > this.scrollY
})
this.isActive = getIndex
this.left_warp_item(getIndex)
})
},
// 计算右边内容需要添加的 padding-bottom
cala_right_warpPaddingB() {
// 获取 右边最外面盒子的高度
const right_warpH = this.$refs.right_warp.clientHeight
// 获取最后一个元素的高度
const itemsELH = this.$refs.right_warp_content.lastElementChild.clientHeight
// 说明最后一个盒子的高度没有屏幕高 需要设置 padding-bottom
if(right_warpH > itemsELH) {
this.right_warpPaddingB = right_warpH - itemsELH
}
}
},
beforeDestroy() {
this.left_Scroll.destroy()
this.right_Scroll.destroy()
}
}