项目中经常出现一个横向scroll-view套了一层列表,需要配套做到点击列表项时scrollview滚动到相应位置,因为这种情况比较多,所以封装了一个scrollview组件,主要原理是通过计算点击项的位置更新scrollleft的改变
<scroll-view
scroll-x
id="scrollContainer"
class="scroll-to-view"
:scroll-left="scrollLeft"
scroll-with-animation
@touchmove.stop.prevent="() => {}"
>
<view
class="scroll-to-view-item"
v-for="(item, inx) in list"
:key="inx"
:style="[value === inx ? activeStyle : customStyle]"
@click="checkItem(inx)"
>{{ item[field] }}</view
>
</scroll-view>
</template>
<script>
/**
* @property {Number} value 选中项的下标
* @property {Array} list 列表
* @property {String} field='name' 显示对应列表中字段
* @property {Object} customStyle 列表项样式
* @property {Object} activeStyle 项样式
*
* @event {Function(current)} change 改变标签触发
*/
export default {
props: {
list: {
type: Array,
default() {
return [];
},
},
value: {
type: Number,
default() {
return 0;
},
},
field: {
type: String,
default() {
return 'name';
},
},
customStyle: {
type: Object,
default() {
return {};
},
},
activeStyle: {
type: Object,
default() {
return {
fontSize: '28rpx',
color: '#000',
fontWeight: 'bold',
background: '#f1f1f1',
};
},
},
},
data() {
return {
containerWidth: 0,
scrollLeft: 0,
};
},
watch: {
value(val) {
this.$nextTick(() => {
this.scrollIntoView(val);
});
},
},
methods: {
checkItem(inx) {
this.$emit('check', inx);
},
scrollIntoView(val) {
const query = uni
.createSelectorQuery()
// #ifndef MP-ALIPAY
.in(this);
// #endif
// 获取容器的宽度
query
.select('#scrollContainer')
.boundingClientRect((data) => {
this.containerWidth = data.width;
})
.exec();
// 累加内部项长度和最后一项长度的一半,设置最后一项滚动到最中间
query
.selectAll('.scroll-to-view-item')
.boundingClientRect((data) => {
if (!data) {
return;
}
let lineLeft = 0;
let currentWidth = 0;
if (data) {
for (let i = 0; i < data.length; i++) {
if (i < val) {
lineLeft += data[i].width;
} else if (i == val) {
currentWidth = data[i].width;
} else {
break;
}
}
}
lineLeft = lineLeft + currentWidth / 2;
this.scrollLeft = lineLeft - this.containerWidth / 2;
})
.exec();
},
},
};
- 组件可以复用,可以用customStyle和activeStyle自定义组件样式
- uni.createSelectorQuery()在各端可以替换为my.createSelectorQuery或wx.createSelectorQuery
- 列表过长如果产生性能问题,可以使用event.target.left的方式避免query.selectAll和长度计算.