vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件
1.下拉刷新和上拉加载更多组件
Scroller.vue
<!-- 下拉刷新 上拉加载更多 组件 -->
<template>
<div
:style="marginTop"
class="yo-scroll"
:class="{'down':(state===0),'up':(state==1),refresh:(state===2),touch:touching}"
@touchstart="touchStart($event)"
@touchmove="touchMove($event)"
@touchend="touchEnd($event)">
<section class="inner" :style="{ transform: 'translate3d(0, ' + top + 'px, 0)' }">
<!-- 顶部提示语(刷新) -->
<header class="pull-refresh">
<slot name="pull-refresh">
<span class="down-tip">下拉更新</span>
<span class="up-tip">松开刷新数据</span>
<span class="refresh-tip">加载中……</span>
</slot>
</header>
<!-- 父组件 列表部分 -->
<slot>
</slot>
<!-- 底部提示语(加载更多) -->
<footer class="load-more">
<slot name="load-more">
<span v-show="downFlag === false">上拉加载更多</span>
<span v-show="downFlag === true">加载中……</span>
</slot>
</footer>
<!-- 暂无数据提示语 -->
<div class="nullData" v-show="dataList.noFlag">暂无更多数据</div>
</section>
</div>
</template> <script>
export default {
// 接收父组件参数
props: {
marginTop: {
default: "margin-top:40px;"
},
// 默认高度
offset: {
type: Number,
default: 100
},
// 是否支持加载更多
enableInfinite: {
type: Boolean,
default: true
},
// 是否支持刷新
enableRefresh: {
type: Boolean,
default: true
},
// 是否显示'暂无数据'
dataList: {
default: false,
required: false
},
// 刷新方法
onRefresh: {
type: Function,
default: undefined,
required: false
},
// 加载更多方法
onInfinite: {
type: Function,
default: undefined,
require: false
}
},
data() {
return {
top: 0, // 下拉高度
state: 0, // 状态: 0 下拉/ 1 上拉 / 2 刷新
startX: 0, // 手指滑动起始位置 X轴
startY: 0, // 手指滑动起始位置 Y轴
touching: false, // -webkit-overflow-scrolling
infiniteLoading: false, // 加载更多效果
downFlag: false, //用来显示是否加载中
}
},
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; // 默认 不显示'暂无数据'
this.$el.querySelector('.load-more').style.display = 'block';// 实体化加载更多
},
// 手指移动中
touchMove(e) {
if(!this.enableRefresh || this.dataList.noFlag || !this.touching) {
return
}
let diff = e.targetTouches[0].pageY - this.startY - this.startScroll
if(diff > 0) e.preventDefault()
this.top = Math.pow(diff, 0.8) + (this.state === 2 ? this.offset : 0)
if(this.state === 2) { // 刷新中
return
}
if(this.top >= this.offset) {
this.state = 1
} else {
this.state = 0
}
let more = this.$el.querySelector('.load-more');
if(!this.top && this.state === 0) {
more.style.display = 'block';
} else {
more.style.display = 'none';
}
},
// 手指结束滑动
touchEnd(e) {
if(!this.enableRefresh) {
return
}
this.touching = false
if(this.state === 2) { // 刷新中
this.state = 2
this.top = this.offset
return
}
if(this.top >= this.offset) { // 进行刷新
this.refresh()
} else { // 取消刷新
this.state = 0
this.top = 0
}
//用于判断滑动是否在原地 ----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("滑动距离太短")
return;
}
//--------end--------
if(!this.enableInfinite || this.infiniteLoading) {
return
}
let outerHeight = this.$el.clientHeight,
innerHeight = this.$el.querySelector('.inner').clientHeight,
scrollTop = this.$el.scrollTop,
ptrHeight = this.onRefresh ? this.$el.querySelector('.pull-refresh').clientHeight : 0,
bottom = innerHeight - outerHeight - scrollTop - ptrHeight;
if(bottom <= this.offset && this.state === 0) {
this.downFlag = true;
this.infinite();
} else {
this.$el.querySelector('.load-more').style.display = 'none';
this.downFlag = false;
}
},
// 刷新
refresh() {
this.state = 2;
this.top = this.offset;
setTimeout(() => {
this.onRefresh(this.refreshDone)
}, 300);
},
// 结束刷新
refreshDone() {
this.state = 0
this.top = 0
},
// 加载更多
infinite() {
this.infiniteLoading = true
setTimeout(() => {
this.onInfinite(this.infiniteDone);
}, 2000);
},
// 结束加载更多
infiniteDone() {
this.infiniteLoading = false
}
}
}
</script> <style lang="less" scoped>
.yo-scroll {
// margin-top: 40px; // 解决有标题栏的bug
font-size: 16px;
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: -50px;
width: 100%;
height: auto;
transition-duration: 300ms;
.pull-refresh {
position: relative;
left: 0;
top: 0;
width: 100%;
height: 50px;
display: flex;
display: -webkit-flex;
align-items: center;
justify-content: center;
}
.load-more {
height: 50px;
line-height: 50px;
display: flex;
text-align: center;
align-items: center;
justify-content: center;
display: none;
}
.nullData { //暂无更多数据样式
font-size: 16px;
color: #999999;
height: 50px;
line-height: 60px;
text-align: center;
}
.down-tip,
.refresh-tip,
.up-tip {
display: none;
}
.up-tip:before,
.refresh-tip:before {
content: '';
display: inline-block;
width: 110px;
height: 40px;
font-size: 16px;
background-size: 70% !important;
position: absolute;
top: 0;
left: 20%;
}
.up-tip:before {
background: url(../assets/images/down-logo.png) no-repeat left;
}
.refresh-tip:before {
background: url(../assets/images/refresh-logo.gif) no-repeat left;
}
}
} .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>
2.页面调用
LoadMore.vue
<!-- 加载更多 -->
<template>
<div>
<!-- 标题栏 -->
<mt-header title="加载更多">
<router-link to="/" slot="left">
<mt-button icon="back">返回</mt-button>
</router-link>
</mt-header>
<!-- 列表 -->
<div class="cont">
<m-scroller :on-refresh="onRefresh" :on-infinite="onInfinite" :dataList="scrollData" :marginTop="marginTop">
<ul>
<li v-for="(item,index) in listdata">{{item.name}}</li>
</ul>
</m-scroller>
</div>
</div>
</template> <script>
import mScroller from '../components/Scroller' export default {
components: {
mScroller
},
data() {
return {
marginTop:'margin-top:40px;',
pageStart: 0, // 开始页数
pageEnd: 0, // 结束页数
listdata: [], // 数据列表
scrollData:{
noFlag: false //暂无更多数据显示
}
}
},
mounted: function() {
// 首次请求数据
this.fetchData();
},
methods: {
fetchData() {
this.axios.get('/api/testData').then((response) => {
this.listdata = response.data.data.list;
// 获取总页数
this.pageEnd = response.data.data.totalPage;
// 还原
this.pageStart = 0;
})
},
// 下拉刷新
onRefresh(done) {
this.fetchData();
done(); // call done
},
// 上拉加载更多
onInfinite(done) {
this.pageStart++;
// 加载条
let more = this.$el.querySelector('.load-more');
// 判断是否显示加载条
if(this.pageStart > this.pageEnd){
//走完数据调用方法
this.scrollData.noFlag = true;
}else{
let _this = this;
this.axios.get('/api/testData').then((response) => {
_this.listdata = _this.listdata.concat(response.data.data.list);
// 获取总页数
_this.pageEnd = response.data.data.totalPage;
})
}
// 隐藏加载条
more.style.display = 'none';
done();
}
}
}
</script> <style lang="less" scoped>
ul {
li {
min-height: 50px;
line-height: 50px;
text-align: center;
border: 1px solid red;
}
}
// 隐藏滚动条
::-webkit-scrollbar{
display:none;
}
</style>
3.效果图
vue2.0 自定义 下拉刷新和上拉加载更多(Scroller) 组件的更多相关文章
- juery下拉刷新,div加载更多元素并添加点击事件(二)
buffer.append("<div class='col-xs-3 "+companyId+"' style='padding-left: 10px; padd ...
- android--------自定义控件ListView实现下拉刷新和上拉加载
开发项目过程中基本都会用到listView的下拉刷新和上滑加载更多,为了方便重写的ListView来实现下拉刷新,同时添加了上拉自动加载更多的功能. Android下拉刷新可以分为两种情况: 1.获取 ...
- Android 自定义 ListView 上下拉动“刷新最新”和“加载更多”歌曲列表
本文内容 环境 测试数据 项目结构 演示 参考资料 本文演示,上拉刷新最新的歌曲列表,和下拉加载更多的歌曲列表.所谓"刷新最新"和"加载更多"是指日期.演示代码 ...
- 下拉刷新和上拉加载 Swift
转载自:http://iyiming.me/blog/2015/07/05/custom-refresh-and-loading/ 关于下拉刷新和上拉加载,项目中一直使用MJRefresh(原先还用过 ...
- Diycode开源项目 搭建可以具有下拉刷新和上拉加载的Fragment
1.效果预览 1.1.这个首页就是一个Fragment碎片,本文讲述的就是这个碎片的搭建方式. 下拉会有一个旋转的刷新圈,上拉会刷新数据. 1.2.整体结构 首先底层的是BaseFragment 然后 ...
- Android实现RecyclerView的下拉刷新和上拉载入很多其它
需求 先上效果图, Material Design风格的下拉刷新和上拉载入很多其它. 源代码地址(欢迎star) https://github.com/studychen/SeeNewsV2 假设对于 ...
- RecyclerView下拉刷新和上拉加载更多实现
RecyclerView下拉刷新和上拉加载更多实现 转 https://www.jianshu.com/p/4ea7c2d95ecf 在Android开发中,RecyclerView算是使用频率非 ...
- Android 5.X新特性之为RecyclerView添加下拉刷新和上拉加载及SwipeRefreshLayout实现原理
RecyclerView已经写过两篇文章了,分别是Android 5.X新特性之RecyclerView基本解析及无限复用 和 Android 5.X新特性之为RecyclerView添加Header ...
- iscroll.js 下拉刷新和上拉加载
html代码如下 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> < ...
随机推荐
- day01_10.for循环
for和while都是一种循环 解释:所有循环的共同点 画图详解 在一条数轴上,循环就是有起始点($i=0); 有结束点($i<=10);有步长($i++); 每走一个相应的步长,就执行一次代码 ...
- API生命周期第三阶段:API实施:使用swagger codegen生成可部署工程,择取一个作为mock service
在分享培训了swagger对于API的设计之后,有一些人问我说:你看,现在咱们前端使用web_API做为mock data在进行测试,后端也有mock 测试.然后我们再进行联调,这之中肯定会出现一些偏 ...
- poj 2499第K短路模板
第k*短路模板(单项边) #include <iostream> #include <cstdio> #include <algorithm> #include & ...
- 九度oj 题目1494:Dota
题目描述: 大家都知道在dota游戏中,装备是对于英雄来说十分重要的要素. 英雄们不仅可以购买单个的装备,甚至某些特定的装备组合能够合成更强的装备. 为了简化问题,我们将每个装备对于英雄的功能抽象为一 ...
- 刷题总结——regular words(hdu1502 dp+高精度加法+压位)
题目: Problem Description Consider words of length 3n over alphabet {A, B, C} . Denote the number of o ...
- 学习struts2及MVC
1.MVC模式基础 1.1.MVC模式简介 MVC是一种架构型模式,它本身并不引入新的功能,只是用来指导我们改善应用程序的架构,使得应用的模型和视图相分离,从而达到更好的开发和维护效率.在MVC模式中 ...
- spring的事务传播与隔离
propagation 事务的传播属性: 1.PROPAGATION_REQUIRED(*-required):支持当前事务,如果当前没有事务,就新建一个事务.(最常见的选择) 2.PROPAGATI ...
- 【bzoj1592】[Usaco2008 Feb]Making the Grade 路面修整
FJ打算好好修一下农场中某条凹凸不平的土路.按奶牛们的要求,修好后的路面高度应当单调上升或单调下降,也就是说,高度上升与高度下降的路段不能同时出现在修好的路中. 整条路被分成了N段,N个整数A_1, ...
- javaweb学习总结(十五)——JSP基础语法(转)
任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语法,而且在JSP中,所有的JAVA语句都可以使用. 一.JSP模版元素 JSP页面中的HTML内容称之 ...
- luogu 1004 方格取数 dp
题目链接 题意 设有N*N的方格图(N<=9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字0.如下图所示: A 0 0 0 0 0 0 0 0 0 0 13 0 0 6 0 0 ...