业务场景
如下图,蓝色框住view的是可滚动的容器,红色框住的view是容器中的一个子元素,我们需要将容器中的子元素滚动到容器中间,并且每个子元素高度是不定的。
实现思路
在微信小程序中要控制scroll-view组件 的滚动位置有两种方法:设置scrollTop/scrollLeft 或 使用 scroll-into-view 属性,scroll-into-view属性只能滚动到容器最前面,不能滚动到中间,所以要将元素滚动到容器中间只能使用scrollTop/scrollLeft,下面以纵向滚动讲解下scrollTop的计算方法,计算思路如下图:
容器滚动itemCenter - containerCenter后,item会处于容器的中心,所以scrollTop = itemCenter - containerCenter
代码实现
子元素高度固定
- 获取容器的高度
const query = this.createSelectorQuery()
query
.select(`#container`) // 容器id
.boundingClientRect((rect) => {
this.setData({
containerHeight: rect.height,
})
})
.exec()
- 根据子元素高度和子元素Index计算要滚动到容器中间的scrollTop值
/**
* 设置容器scrollTop使得子元素居中
* @param itemHeight - 子元素高度
* @param itemIndex - 子元素Index
*/
setScrollTop(itemHeight, itemIndex) {
const containerHeight = this.data.containerHeight
const itemCenter = itemHeight * itemIndex + itemHeight / 2 // 子元素中心
const containerCenter = containerHeight / 2
const scrollTop = itemCenter - containerCenter
this.setData({ scrollTop })
},
子元素高度不固定
- 获取容器的信息
const query = this.createSelectorQuery()
query
.select(`#menuContainer`)
.boundingClientRect((rect) => {
this.setData({
containerInfo: {
top: rect.top,
height: rect.height,
center: rect.top + rect.height / 2,
},
})
})
.exec()
- 计算scrollTop,由于子元素高度不固定,改用boundingClientRect来获取子元素位置
/**
* 设置容器scrollTop使得子元素居中
* @param itemId - 子元素id
*/
setScrollTop(itemId) {
this.createSelectorQuery()
.select(`#${itemId}`)
.boundingClientRect((rect) => {
if (this.data.containerInfo) {
const containerCenter = this.data.containerInfo.center
const itemCenter = rect.bottom - rect.height / 2
this.setData({
scrollTop: itemCenter - containerCenter,
})
}
})
.exec()
},
注意, 为了确保scroll-view组件可以正常滚动,scroll-view最好设置一个高度