一、vant组件List(完整)
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
<van-list
v-model="loading"
:finished="finished"
finished-text="没有更多了"
:error.sync="error"
error-text="请求失败,点击重新加载"
@load="onLoad"
>
// 列表项 <div class="batchItem" v-for="item in batchList" :key="item.pcbzid"></div>
</van-list>
</van-pull-refresh>
refreshing: false,
loading: false,
error: false,
finished: false,
async onLoad() {
if (this.refreshing) {
this.batchList = [];
this.pageNum = 1;
this.refreshing = false;
}
try {
await this.getBatchList();
this.loading = false;
console.log(this.batchList.length, this.total);
// 数据全部加载完成
if (this.batchList.length >= this.total) {
this.finished = true;
}
} catch (err) {
this.error = true;
} finally {
this.loading = false;
}
},
onRefresh() {
// 清空列表数据
this.finished = false;
// 重新加载数据
// 将 loading 设置为 true,表示处于加载状态
this.loading = true;
this.onLoad();
},
上拉加载事件:
- List 初始化后会触发一次 load 事件,加载第一屏数据,该特性可以通过immediate-check属性关闭。
- 当loading为true时,不会触发load事件;load事件自动将loading改为true;故load事件结束后,要手动改loading为false;当loading为false时,会检测触底距离,调用load事件。
- finished为true后,将不会触发load事件。
错误提示事件:
- 当load事件加载失败后,手动改error为true,并将loading改为false。
下拉刷新事件:
- 意味着清空当前列表,还原初始化参数,加载第一屏数据 。
- 当下拉超过一定距离,自动改refresh为true,调用refresh事件,结束后,手动改refresh为false。
二、自定义分页器(简易上拉加载)
概念理解:
- 页面滚动距离/网页顶部被卷去高度(+) scrollTop document.documentElement.scrollTop || document.body.scrollTop
- 可视窗口高度 windowHeight document.documentElement.clientHeight || document.body.clientHeight
- 滚动条总高度 scrollHeight document.documentElement.scrollHeight || document.body.scrollHeight
- 列表距离可视窗口顶部 listOffset this.$refs.vanlist.getBoundingClientRect().top
- 列表高度 listHeight this.$refs.vanlist.clientHeight
在加载第一屏数据后滚动,只有scrollTop、listOffset会变
当 scrollTop + windowHeight = scrollHeight 时,说明当前滚动条已经到达底部
<div class="title">我是筛选条件区域</div>
<div ref="vanlist">
<p v-for="item in list" :key="item">{{ item }}</p>
</div>
page: 1,//加载页数
list: 10,
isRefreshUnLock: true,//防止多次触底,频繁加载
mounted() {
window.addEventListener("scroll", this.handleScroll);
},
destroyed() {
window.removeEventListener("scroll", this.handleScroll);
},
methods: {
handleScroll() {
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
let windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
let scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
let listOffset = this.$refs.vanlist.getBoundingClientRect().top;
let listHeight = this.$refs.vanlist.clientHeight;
// console.log("scrollTop", scrollTop);
// console.log("windowHeight", windowHeight);
// console.log("scrollHeight", scrollHeight);
// console.log("距离顶端的距离", listOffset); //顶端是可视窗口顶端
// console.log("list高度", listHeight);
//滚动条距离底部小于等于50,且当前不在加载状态时 =》 加载更多数据
if (scrollTop + windowHeight >= scrollHeight - 50 && this.isRefreshLock) {
this.isRefreshUnLock = false;
setTimeout(() => {
this.list += 10;
this.isRefreshUnLock = true;
this.page++;
}, 3000);
}
}
}
补充:自定义的话,除了监听scroll事件,还可以使用IntersectionObserve这个API实现
参考: 移动端滚动分页解决方案 - 掘金
三、模仿京东商品列表页的已浏览数与返回顶部(van-list)
当第一屏数据完全滚出画面后,页面右下角出现提示:
当页面处于滚动状态,提示已浏览数/总数;当页面处于静止状态,提示返回顶部的标识。
1. 页面结构:
<!-- 搜索框在滚动时会吸附在顶部 navHeight -->
<van-sticky> <div ref="navHeight"></div> </van-sticky>
<!-- 可滚动区域 moveContent:条件查询 condition + 列表 vanlist -->
<div ref="moveContent">
<div ref="condition"></div>
<van-pull-refresh> <van-list> </van-list> </van-pull-refresh>
</div>
<!-- 右下角提示内容 -->
<div class="fixPart" v-show="isScroll">
<div v-show="isPage"> <span>{{ num }}</span ><span>/{{ total }} </span> </div>
<div v-show="!isPage" @click="backTop"><van-icon name="back-top"/></div>
</div>
2. 要先实现监听滚动,并检测滚动停止:
滚动事件中记录当前滚动开始位置SA,开启延时器,延时事件中记录当下滚动结束位置SB,比较SA与SB,判断是否处于滚动状态。
watchScrollTimer: null, //监听滚动定时器
scrollT: 0, //滚动开始位置,
stopscroll: 0, //滚动结束位置
isPage: true, //显示浏览数 / 返回顶部
isScroll: false, //显示右下角提示
methods: {
handleScroll() {
clearTimeout(this.watchScrollTimer); //清除监听滚动定時器
this.watchScrollTimer = setTimeout(this.scrollEnd, 500);
this.scrollT = document.documentElement.scrollTop || document.body.scrollTop;
this.isPage = true;
// .......
},
scrollEnd() {
this.stopscroll = document.documentElement.scrollTop || document.body.scrollTop;
// 判断当前处于静止或滚动状态
if (this.stopscroll == this.scrollT) {
console.log("滚动已结束");
this.isPage = false;
}
},
}
mounted() {
window.addEventListener("scroll", this.handleScroll);
},
destroyed() {
window.removeEventListener("scroll", this.handleScroll);
clearInterval(this.watchScrollTimer); // 清除定时器
this.watchScrollTimer = null;
},
3. 判断浏览个数:
num: 0, //已浏览个数
total: 0, //商品总数
handleScroll() {
// ......
let windowHeight = document.documentElement.clientHeight || document.body.clientHeight;
let navHeight = this.$refs.navHeight.clientHeight;
let moveOffset = this.$refs.moveContent.getBoundingClientRect().top; //要滚动内容距顶端距离
let moveHeight = this.$refs.moveContent.clientHeight; //要滚动内容的高度
let conditionHeght = this.$refs.condition.clientHeight; //查询条件的高度
let listOffset = moveOffset + conditionHeght;
let listHeight = moveHeight - conditionHeght;
// 总结:牵扯这么多距离,就是为了得到列表List自身的高度,与窗口顶端的距离
// 判断浏览数
if (listOffset >= navHeight) {
// 只要列表距离顶部的距离大于吸附元素的高度 =》 页面上列表没有被吸附元素遮挡 =》 浏览数认定1
this.num = 1;
} else {
// 只要遮挡了,开始计算当前被遮挡的是第几位,即浏览数为几
let single = listHeight / this.list.length; // 100为css样式设定的
this.num = -Math.ceil((listOffset - navHeight) / single) + 1;
}
// 意图第一屏数据滚出窗口 即 滚动距离等于窗口高度的时候,显示右下角提示;但这里判断太粗糙,不精确
// 其实想要出现提示的时机很随意,可以自己把握
if (listOffset < -windowHeight) {
this.isScroll = true;
} else {
this.isScroll = false;
}
},
4. 返回顶部 :
backTop() {
document.documentElement.scrollTop = 0;
document.body.scrollTop = 0;
},