You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
87 lines
2.5 KiB
87 lines
2.5 KiB
<template> |
|
<!-- @scrolltolower触底事件,@scroll滚动事件 --> |
|
<scroll-view scroll-y="true" :style="{height: containerHeight+'px'}" @scroll="scrollTop = $event.detail.scrollTop" |
|
@scrolltolower="$emit('@scrolltolower')"> |
|
<!-- 监听滚动事件使用passive修饰符 --> |
|
<view :style="paddingStyle"> |
|
<!-- key使用index,可避免多次渲染该dom --> |
|
<view id="box" v-for="(item, index) in showList" :key="index"> |
|
<!-- 使用作用域插槽,将遍历后的数据item和index传递出去 --> |
|
<slot :item="item" :$index="index"></slot> |
|
</view> |
|
</view> |
|
</scroll-view> |
|
</template> |
|
|
|
<script> |
|
export default { |
|
name: "App", |
|
props: { |
|
// 所有数据 |
|
allList: { |
|
type: Array, |
|
default () { |
|
return [] |
|
} |
|
}, |
|
// 容器高度 |
|
containerHeight: { |
|
type: Number, |
|
default: 0 |
|
}, |
|
}, |
|
data() { |
|
return { |
|
oneHeight: 200, // 单个元素的高度,默认200.在mounted中会再次回去单个元素高度 |
|
scrollTop: 0 // 滚动距离 |
|
}; |
|
}, |
|
async mounted() { |
|
// 计算单个元素的高度 |
|
await this.$nextTick(() => { |
|
|
|
}) |
|
|
|
// uniapp中获取高度的兼容写法 |
|
const query = uni.createSelectorQuery(); |
|
console.log('query.select :>> ', query.select('#box').boundingClientRect); |
|
query.select('#box').boundingClientRect(data => { |
|
console.log('data :>> ', data); |
|
this.oneHeight = data.height |
|
}).exec(); |
|
}, |
|
computed: { |
|
// 一屏多少条数据 |
|
showNum() { |
|
return ~~(this.containerHeight / this.oneHeight) + 2; |
|
}, |
|
// 开始索引 |
|
startIndex() { |
|
// 可见区域,第一个元素的index |
|
const curIndex = ~~(this.scrollTop / this.oneHeight) |
|
// console.log(this.showNum, this.oneHeight) |
|
// 渲染区域第一个元素的index,这里缓冲区域的列表条数使用的是this.showNum |
|
return curIndex < this.showNum ? 0 : curIndex - this.showNum |
|
}, |
|
// 渲染元素最后的index |
|
endIndex() { |
|
// 可见区域,第一个index |
|
const curIndex = ~~(this.scrollTop / this.oneHeight) |
|
let end = curIndex + this.showNum * 3; // 2倍是需要预留缓冲区域 |
|
let len = this.allList.length |
|
return end >= len ? len : end; // 结束元素大于所有元素的长度时,就取元素长度 |
|
}, |
|
// 需要渲染的数据 |
|
showList() { |
|
return this.allList.slice(this.startIndex, this.endIndex) |
|
}, |
|
// 空白占位的高度 |
|
paddingStyle() { |
|
return { |
|
paddingTop: this.startIndex * this.oneHeight + 'px', |
|
paddingBottom: (this.allList.length - this.endIndex) * this.oneHeight + 'px' |
|
} |
|
} |
|
}, |
|
}; |
|
</script> |