最近在研究vuejs上拉加载更多实现方案,上网找了下这方面的文章和代码貌似不是太多,而且逻辑实现并不太清晰,于是自己结合了前人的经验自己整合了下总结下经验.
上拉加载更多实现思路最关键的就是如何识别手指滑动操作,如果不是用vuejs,可以用html的onscroll函数来监听滑动的位置来实现,如果是基于vuejs,直接在标签里用onscroll事件是没用,这个具体没有研究清楚.下面就讲讲vuejs的方案,先贴出代码:
//scroll.vue
<template lang="html">
<div class="yo-scroll" @touchstart="touchStart($event)"
@touchmove="touchMove($event)" @touchend="touchEnd($event)" >
<section class="inner">
<!-- 使用时外面的标签会填在里面 -->
<slot>
</slot>
<!-- 保持加载更多条在最下面 -->
<footer class="load-more">
<slot name="load-more">
<span>{{loadMoreText}}</span>
</slot>
</footer>
<div class="nullData" v-show="dataList.noFlag">暂无更多数据</div>
</section>
</div>
</template>
<style lang="less">
/*:class="{'down':(state===0),'up':(state==1),refresh:(state===2),touch:touching}"*/
.yo-scroll {
font-size: 24px;
position: absolute; //关键
top: 0;
right: 0;
bottom: 0;
left: 0;
overflow: auto; //关键
z-index: 100;
height: auto;
-webkit-overflow-scrolling: touch;
.inner { position: absolute;
/*top: -5rem;*/
width: 100%;
height: auto;
transition-duration: 300ms;
.load-more { height: 5rem;
line-height: 5rem;
display: flex;
text-align: center;
align-items: center;
justify-content: center;
display: none;
}
.nullData {//暂无更多数据样式
font-size: 26px;
color: #999999;
height: 100px;
line-height: 100px;
text-align: center;
}
.down-tip,
.refresh-tip,
.up-tip {
display: none;
}
}
}
.yo-scroll.touch .inner {
transition-duration: 0;
}
.yo-scroll.down .down-tip {
display: block;
}
.yo-scroll.up .up-tip {
display: block;
}
.yo-scroll.refresh .refresh-tip {
display: block;
}
</style>
<script>
export default {
props: {
offset: {
type: Number,
default: 100 //默认高度
},
enableLoadMore: {
type: Boolean,
default: true
},
dataList: {
default: false,
required: false
},
onLoadMore: {
type: Function,
default: undefined,
require: false
}
},
data() {
return {
startX: 0,
startY: 0,
touching: false,
isLoading: false,
loadMoreText: "上拉加载更多"
}
},
methods: {
touchStart(e) {
this.startY = e.targetTouches[0].pageY;
this.startX = e.targetTouches[0].pageX;
this.startScroll = this.$el.scrollTop || 0;
this.touching = true; //留着有用,不能删除
this.dataList.noFlag = false;
},
//滑动中
touchMove(e) {
if(!this.enableLoadMore || this.dataList.noFlag || !this.touching) {
return
}
let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
if(diff > 0) {
e.preventDefault()
}
this.loadMoreText = '上拉加载更多'
this.$el.querySelector('.load-more').style.display = 'block';
},
touchEnd(e) {
if (this.isLoading) {
return;
}
this.touching = false
//用于判断滑动是否在原地 ----begin
let endX = e.changedTouches[0].pageX,
endY = e.changedTouches[0].pageY,
dy = this.startY - endY,
dx = endX - this.startX;
//如果滑动距离太短
if(Math.abs(dx) < 2 && Math.abs(dy) < 2) {
// console.log("滑动距离太短")
let more = this.$el.querySelector('.load-more')
more.style.display = 'none'; //隐藏加载条
return;
}
if(!this.enableLoadMore || this.isLoading) {
let more = this.$el.querySelector('.load-more')
more.style.display = 'none'; //隐藏加载条
return
}
let outerHeight = this.$el.clientHeight,
innerHeight = this.$el.querySelector('.inner').clientHeight,
scrollTop = this.$el.scrollTop,
bottom = innerHeight - outerHeight - scrollTop;
if(bottom <= this.offset) {
//内容太少
this.doLoadMore();
} else {
let more = this.$el.querySelector('.load-more')
more.style.display = 'none'; //隐藏加载条
}
},
doLoadMore() {
this.isLoading = true
this.loadMoreText = '正在加载'
this.onLoadMore(this.loadDone);
},
loadDone() {
this.isLoading = false
let more = this.$el.querySelector('.load-more')
more.style.display = 'none'; //隐藏加载条
}
}
}
</script>
这里是使用组件的方式实现, @touchstart=”touchStart(
event)"@touchmove="touchMove(
e
v
e
n
t
)
"
@
t
o
u
c
h
m
o
v
e
="
t
o
u
c
h
M
o
v
e
(
event)” @touchend=”touchEnd($event) 为布局加上滚动事件,具体实现在script里,touchStart先记录手指按下坐标,touchmove记录手指滑动的距离,判断是否显示更多条,touchEnd判断是否触发加载更多事件,一但达到条件就调用外面传进来的onLoadMore函数,通过外面的调用done来控制是否完成.实现的效果是上拉时显示”下拉加载更多”,手指释放时显示”正在加载”,完成后隐藏控制条.
外面使用的组件代码 :
<template>
<div>
<v-scroll :onLoadMore="onLoadMore" :dataList="scrollData">
<ul>
<li v-for="(item) in listdata" :key="item.name">{{item.name}}</li>
<li v-for="(item) in downdata" :key="item.name">{{item.name}}</li>
</ul>
</v-scroll>
</div>
</template>
<style lang="less">
ul li {
min-height: 100px;
line-height: 100px;
text-align: center;
border: 1px solid red;
}
</style>
<script>
import loadmore from "./scroll.vue";
export default {
components: {
'v-scroll': loadmore
},
data() {
return {
counter: 1, //当前页
num: 10, // 一页显示多少条
pageStart: 0, // 开始页数
pageEnd: 0, // 结束页数
listdata: [], // 下拉更新数据存放数组
downdata: [], // 上拉更多的数据存放数组
scrollData:{
noFlag: false //暂无更多数据显示
}
}
},
mounted: function() {
this.getList();
},
methods: {
getList() {
var response = []
for(let i = 0; i < 60; i++) {
response.push({
name: i
})
}
this.listdata = response.slice(0, this.num);
},
onLoadMore(done) {
this.counter++;
let end = this.pageEnd = this.num * this.counter;
let i = this.pageStart = this.pageEnd - this.num;
setTimeout(() => {
for(i; i < end; i++) {
if(i >= 30) {
//走完数据调用方法
// this.scrollData.noFlag = true;
break;
} else {
this.downdata.push({
name: i + "==="
})
// more.style.display = 'none'; //隐藏加载条
}
}
done();
}, 2000);
}
}
}
</script>
实现的完整代码在github上可以找到:https://github.com/Cmdmac/vuejs-loadmore.git