vue-infinite-scroll
安装
npm install vue-infinite-scroll --save
尽管官方也推荐了几种载入方式,但“最vue”的方式肯定是在main.js中加入
import infiniteScroll from 'vue-infinite-scroll'
Vue.use(infiniteScroll)
实现范例
官方给的代码范例是假设你在根组件写代码,实际上我们肯定是在子组件里写代码,所以代码也需要略作修改,下方只列有用的代码片段:
<div v-infinite-scroll="loadMore" infinite-scroll-disabled="busy" infinite-scroll-distance="10">
<div v-for="item in data" :key="item.index">{{item.name}}</div>
</div>
data () {
return {
count: 0,
data: [],
busy: false
}
}
methods: {
loadMore: function() {
this.busy = true
setTimeout(() => {
for (var i = 0, j = 10; i < j; i++) {
this.data.push({name: this.count++ })
}
console.log(this.data)
this.busy = false
}, 1000)
}
}
效果
默认会载入10行数据,只要往下滚动到页面底部,就会在1秒后再次加载10条,然后继续滚动,又会加载10条。就如下图:
选项解释
v-infinite-scroll="loadMore"
表示回调函数是loadMore
infinite-scroll-disabled="busy"
表示由变量busy
决定是否执行loadMore
,false
则执行loadMore
,true
则不执行,看清楚,busy表示繁忙,繁忙的时候是不执行的。infinite-scroll-distance="10"
这里10
决定了页面滚动到离页尾多少像素的时候触发回调函数,10
是像素值。通常我们会在页尾做一个几十像素高的“正在加载中...”,这样的话,可以把这个div的高度设为infinite-scroll-distance
的值即可。
其他选项:
infinite-scroll-immediate-check
默认值为true
,该指令意思是,应该在绑定后立即检查busy的值和是否滚动到底。如果你的初始内容高度不够高、不足以填满可滚动的容器的话,你应设为true
,这样会立即执行一次loadMore
,会帮你填充一些初始内容。infinite-scroll-listen-for-event
当事件在Vue实例中发出时,无限滚动将再次检查。infinite-scroll-throttle-delay
检查busy
的值的时间间隔,默认值是200,因为vue-infinite-scroll的基础原理就是,vue-infinite-scroll会循环检查busy
的值,以及是否滚动到底,只有当:busy为false且滚动到底,回调函数才会执行。
实战应用
可以看到,上方的例子是在不断的修改data变量,data变量的数据不断增加,这看起来是没错的。但是,实战中,我们的新数据肯定是Ajax获取的,并不是范例中的用for循环来灌入无用的自然数,而且,并不需要setTimeout,我们希望的是页面滚动到底部就立即执行Ajax,事实上,上面代码中的setTimeout只是为了模拟一个延迟加载的效果,并不是说必须要延迟1秒才Ajax。
实战中该怎么做?
只需要将这段模拟Ajax的代码改为真正的Ajax获取数据的代码即可:
setTimeout(() => {
for (var i = 0, j = 10; i < j; i++) {
this.data.push({name: this.count++ })
}
console.log(this.data)
this.busy = false
}, 1000)
另外,
this.busy = false
也必须作为Ajax的回调
vue-scroller
安装
npm install vue-scroller -d
在main.js里面使用
import VueScroller from 'vue-scroller'
Vue.use(VueScroller)
使用
注意:scroller的使用最好设置一个高
<scroller style="top: 100px;" :height='400' :on-refresh="refresh" :on-infinite="infinite" ref="myscroller">
<div class="order-box" v-for="(item,index) in orderList" :key="index">
</div>
</scroller>
数据
data(){
return{
status:'all',
orderList:[],
page:0,
all_page:1,
}
},
下拉刷新
refresh (done) {
setTimeout(()=>{
done();
},1500)
},
上拉加载更多
注意:done的使用,如果在数据没有赋值到模板前就调用,就会一直触发下拉函数,所以我们要在请求成功的回调中模板赋值后调用
下拉的函数是绑定属性的方式绑定在scroller标签上的,所以我们不需要在created里面调用一次请求函数,页面初始化的时候回自动调用一次下拉的函数,从而获取到第一页的数据
//下拉触发
infinite (done) {
if(this.page>=this.all_page){
setTimeout(()=>{
this.$refs.myscroller.finishInfinite(true);
},1500)
}else{
setTimeout(()=>{
this.page++;
this.getorderList(done)
},500);
}
},
getorderList(done){
this.$http({
method:'post',
url:'/seckill/server/orderList',
data:{
jwt:this.jwt,
status:this.status,
page:this.page,
page_size:5
}
}).then(res=>{
if(res.data.code == 0){
this.orderList.push.apply(this.orderList,res.data.data.list)
this.$refs.myscroller.finishInfinite(true)
this.page = res.data.data.page
this.all_page = res.data.data.all_page
done();
}else{
}
})
},
注意
如果涉及到tab栏切换,需要重新设置scroller的状态.finishInfinite(false)参数为false时会从新调用一次上拉函数,从而重置当前scroller的状态
goodsAll(){
this.status = 'all'
this.page = 0
this.all_page = 1
this.$refs.myscroller.finishInfinite(false);
this.orderList = []
},
triggerPullToRefresh() 触发下拉刷新
finishPullToRefresh() 完成下拉刷新
this.$refs.my_scroller.finishInfinite(false)
finishInfinite(isNoMoreData :Boolean) 当参数为false时,上拉获取数据可以重新调用。当参数为true,上拉获取数据回调函数停止使用,下拉下部不再显示loading,会显示‘’暂无更多数据
vue-infinite-loading
安装
npm install vue-infinite-loading --save
组件内使用
// 组件类使用
import InfiniteLoading from 'vue-infinite-loading';
export default {
components: { InfiniteLoading }
}
//使用 基础版
<infinite-loading
spinner="spiral"
@infinite="infiniteHandler"
:distance="200"
class="infinite-loading-wrap"
>
<!-- <div slot="spinner">Loading...</div> -->
<div slot="no-more">No more Data</div>
<div slot="no-results">No results Data</div>
<!-- <div slot="error" slot-scope="{ trigger }">
Error Data, click <a href="javascript:;" @click="trigger">here</a> toretry
</div> -->
</infinite-loading>
基本用法
<template>
<div>
<p v-for="(item,index) in list" :key="index">
<span v-text="item"></span>
</p>
<!--infinite-loading这个组件要放在列表的底部,滚动的盒子里面!-->
<infinite-loading
spinner="spiral"
@infinite="infiniteHandler"
:identifier="infiniteId"
:distance="200"
class="infinite-loading-wrap"
>
<div slot="spinner">Loading...</div>
<div slot="no-more">No more Data</div>
<div slot="no-results">No results Data</div>
<div slot="error" slot-scope="{ trigger }">
Error Data, click <a href="javascript:;" @click="trigger">here</a> toretry
</div>
</infinite-loading>
</div>
</template>
<script>
import InfiniteLoading from 'vue-infinite-loading';
export default {
data() {
return {
infiniteId: +new Date(), // 重置滚动状态 改变
page: 1,
list: []
};
},
methods: {
// 重置滚动状态
rest(){
this.list = [];
this.page = 1;
this.infiniteId += 1;
},
async infiniteHandler($state) {
// 模仿请求数据
const res = await this.$axios.workList({ page: this.page, pagesize: 20 });
if (res.data.list.length) {
this.page += 1;
this.list = this.list.concat(res.data.list);
$state.loaded();
} else {
$state.complete();
}
// 这里模仿加载延迟1秒钟
//setTimeout(() => {
// let temp = [];
// for (let i = this.list.length + 1; i <= this.list.length + 20; i++) {
// temp.push(i);
// }
// this.list = this.list.concat(temp);
// $state.loaded();
//}, 1000);
//},
},
components: { InfiniteLoading }
}
</script>
分页用法
<template>
<div>
<ul>
<li class="hacker-news-item" v-for="(item, key) in list"></li>
</ul>
<infinite-loading @infinite="infiniteHandler">
<span slot="no-more">No more Data</span>
</infinite-loading>
</div>
</template>
<script>
import InfiniteLoading from "vue-infinite-loading";
import axios from "axios";
export default {
data() {
return {
list: [],
};
},
methods: {
infiniteHandler($state) {
let api = "http://xxx.com/xxx"; // api为你请求数据地址
axios
.get(api, {
params: {
// 页码参数(10条每页)
page: this.list.length / 10 + 1,
},
})
.then((response) => {
if (response.data.length) {
// response.data为你请求接口返回的数组列表
this.list = this.list.concat(response.data);
$state.loaded();
if (this.list.length / 10 === 10) {
// 这里是加载了10页数据,设置不在加载
$state.complete();
}
} else {
$state.complete();
}
});
},
},
components: { InfiniteLoading },
};
</script>
说明: $state: 该组件会传递一个特殊的事件参数$state给事件处理器来改变加载状态,$state参数包括三个方法,它们是loaded方法,complete方法和reset方法。
- loaded方法用于在每次加载数据后停止播放动画,然后该组件将准备好进行下一次触发。
- complete方法用于完成完整的无限加载,则该组件将不再处理任何滚动操作。如果在loaded调用complete方法时永远不会调用该方法,则此组件将显示用户的结果消息,如果不是,则将显示不再有用户消息,并且可以按slot设置其它内容
- reset方法是将组件返回到原来的状态
条件用法
<template>
<div class="hacker-news-list">
<div class="hacker-news-header">
<!--下拉改变-->
<select v-model="tag" @change="changeFilter()">
<option value="story">Story</option>
<option value="history">History</option>
</select>
<!--或者点击改变-->
<button @click="changeFilter()">搜索</button>
</div>
<ul>
<li class="hacker-news-item" v-for="(item, key) in list"></li>
</ul>
<!--不要忘记设置这个 ref="infiniteLoading"-->
<infinite-loading @infinite="infiniteHandler" ref="infiniteLoading">
<span slot="no-more">No more data</span>
</infinite-loading>
</div>
</template>
<script>
import InfiniteLoading from 'vue-infinite-loading';
import axios from 'axios';
export default {
data() {
return {
list: [],
tag: 'story',
};
},
methods: {
infiniteHandler($state) {
const api="http://xxx.com/xxx";
// api为你请求数据地址
axios.get(api, {
params: {
// 改变的条件参数
tags: this.tag,
page: this.list.length / 10 + 1,
},
}).then(({ data }) => {
if (data.result.length) {
this.list = this.list.concat(data.result);
$state.loaded();
if (this.list.length / 20 === 10) {
state.complete();
}
} else {
$state.complete();
}
});
},
//改变条件条用此方法
changeFilter() {
this.list = [];
this.$nextTick(() => {
this.$refs.infiniteLoading.$emit('$InfiniteLoading:reset');
});
},
},
components: { InfiniteLoading }
}
</script>
防抖
import { debounce } from "lodash"; // 防抖
// 防抖
get: debounce(async function () {
let k = await this.$axios.getList_API();
console.log(k, "防抖版");
}, 1000),