配置参数
const scrollProps = {
threshold: { default: 0, type: Number },
hasMore: { default: false, type: Boolean },
loadMoreFn: { default: () => { }, type: Function },
el: { default: null, type: String },
}
参数说明:
threshold:到达底部多少距离的时候开始请求数据,
hasMore:是否还需要请求
loadMoreFn: 发起请求的函数
el: 限制在el元素内部滚动,如果不传el,则默认浏览器滚动条
核心滚动
判断是否有传入el,如果有的话就将scroll绑定到el的滚动事件,如果没有则直接绑定到window的滚动事件
if (props.el) {
nextTick(() => {
const el = document.querySelector(props.el)
if (el) { el.addEventListener("scroll", (e) => { scroll() }) }
})
} else {
window.onscroll = scroll
}
scroll函数,支持异步,
async function scroll(e) {
let el = document.body
if (props.el) {
el = document.querySelector(props.el)
}
const threshold = props.threshold || 10;
let scrollTop = props.el ? el.scrollTop : (el.scrollTop || document.documentElement.scrollTop || window.pageXOffset);
const docHeight = el.scrollHeight - (props.el ? el.offsetHeight : window.innerHeight)
if ((docHeight <= (scrollTop + threshold)) && props.hasMore) {
// 防止滚动过程中重复触发请求
if (!doing) {
doing = 'loading'
const d = await props.loadMoreFn()
setTimeout(() => {
doing = d;
}, 100);
}
}
}
代码中使用:
<!--document滚动-->
<div v-for="item in List" :key="item" style="padding:2rem .2rem;border-bottom:1px solid #ccc">{{item}}</div>
<infinite-scroll :loadMoreFn="loadMoreFn" :hasMore="hasMore" />
<!---容器中滚动--->
<div id="box" style="height:5rem;overflow-y:auto">
<div v-for="item in List" :key="item" style="padding:20px 10px;border-bottom:1px solid #ccc">{{item}}</div>
<infinite-scroll el="#box" :loadMoreFn="loadMoreFn" :hasMore="hasMore" />
</div>
<script>
async function loadMoreFn() {
console.log('loadMore');
const ret = await GetApi(state.PageIndex)
state.hasMore = ret.length > 0;
state.List = [...state.List, ...ret]
state.PageIndex = state.PageIndex + 1
}
</script>
效果图如下: