Commit 30955aad by 汤强勇

增加iscroll插件 消息下拉刷新,上拉加载更多

parent 1d16a73d
/build/ /build/
/config/ /config/
/dist/ /dist/
/src/lib/
/*.js /*.js
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
span.user-name {{user.name}} span.user-name {{user.name}}
i.fa.fa-angle-down i.fa.fa-angle-down
li.nav-item.fr li.nav-item.fr
a.link a.link(@click="showMessage()")
i.fa.fa-envelope-o i.fa.fa-envelope-o
li.nav-item.fr li.nav-item.fr
el-popover( el-popover(
...@@ -242,8 +242,42 @@ ...@@ -242,8 +242,42 @@
border-radius: 5px; border-radius: 5px;
margin-right: 5px; margin-right: 5px;
</style> </style>
<style lang="scss">
.message-panel {
top:70px !important;
padding-top: 0;
&.el-notification {
height: 864px;
width: 420px;
overflow: hidden;
overflow-y: scroll;
}
.el-notification__group {
width: 100%;
}
.el-notification__title {
height: 40px;
box-sizing: border-box;
line-height: 1;
position: relative;
background: #ffffff;
border-bottom: 1px solid #ddd;
z-index: 2;
padding: 10px 20px;
font-weight: bold;
font-size: 16px;
}
.el-notification__closeBtn {
z-index: 9;
}
}
</style>
<script> <script>
import { mapGetters, mapActions } from 'vuex' import { mapGetters, mapActions } from 'vuex'
import message from './message'
export default { export default {
name: 'headerNav', name: 'headerNav',
data () { data () {
...@@ -296,6 +330,9 @@ export default { ...@@ -296,6 +330,9 @@ export default {
sidebarUnfoldInfo: 'getSidebarUnfoldInfo' sidebarUnfoldInfo: 'getSidebarUnfoldInfo'
}) })
}, },
components: {
message
},
methods: { methods: {
...mapActions([ ...mapActions([
'showEditMenus', 'showEditMenus',
...@@ -304,6 +341,15 @@ export default { ...@@ -304,6 +341,15 @@ export default {
clickItem () { clickItem () {
console.log(this) console.log(this)
}, },
showMessage () {
const h = this.$createElement
this.$notify({
title: '消息中心',
message: h('message'),
duration: 0,
customClass: 'message-panel'
})
},
handleOpen () {}, handleOpen () {},
handleClose () {}, handleClose () {},
handleShowMenus () { handleShowMenus () {
......
<template> <template>
<div> <div id="wrapper">
<!--滑动区域--> <div id="scroller">
<mescroll-vue ref="mescroll" :up="mescrollUp" @init="mescrollInit"> <div id="pullDown">
<!--筛选条件; 模拟列表的重置和演示空布局的使用--> <span class="pullDownIcon" style="display: none"></span><span class="pullDownLabel">释放刷新</span>
<div class="nav">
<p :class="getActiveCls(0)" @click="changeTab(0)">全部</p>
<p :class="getActiveCls(1)" @click="changeTab(1)">奶粉</p>
<p :class="getActiveCls(2)" @click="changeTab(2)">图书</p>
</div> </div>
<!--展示上拉加载的数据列表--> <ul id="thelist">
<ul id="dataList" class="data-list"> <li v-for="(item, index) in items" class="message-item" :key="index">
<li v-for="pd in dataList" :key="pd.id"> <div class="message-item-title">{{item.title}}</div>
<p class="msg-title">{{pd.title}}</p> <div class="message-desc">{{item.content_text}}</div>
<p class="msg-text">{{pd.content_text}}</p> <div class="message-desc">{{item.push_time | fomatDate}}</div>
<p class="msg-time">{{pd.create_time}}</p>
</li> </li>
</ul> </ul>
</mescroll-vue> <div id="pullUp">
<span class="pullUpIcon" style="display: none"></span><span class="pullUpLabel">释放加载</span>
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
// 引入mescroll的vue组件 require('@/lib/iscroll/iscroll.js')
import MescrollVue from '@/lib/mescroll/mescroll.vue' const IScroll = window.iScroll
let pullDownEl, pullDownOffset,
pullUpEl, pullUpOffset
export default { export default {
name: 'message', name: 'message',
components: {
MescrollVue
},
data () { data () {
return { return {
mescroll: null, // mescroll实例对象 items: [],
mescrollUp: { myScroll: null,
callback: this.upCallback, // 上拉回调,此处可简写; 相当于 callback: function (page, mescroll) { getListData(page); } pageNo: 0,
page: { isLastPage: false
num: 0, // 当前页码,默认0,回调之前会加1,即callback(page)会从1开始
size: 10 // 每页数据的数量
},
noMoreSize: 5, // 如果列表已无数据,可设置列表的总数量要大于等于5条才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看
toTop: {
src: './static/images/mescroll/mescroll-totop.png' // 回到顶部按钮的图片路径,支持网络图
},
empty: {
// 列表第一页无任何数据时,显示的空提示布局; 需配置warpId才生效;
warpId: 'dataList', // 父布局的id;
icon: './static/images/mescroll/mescroll-empty.png', // 图标,支持网络图
tip: '暂无相关数据~', // 提示
btntext: '去逛逛 >', // 按钮,默认""
btnClick () { // 点击按钮的回调,默认null
alert('点击了按钮,具体逻辑自行实现')
}
},
lazyLoad: {
use: true // 是否开启懒加载,默认false
}
},
dataList: [], // 列表数据
pdType: 0 // 菜单
} }
}, },
beforeRouteEnter (to, from, next) { // 如果没有配置回到顶部按钮或isBounce,则beforeRouteEnter不用写 components: {
next(vm => {
vm.$refs.mescroll.beforeRouteEnter() // 进入路由时,滚动到原来的列表位置,恢复回到顶部按钮和isBounce的配置
})
}, },
beforeRouteLeave (to, from, next) { // 如果没有配置回到顶部按钮或isBounce,则beforeRouteLeave不用写 created () {
this.$refs.mescroll.beforeRouteLeave() // 退出路由时,记录列表滚动的位置,隐藏回到顶部按钮和isBounce的配置 this.getListDataFromNet(1, 10)
next()
}, },
methods: {
// mescroll组件初始化的回调,可获取到mescroll对象
mescrollInit (mescroll) {
this.mescroll = mescroll
},
// 上拉回调 page = {num:1, size:10}; num:当前页 ,默认从1开始; size:每页数据条数,默认10
upCallback (page, mescroll) {
// 模拟联网
this.getListDataFromNet(page.num, page.size)
},
// 选中状态的样式 watch: {
getActiveCls (type) {
return this.pdType === type ? 'active' : '' },
}, computed: {
// 切换菜单
changeTab (type) {
if (this.pdType !== type) {
this.pdType = type
this.dataList = []// 在这里手动置空列表,可显示加载中的请求进度
this.mescroll.resetUpScroll() // 刷新列表数据
}
},
/* 联网加载列表数据 },
在您的实际项目中,请参考官方写法: http://www.mescroll.com/api.html#tagUpCallback mounted () {
请忽略getListDataFromNet的逻辑,这里仅仅是在本地模拟分页数据,本地演示用 this.$nextTick(() => {
实际项目以您服务器接口返回的数据为准,无需本地处理分页. this.loaded()
* */ })
async getListDataFromNet (pageNum, pageSize) { },
methods: {
async getListDataFromNet () {
if (this.isLastPage) {
this.myScroll.refresh()
return false
}
this.pageNo++
// 延时一秒,模拟联网 // 延时一秒,模拟联网
const res = await this.axios.get('http://rap2api.taobao.org/app/mock/115626/store/notice!getStoreNoticeListByPageAction.do', { const res = await this.axios.get(
params: { 'http://rap2api.taobao.org/app/mock/115626/store/notice!getStoreNoticeListByPageAction.do',
pageNo: pageNum, {
pageSize, params: {
push_state: 2 pageNo: this.pageNo,
pageSize: 10,
push_state: 2
}
} }
}) )
if (res.data.code === 0) { if (res.data.code === 0) {
const resData = res.data.dataList const resData = res.data.data
const length = this.dataList.length const length = this.items.length
if (length <= res.data.totalCount) { if (length <= resData.totalCount) {
this.dataList = this.dataList.concat(resData) this.items = this.items.concat(resData.dataList)
} else {
this.isLastPage = true
} }
} }
this.myScroll.refresh()
},
loaded () {
pullDownEl = document.getElementById('pullDown')
pullDownOffset = pullDownEl.offsetHeight
pullUpEl = document.getElementById('pullUp')
pullUpOffset = pullUpEl.offsetHeight
this.myScroll = new IScroll('wrapper', {
scrollbarClass: 'myScrollbar', /* 重要样式 */
useTransition: false, /* 此属性不知用意,本人从true改为false */
topOffset: pullDownOffset,
onRefresh: () => {
this.$nextTick(() => {
if (pullDownEl.className.match('loading')) {
pullDownEl.className = ''
pullDownEl.querySelector('.pullDownLabel').innerHTML = '释放刷新'
} else if (pullUpEl.className.match('loading')) {
pullUpEl.className = ''
pullUpEl.querySelector('.pullUpLabel').innerHTML = this.isLastPage ? '没有更多数据' : '释放加载'
}
})
},
onScrollMove: function () {
if (this.y > 5 && !pullDownEl.className.match('flip')) {
pullDownEl.className = 'flip'
pullDownEl.querySelector('.pullDownLabel').innerHTML = '释放加载'
this.minScrollY = 0
} else if (this.y < 5 && pullDownEl.className.match('flip')) {
pullDownEl.className = ''
pullDownEl.querySelector('.pullDownLabel').innerHTML = '释放刷新'
this.minScrollY = -pullDownOffset
} else if (this.y < (this.maxScrollY - 5) && !pullUpEl.className.match('flip')) {
pullUpEl.className = 'flip'
pullUpEl.querySelector('.pullUpLabel').innerHTML = '释放加载'
this.maxScrollY = this.maxScrollY
} else if (this.y > (this.maxScrollY + 5) && pullUpEl.className.match('flip')) {
pullUpEl.className = ''
pullUpEl.querySelector('.pullUpLabel').innerHTML = '释放刷新'
this.maxScrollY = pullUpOffset
}
},
onScrollEnd: () => {
this.$nextTick(() => {
if (pullDownEl.className.match('flip')) {
pullDownEl.className = 'loading'
pullDownEl.querySelector('.pullDownLabel').innerHTML = '加载中...'
this.pullDownAction()
} else if (pullUpEl.className.match('flip')) {
pullUpEl.className = 'loading'
pullUpEl.querySelector('.pullUpLabel').innerHTML = '加载中...'
this.pullUpAction()
}
})
}
})
document.addEventListener('touchmove', function (e) { e.preventDefault() }, false)
},
pullDownAction () {
this.items = []
this.pageNo = 0
this.isLastPage = false
this.getListDataFromNet()
},
pullUpAction () {
this.getListDataFromNet()
} }
} }
} }
</script> </script>
<style scope> <style scoped>
/*以fixed的方式固定mescroll的高度*/ #wrapper {
.mescroll {
position: fixed;
top: 44px;
bottom: 0;
height: auto;
}
.header {
z-index: 9990;
position: fixed;
top: 0;
left: 0;
width: 100%; width: 100%;
height: 44px;
line-height: 44px;
text-align: center;
border-bottom: 1px solid #eee;
background-color: white;
}
.header .btn-left {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; bottom: 0;
padding: 12px;
line-height: 22px;
}
.swiper {
width: 100%;
vertical-align: bottom;
} }
#pullDown,#pullUp {
.nav { border-bottom: none;
text-align: center; text-align: center;
border-bottom: 1px solid #ddd;
}
.nav p {
display: inline-block;
width: 30%;
padding: 10px 0;
} }
.nav .active { #pullUp {
border-bottom: 1px solid #FF6990; border-top: solid 1px #d7d7d7;
color: #FF6990; text-align: center;
}
.data-list li {
position: relative;
padding: 10px 8px 10px 120px;
border-bottom: 1px solid #eee;
} }
</style>
.data-list .pd-img { <style lang="scss" scoped>
position: absolute; .message-item {
left: 18px; border-top: 1px dashed #ddd;
top: 18px; padding: 5px 20px;
width: 80px; cursor: pointer;
height: 80px; &:first-child {
border-top:none;
}
} }
.data-list .pd-name { .message-item-title {
font-size: 16px; font-size: 15px;
line-height: 20px;
height: 40px;
overflow: hidden;
} }
.data-list .pd-price { .message-desc {
margin-top: 8px; font-size: 13px;
color: red;
} }
.data-list .pd-sold {
font-size: 12px;
margin-top: 8px;
color: gray;
}
</style> </style>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>iScroll 实例:下拉刷新,滚动翻页</title>
<link rel="stylesheet" type="text/css" href="scrollbar.scss">
<script type="application/javascript" src="iscroll.js"></script>
<script type="text/javascript">
var myScroll,
pullDownEl, pullDownOffset,
pullUpEl, pullUpOffset,
generatedCount = 0;
/**
* 下拉刷新 (自定义实现此方法)
* myScroll.refresh(); // 数据加载完成后,调用界面更新方法
*/
function pullDownAction () {
setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production!
var el, li, i;
el = document.getElementById('thelist');
for (i=0; i<3; i++) {
li = document.createElement('li');
li.innerText = 'Generated row ' + (++generatedCount);
el.insertBefore(li, el.childNodes[0]);
}
myScroll.refresh(); //数据加载完成后,调用界面更新方法 Remember to refresh when contents are loaded (ie: on ajax completion)
}, 1000); // <-- Simulate network congestion, remove setTimeout from production!
}
/**
* 滚动翻页 (自定义实现此方法)
* myScroll.refresh(); // 数据加载完成后,调用界面更新方法
*/
function pullUpAction () {
setTimeout(function () { // <-- Simulate network congestion, remove setTimeout from production!
var el, li, i;
el = document.getElementById('thelist');
for (i=0; i<3; i++) {
li = document.createElement('li');
li.innerText = 'Generated row ' + (++generatedCount);
el.appendChild(li, el.childNodes[0]);
}
myScroll.refresh(); // 数据加载完成后,调用界面更新方法 Remember to refresh when contents are loaded (ie: on ajax completion)
}, 1000); // <-- Simulate network congestion, remove setTimeout from production!
}
/**
* 初始化iScroll控件
*/
function loaded() {
pullDownEl = document.getElementById('pullDown');
pullDownOffset = pullDownEl.offsetHeight;
pullUpEl = document.getElementById('pullUp');
pullUpOffset = pullUpEl.offsetHeight;
myScroll = new iScroll('wrapper', {
scrollbarClass: 'myScrollbar', /* 重要样式 */
useTransition: false, /* 此属性不知用意,本人从true改为false */
topOffset: pullDownOffset,
onRefresh: function () {
if (pullDownEl.className.match('loading')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = '下拉刷新...';
} else if (pullUpEl.className.match('loading')) {
pullUpEl.className = '';
pullUpEl.querySelector('.pullUpLabel').innerHTML = '上拉加载更多...';
}
},
onScrollMove: function () {
if (this.y > 5 && !pullDownEl.className.match('flip')) {
pullDownEl.className = 'flip';
pullDownEl.querySelector('.pullDownLabel').innerHTML = '松手开始更新...';
this.minScrollY = 0;
} else if (this.y < 5 && pullDownEl.className.match('flip')) {
pullDownEl.className = '';
pullDownEl.querySelector('.pullDownLabel').innerHTML = '下拉刷新...';
this.minScrollY = -pullDownOffset;
} else if (this.y < (this.maxScrollY - 5) && !pullUpEl.className.match('flip')) {
pullUpEl.className = 'flip';
pullUpEl.querySelector('.pullUpLabel').innerHTML = '松手开始更新...';
this.maxScrollY = this.maxScrollY;
} else if (this.y > (this.maxScrollY + 5) && pullUpEl.className.match('flip')) {
pullUpEl.className = '';
pullUpEl.querySelector('.pullUpLabel').innerHTML = '上拉加载更多...';
this.maxScrollY = pullUpOffset;
}
},
onScrollEnd: function () {
if (pullDownEl.className.match('flip')) {
pullDownEl.className = 'loading';
pullDownEl.querySelector('.pullDownLabel').innerHTML = '加载中...';
pullDownAction(); // Execute custom function (ajax call?)
} else if (pullUpEl.className.match('flip')) {
pullUpEl.className = 'loading';
pullUpEl.querySelector('.pullUpLabel').innerHTML = '加载中...';
pullUpAction(); // Execute custom function (ajax call?)
}
}
});
setTimeout(function () { document.getElementById('wrapper').style.left = '0'; }, 800);
}
//初始化绑定iScroll控件
document.addEventListener('touchmove', function (e) { e.preventDefault(); }, false);
document.addEventListener('DOMContentLoaded', loaded, false);
</script>
<style type="text/css" media="all">
body,ul,li {
padding:0;
margin:0;
border:0;
}
body {
font-size:12px;
-webkit-user-select:none;
-webkit-text-size-adjust:none;
font-family:helvetica;
}
#header {
position:absolute;
top:0; left:0;
width:100%;
height:45px;
line-height:45px;
background-image:-webkit-gradient(linear, 0 0, 0 100%, color-stop(0, #fe96c9), color-stop(0.05, #d51875), color-stop(1, #7b0a2e));
background-image:-moz-linear-gradient(top, #fe96c9, #d51875 5%, #7b0a2e);
background-image:-o-linear-gradient(top, #fe96c9, #d51875 5%, #7b0a2e);
padding:0;
color:#eee;
font-size:20px;
text-align:center;
}
#header a {
color:#f3f3f3;
text-decoration:none;
font-weight:bold;
text-shadow:0 -1px 0 rgba(0,0,0,0.5);
}
#footer {
position:absolute;
bottom:0; left:0;
width:100%;
height:48px;
background-image:-webkit-gradient(linear, 0 0, 0 100%, color-stop(0, #999), color-stop(0.02, #666), color-stop(1, #222));
background-image:-moz-linear-gradient(top, #999, #666 2%, #222);
background-image:-o-linear-gradient(top, #999, #666 2%, #222);
padding:0;
border-top:1px solid #444;
}
#wrapper {
position:absolute; z-index:1;
top:45px; bottom:48px; left:0;
width:100%;
background:#555;
overflow:auto;
}
#scroller {
position:relative;
/* -webkit-touch-callout:none;*/
-webkit-tap-highlight-color:rgba(0,0,0,0);
float:left;
width:100%;
padding:0;
}
#scroller ul {
position:relative;
list-style:none;
padding:0;
margin:0;
width:100%;
text-align:left;
}
#scroller li {
padding:0 10px;
height:40px;
line-height:40px;
border-bottom:1px solid #ccc;
border-top:1px solid #fff;
background-color:#fafafa;
font-size:14px;
}
#scroller li > a {
display:block;
}
/**
*
* 下拉样式 Pull down styles
*
*/
#pullDown, #pullUp {
background:#fff;
height:40px;
line-height:40px;
padding:5px 10px;
border-bottom:1px solid #ccc;
font-weight:bold;
font-size:14px;
color:#888;
}
#pullDown .pullDownIcon, #pullUp .pullUpIcon {
display:block; float:left;
width:40px; height:40px;
background:url(pull-icon@2x.png) 0 0 no-repeat;
-webkit-background-size:40px 80px; background-size:40px 80px;
-webkit-transition-property:-webkit-transform;
-webkit-transition-duration:250ms;
}
#pullDown .pullDownIcon {
-webkit-transform:rotate(0deg) translateZ(0);
}
#pullUp .pullUpIcon {
-webkit-transform:rotate(-180deg) translateZ(0);
}
#pullDown.flip .pullDownIcon {
-webkit-transform:rotate(-180deg) translateZ(0);
}
#pullUp.flip .pullUpIcon {
-webkit-transform:rotate(0deg) translateZ(0);
}
#pullDown.loading .pullDownIcon, #pullUp.loading .pullUpIcon {
background-position:0 100%;
-webkit-transform:rotate(0deg) translateZ(0);
-webkit-transition-duration:0ms;
-webkit-animation-name:loading;
-webkit-animation-duration:2s;
-webkit-animation-iteration-count:infinite;
-webkit-animation-timing-function:linear;
}
@-webkit-keyframes loading {
from { -webkit-transform:rotate(0deg) translateZ(0); }
to { -webkit-transform:rotate(360deg) translateZ(0); }
}
</style>
</head>
<body>
<div id="header">
<a href="../db.html#page2">iScroll实例:下拉刷新,滚动翻页</a>
</div>
<div id="wrapper">
<div id="scroller">
<div id="pullDown">
<span class="pullDownIcon"></span><span class="pullDownLabel">下拉刷新...</span>
</div>
<ul id="thelist">
<li>Pretty row 1</li>
<li id="aaa">Pretty row 2</li>
<li>Pretty row 3</li>
<li>Pretty row 4</li>
<li>Pretty row 5</li>
<li>Pretty row 6</li>
<li>Pretty row 7</li>
<li>Pretty row 8</li>
<li>Pretty row 9</li>
<li>Pretty row 10</li>
<li>Pretty row 11</li>
<li>Pretty row 12</li>
<li>Pretty row 13</li>
<li>Pretty row 14</li>
<li>Pretty row 15</li>
<li>Pretty row 16</li>
<li>Pretty row 17</li>
<li>Pretty row 18</li>
<li>Pretty row 19</li>
<li>Pretty row 20</li>
<li>Pretty row 21</li>
<li>Pretty row 22</li>
<li>Pretty row 23</li>
<li>Pretty row 24</li>
<li>Pretty row 25</li>
<li>Pretty row 26</li>
<li>Pretty row 27</li>
<li>Pretty row 28</li>
<li>Pretty row 29</li>
<li>Pretty row 30</li>
<li>Pretty row 31</li>
<li>Pretty row 32</li>
<li>Pretty row 33</li>
<li>Pretty row 34</li>
<li>Pretty row 35</li>
<li>Pretty row 36</li>
<li>Pretty row 37</li>
<li>Pretty row 38</li>
<li>Pretty row 39</li>
<li>Pretty row 40</li>
</ul>
<div id="pullUp">
<span class="pullUpIcon"></span><span class="pullUpLabel">上拉加载更多...</span>
</div>
</div>
</div>
<div id="footer"></div>
</body>
</html>
/*!
* iScroll v4.2.5 ~ Copyright (c) 2012 Matteo Spinelli, http://cubiq.org
* Released under MIT license, http://cubiq.org/license
*/
(function(window, doc){
var m = Math,
dummyStyle = doc.createElement('div').style,
vendor = (function () {
var vendors = 't,webkitT,MozT,msT,OT'.split(','),
t,
i = 0,
l = vendors.length;
for ( ; i < l; i++ ) {
t = vendors[i] + 'ransform';
if ( t in dummyStyle ) {
return vendors[i].substr(0, vendors[i].length - 1);
}
}
return false;
})(),
cssVendor = vendor ? '-' + vendor.toLowerCase() + '-' : '',
// Style properties
transform = prefixStyle('transform'),
transitionProperty = prefixStyle('transitionProperty'),
transitionDuration = prefixStyle('transitionDuration'),
transformOrigin = prefixStyle('transformOrigin'),
transitionTimingFunction = prefixStyle('transitionTimingFunction'),
transitionDelay = prefixStyle('transitionDelay'),
// Browser capabilities
isAndroid = (/android/gi).test(navigator.appVersion),
isIDevice = (/iphone|ipad/gi).test(navigator.appVersion),
isTouchPad = (/hp-tablet/gi).test(navigator.appVersion),
has3d = prefixStyle('perspective') in dummyStyle,
hasTouch = 'ontouchstart' in window && !isTouchPad,
hasTransform = vendor !== false,
hasTransitionEnd = prefixStyle('transition') in dummyStyle,
RESIZE_EV = 'onorientationchange' in window ? 'orientationchange' : 'resize',
START_EV = hasTouch ? 'touchstart' : 'mousedown',
MOVE_EV = hasTouch ? 'touchmove' : 'mousemove',
END_EV = hasTouch ? 'touchend' : 'mouseup',
CANCEL_EV = hasTouch ? 'touchcancel' : 'mouseup',
TRNEND_EV = (function () {
if ( vendor === false ) return false;
var transitionEnd = {
'' : 'transitionend',
'webkit' : 'webkitTransitionEnd',
'Moz' : 'transitionend',
'O' : 'otransitionend',
'ms' : 'MSTransitionEnd'
};
return transitionEnd[vendor];
})(),
nextFrame = (function() {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) { return setTimeout(callback, 1); };
})(),
cancelFrame = (function () {
return window.cancelRequestAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.webkitCancelRequestAnimationFrame ||
window.mozCancelRequestAnimationFrame ||
window.oCancelRequestAnimationFrame ||
window.msCancelRequestAnimationFrame ||
clearTimeout;
})(),
// Helpers
translateZ = has3d ? ' translateZ(0)' : '',
// Constructor
iScroll = function (el, options) {
var that = this,
i;
that.wrapper = typeof el == 'object' ? el : doc.getElementById(el);
that.wrapper.style.overflow = 'hidden';
that.scroller = that.wrapper.children[0];
// Default options
that.options = {
hScroll: true,
vScroll: true,
x: 0,
y: 0,
bounce: true,
bounceLock: false,
momentum: true,
lockDirection: true,
useTransform: true,
useTransition: false,
topOffset: 0,
checkDOMChanges: false, // Experimental
handleClick: true,
// Scrollbar
hScrollbar: true,
vScrollbar: true,
fixedScrollbar: isAndroid,
hideScrollbar: isIDevice,
fadeScrollbar: isIDevice && has3d,
scrollbarClass: '',
// Zoom
zoom: false,
zoomMin: 1,
zoomMax: 4,
doubleTapZoom: 2,
wheelAction: 'scroll',
// Snap
snap: false,
snapThreshold: 1,
// Events
onRefresh: null,
onBeforeScrollStart: function (e) { e.preventDefault(); },
onScrollStart: null,
onBeforeScrollMove: null,
onScrollMove: null,
onBeforeScrollEnd: null,
onScrollEnd: null,
onTouchEnd: null,
onDestroy: null,
onZoomStart: null,
onZoom: null,
onZoomEnd: null
};
// User defined options
for (i in options) that.options[i] = options[i];
// Set starting position
that.x = that.options.x;
that.y = that.options.y;
// Normalize options
that.options.useTransform = hasTransform && that.options.useTransform;
that.options.hScrollbar = that.options.hScroll && that.options.hScrollbar;
that.options.vScrollbar = that.options.vScroll && that.options.vScrollbar;
that.options.zoom = that.options.useTransform && that.options.zoom;
that.options.useTransition = hasTransitionEnd && that.options.useTransition;
// Helpers FIX ANDROID BUG!
// translate3d and scale doesn't work together!
// Ignoring 3d ONLY WHEN YOU SET that.options.zoom
if ( that.options.zoom && isAndroid ){
translateZ = '';
}
// Set some default styles
that.scroller.style[transitionProperty] = that.options.useTransform ? cssVendor + 'transform' : 'top left';
that.scroller.style[transitionDuration] = '0';
that.scroller.style[transformOrigin] = '0 0';
if (that.options.useTransition) that.scroller.style[transitionTimingFunction] = 'cubic-bezier(0.33,0.66,0.66,1)';
if (that.options.useTransform) that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px)' + translateZ;
else that.scroller.style.cssText += ';position:absolute;top:' + that.y + 'px;left:' + that.x + 'px';
if (that.options.useTransition) that.options.fixedScrollbar = true;
that.refresh();
that._bind(RESIZE_EV, window);
that._bind(START_EV);
if (!hasTouch) {
if (that.options.wheelAction != 'none') {
that._bind('DOMMouseScroll');
that._bind('mousewheel');
}
}
if (that.options.checkDOMChanges) that.checkDOMTime = setInterval(function () {
that._checkDOMChanges();
}, 500);
};
// Prototype
iScroll.prototype = {
enabled: true,
x: 0,
y: 0,
steps: [],
scale: 1,
currPageX: 0, currPageY: 0,
pagesX: [], pagesY: [],
aniTime: null,
wheelZoomCount: 0,
handleEvent: function (e) {
var that = this;
switch(e.type) {
case START_EV:
if (!hasTouch && e.button !== 0) return;
that._start(e);
break;
case MOVE_EV: that._move(e); break;
case END_EV:
case CANCEL_EV: that._end(e); break;
case RESIZE_EV: that._resize(); break;
case 'DOMMouseScroll': case 'mousewheel': that._wheel(e); break;
case TRNEND_EV: that._transitionEnd(e); break;
}
},
_checkDOMChanges: function () {
if (this.moved || this.zoomed || this.animating ||
(this.scrollerW == this.scroller.offsetWidth * this.scale && this.scrollerH == this.scroller.offsetHeight * this.scale)) return;
this.refresh();
},
_scrollbar: function (dir) {
var that = this,
bar;
if (!that[dir + 'Scrollbar']) {
if (that[dir + 'ScrollbarWrapper']) {
if (hasTransform) that[dir + 'ScrollbarIndicator'].style[transform] = '';
that[dir + 'ScrollbarWrapper'].parentNode.removeChild(that[dir + 'ScrollbarWrapper']);
that[dir + 'ScrollbarWrapper'] = null;
that[dir + 'ScrollbarIndicator'] = null;
}
return;
}
if (!that[dir + 'ScrollbarWrapper']) {
// Create the scrollbar wrapper
bar = doc.createElement('div');
if (that.options.scrollbarClass) bar.className = that.options.scrollbarClass + dir.toUpperCase();
else bar.style.cssText = 'position:absolute;z-index:100;' + (dir == 'h' ? 'height:7px;bottom:1px;left:2px;right:' + (that.vScrollbar ? '7' : '2') + 'px' : 'width:7px;bottom:' + (that.hScrollbar ? '7' : '2') + 'px;top:2px;right:1px');
bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:opacity;' + cssVendor + 'transition-duration:' + (that.options.fadeScrollbar ? '350ms' : '0') + ';overflow:hidden;opacity:' + (that.options.hideScrollbar ? '0' : '1');
that.wrapper.appendChild(bar);
that[dir + 'ScrollbarWrapper'] = bar;
// Create the scrollbar indicator
bar = doc.createElement('div');
if (!that.options.scrollbarClass) {
bar.style.cssText = 'position:absolute;z-index:100;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);' + cssVendor + 'background-clip:padding-box;' + cssVendor + 'box-sizing:border-box;' + (dir == 'h' ? 'height:100%' : 'width:100%') + ';' + cssVendor + 'border-radius:3px;border-radius:3px';
}
bar.style.cssText += ';pointer-events:none;' + cssVendor + 'transition-property:' + cssVendor + 'transform;' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1);' + cssVendor + 'transition-duration:0;' + cssVendor + 'transform: translate(0,0)' + translateZ;
if (that.options.useTransition) bar.style.cssText += ';' + cssVendor + 'transition-timing-function:cubic-bezier(0.33,0.66,0.66,1)';
that[dir + 'ScrollbarWrapper'].appendChild(bar);
that[dir + 'ScrollbarIndicator'] = bar;
}
if (dir == 'h') {
that.hScrollbarSize = that.hScrollbarWrapper.clientWidth;
that.hScrollbarIndicatorSize = m.max(m.round(that.hScrollbarSize * that.hScrollbarSize / that.scrollerW), 8);
that.hScrollbarIndicator.style.width = that.hScrollbarIndicatorSize + 'px';
that.hScrollbarMaxScroll = that.hScrollbarSize - that.hScrollbarIndicatorSize;
that.hScrollbarProp = that.hScrollbarMaxScroll / that.maxScrollX;
} else {
that.vScrollbarSize = that.vScrollbarWrapper.clientHeight;
that.vScrollbarIndicatorSize = m.max(m.round(that.vScrollbarSize * that.vScrollbarSize / that.scrollerH), 8);
that.vScrollbarIndicator.style.height = that.vScrollbarIndicatorSize + 'px';
that.vScrollbarMaxScroll = that.vScrollbarSize - that.vScrollbarIndicatorSize;
that.vScrollbarProp = that.vScrollbarMaxScroll / that.maxScrollY;
}
// Reset position
that._scrollbarPos(dir, true);
},
_resize: function () {
var that = this;
setTimeout(function () { that.refresh(); }, isAndroid ? 200 : 0);
},
_pos: function (x, y) {
if (this.zoomed) return;
x = this.hScroll ? x : 0;
y = this.vScroll ? y : 0;
if (this.options.useTransform) {
this.scroller.style[transform] = 'translate(' + x + 'px,' + y + 'px) scale(' + this.scale + ')' + translateZ;
} else {
x = m.round(x);
y = m.round(y);
this.scroller.style.left = x + 'px';
this.scroller.style.top = y + 'px';
}
this.x = x;
this.y = y;
this._scrollbarPos('h');
this._scrollbarPos('v');
},
_scrollbarPos: function (dir, hidden) {
var that = this,
pos = dir == 'h' ? that.x : that.y,
size;
if (!that[dir + 'Scrollbar']) return;
pos = that[dir + 'ScrollbarProp'] * pos;
if (pos < 0) {
if (!that.options.fixedScrollbar) {
size = that[dir + 'ScrollbarIndicatorSize'] + m.round(pos * 3);
if (size < 8) size = 8;
that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
}
pos = 0;
} else if (pos > that[dir + 'ScrollbarMaxScroll']) {
if (!that.options.fixedScrollbar) {
size = that[dir + 'ScrollbarIndicatorSize'] - m.round((pos - that[dir + 'ScrollbarMaxScroll']) * 3);
if (size < 8) size = 8;
that[dir + 'ScrollbarIndicator'].style[dir == 'h' ? 'width' : 'height'] = size + 'px';
pos = that[dir + 'ScrollbarMaxScroll'] + (that[dir + 'ScrollbarIndicatorSize'] - size);
} else {
pos = that[dir + 'ScrollbarMaxScroll'];
}
}
that[dir + 'ScrollbarWrapper'].style[transitionDelay] = '0';
that[dir + 'ScrollbarWrapper'].style.opacity = hidden && that.options.hideScrollbar ? '0' : '1';
that[dir + 'ScrollbarIndicator'].style[transform] = 'translate(' + (dir == 'h' ? pos + 'px,0)' : '0,' + pos + 'px)') + translateZ;
},
_start: function (e) {
var that = this,
point = hasTouch ? e.touches[0] : e,
matrix, x, y,
c1, c2;
if (!that.enabled) return;
if (that.options.onBeforeScrollStart) that.options.onBeforeScrollStart.call(that, e);
if (that.options.useTransition || that.options.zoom) that._transitionTime(0);
that.moved = false;
that.animating = false;
that.zoomed = false;
that.distX = 0;
that.distY = 0;
that.absDistX = 0;
that.absDistY = 0;
that.dirX = 0;
that.dirY = 0;
// Gesture start
if (that.options.zoom && hasTouch && e.touches.length > 1) {
c1 = m.abs(e.touches[0].pageX-e.touches[1].pageX);
c2 = m.abs(e.touches[0].pageY-e.touches[1].pageY);
that.touchesDistStart = m.sqrt(c1 * c1 + c2 * c2);
that.originX = m.abs(e.touches[0].pageX + e.touches[1].pageX - that.wrapperOffsetLeft * 2) / 2 - that.x;
that.originY = m.abs(e.touches[0].pageY + e.touches[1].pageY - that.wrapperOffsetTop * 2) / 2 - that.y;
if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
}
if (that.options.momentum) {
if (that.options.useTransform) {
// Very lame general purpose alternative to CSSMatrix
matrix = getComputedStyle(that.scroller, null)[transform].replace(/[^0-9\-.,]/g, '').split(',');
x = +(matrix[12] || matrix[4]);
y = +(matrix[13] || matrix[5]);
} else {
x = +getComputedStyle(that.scroller, null).left.replace(/[^0-9-]/g, '');
y = +getComputedStyle(that.scroller, null).top.replace(/[^0-9-]/g, '');
}
if (x != that.x || y != that.y) {
if (that.options.useTransition) that._unbind(TRNEND_EV);
else cancelFrame(that.aniTime);
that.steps = [];
that._pos(x, y);
if (that.options.onScrollEnd) that.options.onScrollEnd.call(that);
}
}
that.absStartX = that.x; // Needed by snap threshold
that.absStartY = that.y;
that.startX = that.x;
that.startY = that.y;
that.pointX = point.pageX;
that.pointY = point.pageY;
that.startTime = e.timeStamp || Date.now();
if (that.options.onScrollStart) that.options.onScrollStart.call(that, e);
that._bind(MOVE_EV, window);
that._bind(END_EV, window);
that._bind(CANCEL_EV, window);
},
_move: function (e) {
var that = this,
point = hasTouch ? e.touches[0] : e,
deltaX = point.pageX - that.pointX,
deltaY = point.pageY - that.pointY,
newX = that.x + deltaX,
newY = that.y + deltaY,
c1, c2, scale,
timestamp = e.timeStamp || Date.now();
if (that.options.onBeforeScrollMove) that.options.onBeforeScrollMove.call(that, e);
// Zoom
if (that.options.zoom && hasTouch && e.touches.length > 1) {
c1 = m.abs(e.touches[0].pageX - e.touches[1].pageX);
c2 = m.abs(e.touches[0].pageY - e.touches[1].pageY);
that.touchesDist = m.sqrt(c1*c1+c2*c2);
that.zoomed = true;
scale = 1 / that.touchesDistStart * that.touchesDist * this.scale;
if (scale < that.options.zoomMin) scale = 0.5 * that.options.zoomMin * Math.pow(2.0, scale / that.options.zoomMin);
else if (scale > that.options.zoomMax) scale = 2.0 * that.options.zoomMax * Math.pow(0.5, that.options.zoomMax / scale);
that.lastScale = scale / this.scale;
newX = this.originX - this.originX * that.lastScale + this.x;
newY = this.originY - this.originY * that.lastScale + this.y;
this.scroller.style[transform] = 'translate(' + newX + 'px,' + newY + 'px) scale(' + scale + ')' + translateZ;
if (that.options.onZoom) that.options.onZoom.call(that, e);
return;
}
that.pointX = point.pageX;
that.pointY = point.pageY;
// Slow down if outside of the boundaries
if (newX > 0 || newX < that.maxScrollX) {
newX = that.options.bounce ? that.x + (deltaX / 2) : newX >= 0 || that.maxScrollX >= 0 ? 0 : that.maxScrollX;
}
if (newY > that.minScrollY || newY < that.maxScrollY) {
newY = that.options.bounce ? that.y + (deltaY / 2) : newY >= that.minScrollY || that.maxScrollY >= 0 ? that.minScrollY : that.maxScrollY;
}
that.distX += deltaX;
that.distY += deltaY;
that.absDistX = m.abs(that.distX);
that.absDistY = m.abs(that.distY);
if (that.absDistX < 6 && that.absDistY < 6) {
return;
}
// Lock direction
if (that.options.lockDirection) {
if (that.absDistX > that.absDistY + 5) {
newY = that.y;
deltaY = 0;
} else if (that.absDistY > that.absDistX + 5) {
newX = that.x;
deltaX = 0;
}
}
that.moved = true;
that._pos(newX, newY);
that.dirX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;
that.dirY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;
if (timestamp - that.startTime > 300) {
that.startTime = timestamp;
that.startX = that.x;
that.startY = that.y;
}
if (that.options.onScrollMove) that.options.onScrollMove.call(that, e);
},
_end: function (e) {
if (hasTouch && e.touches.length !== 0) return;
var that = this,
point = hasTouch ? e.changedTouches[0] : e,
target, ev,
momentumX = { dist:0, time:0 },
momentumY = { dist:0, time:0 },
duration = (e.timeStamp || Date.now()) - that.startTime,
newPosX = that.x,
newPosY = that.y,
distX, distY,
newDuration,
snap,
scale;
that._unbind(MOVE_EV, window);
that._unbind(END_EV, window);
that._unbind(CANCEL_EV, window);
if (that.options.onBeforeScrollEnd) that.options.onBeforeScrollEnd.call(that, e);
if (that.zoomed) {
scale = that.scale * that.lastScale;
scale = Math.max(that.options.zoomMin, scale);
scale = Math.min(that.options.zoomMax, scale);
that.lastScale = scale / that.scale;
that.scale = scale;
that.x = that.originX - that.originX * that.lastScale + that.x;
that.y = that.originY - that.originY * that.lastScale + that.y;
that.scroller.style[transitionDuration] = '200ms';
that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + that.scale + ')' + translateZ;
that.zoomed = false;
that.refresh();
if (that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
return;
}
if (!that.moved) {
if (hasTouch) {
if (that.doubleTapTimer && that.options.zoom) {
// Double tapped
clearTimeout(that.doubleTapTimer);
that.doubleTapTimer = null;
if (that.options.onZoomStart) that.options.onZoomStart.call(that, e);
that.zoom(that.pointX, that.pointY, that.scale == 1 ? that.options.doubleTapZoom : 1);
if (that.options.onZoomEnd) {
setTimeout(function() {
that.options.onZoomEnd.call(that, e);
}, 200); // 200 is default zoom duration
}
} else if (this.options.handleClick) {
that.doubleTapTimer = setTimeout(function () {
that.doubleTapTimer = null;
// Find the last touched element
target = point.target;
while (target.nodeType != 1) target = target.parentNode;
if (target.tagName != 'SELECT' && target.tagName != 'INPUT' && target.tagName != 'TEXTAREA') {
ev = doc.createEvent('MouseEvents');
ev.initMouseEvent('click', true, true, e.view, 1,
point.screenX, point.screenY, point.clientX, point.clientY,
e.ctrlKey, e.altKey, e.shiftKey, e.metaKey,
0, null);
ev._fake = true;
target.dispatchEvent(ev);
}
}, that.options.zoom ? 250 : 0);
}
}
that._resetPos(400);
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
return;
}
if (duration < 300 && that.options.momentum) {
momentumX = newPosX ? that._momentum(newPosX - that.startX, duration, -that.x, that.scrollerW - that.wrapperW + that.x, that.options.bounce ? that.wrapperW : 0) : momentumX;
momentumY = newPosY ? that._momentum(newPosY - that.startY, duration, -that.y, (that.maxScrollY < 0 ? that.scrollerH - that.wrapperH + that.y - that.minScrollY : 0), that.options.bounce ? that.wrapperH : 0) : momentumY;
newPosX = that.x + momentumX.dist;
newPosY = that.y + momentumY.dist;
if ((that.x > 0 && newPosX > 0) || (that.x < that.maxScrollX && newPosX < that.maxScrollX)) momentumX = { dist:0, time:0 };
if ((that.y > that.minScrollY && newPosY > that.minScrollY) || (that.y < that.maxScrollY && newPosY < that.maxScrollY)) momentumY = { dist:0, time:0 };
}
if (momentumX.dist || momentumY.dist) {
newDuration = m.max(m.max(momentumX.time, momentumY.time), 10);
// Do we need to snap?
if (that.options.snap) {
distX = newPosX - that.absStartX;
distY = newPosY - that.absStartY;
if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) { that.scrollTo(that.absStartX, that.absStartY, 200); }
else {
snap = that._snap(newPosX, newPosY);
newPosX = snap.x;
newPosY = snap.y;
newDuration = m.max(snap.time, newDuration);
}
}
that.scrollTo(m.round(newPosX), m.round(newPosY), newDuration);
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
return;
}
// Do we need to snap?
if (that.options.snap) {
distX = newPosX - that.absStartX;
distY = newPosY - that.absStartY;
if (m.abs(distX) < that.options.snapThreshold && m.abs(distY) < that.options.snapThreshold) that.scrollTo(that.absStartX, that.absStartY, 200);
else {
snap = that._snap(that.x, that.y);
if (snap.x != that.x || snap.y != that.y) that.scrollTo(snap.x, snap.y, snap.time);
}
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
return;
}
that._resetPos(200);
if (that.options.onTouchEnd) that.options.onTouchEnd.call(that, e);
},
_resetPos: function (time) {
var that = this,
resetX = that.x >= 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x,
resetY = that.y >= that.minScrollY || that.maxScrollY > 0 ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
if (resetX == that.x && resetY == that.y) {
if (that.moved) {
that.moved = false;
if (that.options.onScrollEnd) that.options.onScrollEnd.call(that); // Execute custom code on scroll end
}
if (that.hScrollbar && that.options.hideScrollbar) {
if (vendor == 'webkit') that.hScrollbarWrapper.style[transitionDelay] = '300ms';
that.hScrollbarWrapper.style.opacity = '0';
}
if (that.vScrollbar && that.options.hideScrollbar) {
if (vendor == 'webkit') that.vScrollbarWrapper.style[transitionDelay] = '300ms';
that.vScrollbarWrapper.style.opacity = '0';
}
return;
}
that.scrollTo(resetX, resetY, time || 0);
},
_wheel: function (e) {
var that = this,
wheelDeltaX, wheelDeltaY,
deltaX, deltaY,
deltaScale;
if ('wheelDeltaX' in e) {
wheelDeltaX = e.wheelDeltaX / 12;
wheelDeltaY = e.wheelDeltaY / 12;
} else if('wheelDelta' in e) {
wheelDeltaX = wheelDeltaY = e.wheelDelta / 12;
} else if ('detail' in e) {
wheelDeltaX = wheelDeltaY = -e.detail * 3;
} else {
return;
}
if (that.options.wheelAction == 'zoom') {
deltaScale = that.scale * Math.pow(2, 1/3 * (wheelDeltaY ? wheelDeltaY / Math.abs(wheelDeltaY) : 0));
if (deltaScale < that.options.zoomMin) deltaScale = that.options.zoomMin;
if (deltaScale > that.options.zoomMax) deltaScale = that.options.zoomMax;
if (deltaScale != that.scale) {
if (!that.wheelZoomCount && that.options.onZoomStart) that.options.onZoomStart.call(that, e);
that.wheelZoomCount++;
that.zoom(e.pageX, e.pageY, deltaScale, 400);
setTimeout(function() {
that.wheelZoomCount--;
if (!that.wheelZoomCount && that.options.onZoomEnd) that.options.onZoomEnd.call(that, e);
}, 400);
}
return;
}
deltaX = that.x + wheelDeltaX;
deltaY = that.y + wheelDeltaY;
if (deltaX > 0) deltaX = 0;
else if (deltaX < that.maxScrollX) deltaX = that.maxScrollX;
if (deltaY > that.minScrollY) deltaY = that.minScrollY;
else if (deltaY < that.maxScrollY) deltaY = that.maxScrollY;
if (that.maxScrollY < 0) {
that.scrollTo(deltaX, deltaY, 0);
}
},
_transitionEnd: function (e) {
var that = this;
if (e.target != that.scroller) return;
that._unbind(TRNEND_EV);
that._startAni();
},
/**
*
* Utilities
*
*/
_startAni: function () {
var that = this,
startX = that.x, startY = that.y,
startTime = Date.now(),
step, easeOut,
animate;
if (that.animating) return;
if (!that.steps.length) {
that._resetPos(400);
return;
}
step = that.steps.shift();
if (step.x == startX && step.y == startY) step.time = 0;
that.animating = true;
that.moved = true;
if (that.options.useTransition) {
that._transitionTime(step.time);
that._pos(step.x, step.y);
that.animating = false;
if (step.time) that._bind(TRNEND_EV);
else that._resetPos(0);
return;
}
animate = function () {
var now = Date.now(),
newX, newY;
if (now >= startTime + step.time) {
that._pos(step.x, step.y);
that.animating = false;
if (that.options.onAnimationEnd) that.options.onAnimationEnd.call(that); // Execute custom code on animation end
that._startAni();
return;
}
now = (now - startTime) / step.time - 1;
easeOut = m.sqrt(1 - now * now);
newX = (step.x - startX) * easeOut + startX;
newY = (step.y - startY) * easeOut + startY;
that._pos(newX, newY);
if (that.animating) that.aniTime = nextFrame(animate);
};
animate();
},
_transitionTime: function (time) {
time += 'ms';
this.scroller.style[transitionDuration] = time;
if (this.hScrollbar) this.hScrollbarIndicator.style[transitionDuration] = time;
if (this.vScrollbar) this.vScrollbarIndicator.style[transitionDuration] = time;
},
_momentum: function (dist, time, maxDistUpper, maxDistLower, size) {
var deceleration = 0.0006,
speed = m.abs(dist) / time,
newDist = (speed * speed) / (2 * deceleration),
newTime = 0, outsideDist = 0;
// Proportinally reduce speed if we are outside of the boundaries
if (dist > 0 && newDist > maxDistUpper) {
outsideDist = size / (6 / (newDist / speed * deceleration));
maxDistUpper = maxDistUpper + outsideDist;
speed = speed * maxDistUpper / newDist;
newDist = maxDistUpper;
} else if (dist < 0 && newDist > maxDistLower) {
outsideDist = size / (6 / (newDist / speed * deceleration));
maxDistLower = maxDistLower + outsideDist;
speed = speed * maxDistLower / newDist;
newDist = maxDistLower;
}
newDist = newDist * (dist < 0 ? -1 : 1);
newTime = speed / deceleration;
return { dist: newDist, time: m.round(newTime) };
},
_offset: function (el) {
var left = -el.offsetLeft,
top = -el.offsetTop;
while (el = el.offsetParent) {
left -= el.offsetLeft;
top -= el.offsetTop;
}
if (el != this.wrapper) {
left *= this.scale;
top *= this.scale;
}
return { left: left, top: top };
},
_snap: function (x, y) {
var that = this,
i, l,
page, time,
sizeX, sizeY;
// Check page X
page = that.pagesX.length - 1;
for (i=0, l=that.pagesX.length; i<l; i++) {
if (x >= that.pagesX[i]) {
page = i;
break;
}
}
if (page == that.currPageX && page > 0 && that.dirX < 0) page--;
x = that.pagesX[page];
sizeX = m.abs(x - that.pagesX[that.currPageX]);
sizeX = sizeX ? m.abs(that.x - x) / sizeX * 500 : 0;
that.currPageX = page;
// Check page Y
page = that.pagesY.length-1;
for (i=0; i<page; i++) {
if (y >= that.pagesY[i]) {
page = i;
break;
}
}
if (page == that.currPageY && page > 0 && that.dirY < 0) page--;
y = that.pagesY[page];
sizeY = m.abs(y - that.pagesY[that.currPageY]);
sizeY = sizeY ? m.abs(that.y - y) / sizeY * 500 : 0;
that.currPageY = page;
// Snap with constant speed (proportional duration)
time = m.round(m.max(sizeX, sizeY)) || 200;
return { x: x, y: y, time: time };
},
_bind: function (type, el, bubble) {
(el || this.scroller).addEventListener(type, this, !!bubble);
},
_unbind: function (type, el, bubble) {
(el || this.scroller).removeEventListener(type, this, !!bubble);
},
/**
*
* Public methods
*
*/
destroy: function () {
var that = this;
that.scroller.style[transform] = '';
// Remove the scrollbars
that.hScrollbar = false;
that.vScrollbar = false;
that._scrollbar('h');
that._scrollbar('v');
// Remove the event listeners
that._unbind(RESIZE_EV, window);
that._unbind(START_EV);
that._unbind(MOVE_EV, window);
that._unbind(END_EV, window);
that._unbind(CANCEL_EV, window);
if (!that.options.hasTouch) {
that._unbind('DOMMouseScroll');
that._unbind('mousewheel');
}
if (that.options.useTransition) that._unbind(TRNEND_EV);
if (that.options.checkDOMChanges) clearInterval(that.checkDOMTime);
if (that.options.onDestroy) that.options.onDestroy.call(that);
},
refresh: function () {
var that = this,
offset,
i, l,
els,
pos = 0,
page = 0;
if (that.scale < that.options.zoomMin) that.scale = that.options.zoomMin;
that.wrapperW = that.wrapper.clientWidth || 1;
that.wrapperH = that.wrapper.clientHeight || 1;
that.minScrollY = -that.options.topOffset || 0;
that.scrollerW = m.round(that.scroller.offsetWidth * that.scale);
that.scrollerH = m.round((that.scroller.offsetHeight + that.minScrollY) * that.scale);
that.maxScrollX = that.wrapperW - that.scrollerW;
that.maxScrollY = that.wrapperH - that.scrollerH + that.minScrollY;
that.dirX = 0;
that.dirY = 0;
if (that.options.onRefresh) that.options.onRefresh.call(that);
that.hScroll = that.options.hScroll && that.maxScrollX < 0;
that.vScroll = that.options.vScroll && (!that.options.bounceLock && !that.hScroll || that.scrollerH > that.wrapperH);
that.hScrollbar = that.hScroll && that.options.hScrollbar;
that.vScrollbar = that.vScroll && that.options.vScrollbar && that.scrollerH > that.wrapperH;
offset = that._offset(that.wrapper);
that.wrapperOffsetLeft = -offset.left;
that.wrapperOffsetTop = -offset.top;
// Prepare snap
if (typeof that.options.snap == 'string') {
that.pagesX = [];
that.pagesY = [];
els = that.scroller.querySelectorAll(that.options.snap);
for (i=0, l=els.length; i<l; i++) {
pos = that._offset(els[i]);
pos.left += that.wrapperOffsetLeft;
pos.top += that.wrapperOffsetTop;
that.pagesX[i] = pos.left < that.maxScrollX ? that.maxScrollX : pos.left * that.scale;
that.pagesY[i] = pos.top < that.maxScrollY ? that.maxScrollY : pos.top * that.scale;
}
} else if (that.options.snap) {
that.pagesX = [];
while (pos >= that.maxScrollX) {
that.pagesX[page] = pos;
pos = pos - that.wrapperW;
page++;
}
if (that.maxScrollX%that.wrapperW) that.pagesX[that.pagesX.length] = that.maxScrollX - that.pagesX[that.pagesX.length-1] + that.pagesX[that.pagesX.length-1];
pos = 0;
page = 0;
that.pagesY = [];
while (pos >= that.maxScrollY) {
that.pagesY[page] = pos;
pos = pos - that.wrapperH;
page++;
}
if (that.maxScrollY%that.wrapperH) that.pagesY[that.pagesY.length] = that.maxScrollY - that.pagesY[that.pagesY.length-1] + that.pagesY[that.pagesY.length-1];
}
// Prepare the scrollbars
that._scrollbar('h');
that._scrollbar('v');
if (!that.zoomed) {
that.scroller.style[transitionDuration] = '0';
that._resetPos(400);
}
},
scrollTo: function (x, y, time, relative) {
var that = this,
step = x,
i, l;
that.stop();
if (!step.length) step = [{ x: x, y: y, time: time, relative: relative }];
for (i=0, l=step.length; i<l; i++) {
if (step[i].relative) { step[i].x = that.x - step[i].x; step[i].y = that.y - step[i].y; }
that.steps.push({ x: step[i].x, y: step[i].y, time: step[i].time || 0 });
}
that._startAni();
},
scrollToElement: function (el, time) {
var that = this, pos;
el = el.nodeType ? el : that.scroller.querySelector(el);
if (!el) return;
pos = that._offset(el);
pos.left += that.wrapperOffsetLeft;
pos.top += that.wrapperOffsetTop;
pos.left = pos.left > 0 ? 0 : pos.left < that.maxScrollX ? that.maxScrollX : pos.left;
pos.top = pos.top > that.minScrollY ? that.minScrollY : pos.top < that.maxScrollY ? that.maxScrollY : pos.top;
time = time === undefined ? m.max(m.abs(pos.left)*2, m.abs(pos.top)*2) : time;
that.scrollTo(pos.left, pos.top, time);
},
scrollToPage: function (pageX, pageY, time) {
var that = this, x, y;
time = time === undefined ? 400 : time;
if (that.options.onScrollStart) that.options.onScrollStart.call(that);
if (that.options.snap) {
pageX = pageX == 'next' ? that.currPageX+1 : pageX == 'prev' ? that.currPageX-1 : pageX;
pageY = pageY == 'next' ? that.currPageY+1 : pageY == 'prev' ? that.currPageY-1 : pageY;
pageX = pageX < 0 ? 0 : pageX > that.pagesX.length-1 ? that.pagesX.length-1 : pageX;
pageY = pageY < 0 ? 0 : pageY > that.pagesY.length-1 ? that.pagesY.length-1 : pageY;
that.currPageX = pageX;
that.currPageY = pageY;
x = that.pagesX[pageX];
y = that.pagesY[pageY];
} else {
x = -that.wrapperW * pageX;
y = -that.wrapperH * pageY;
if (x < that.maxScrollX) x = that.maxScrollX;
if (y < that.maxScrollY) y = that.maxScrollY;
}
that.scrollTo(x, y, time);
},
disable: function () {
this.stop();
this._resetPos(0);
this.enabled = false;
// If disabled after touchstart we make sure that there are no left over events
this._unbind(MOVE_EV, window);
this._unbind(END_EV, window);
this._unbind(CANCEL_EV, window);
},
enable: function () {
this.enabled = true;
},
stop: function () {
if (this.options.useTransition) this._unbind(TRNEND_EV);
else cancelFrame(this.aniTime);
this.steps = [];
this.moved = false;
this.animating = false;
},
zoom: function (x, y, scale, time) {
var that = this,
relScale = scale / that.scale;
if (!that.options.useTransform) return;
that.zoomed = true;
time = time === undefined ? 200 : time;
x = x - that.wrapperOffsetLeft - that.x;
y = y - that.wrapperOffsetTop - that.y;
that.x = x - x * relScale + that.x;
that.y = y - y * relScale + that.y;
that.scale = scale;
that.refresh();
that.x = that.x > 0 ? 0 : that.x < that.maxScrollX ? that.maxScrollX : that.x;
that.y = that.y > that.minScrollY ? that.minScrollY : that.y < that.maxScrollY ? that.maxScrollY : that.y;
that.scroller.style[transitionDuration] = time + 'ms';
that.scroller.style[transform] = 'translate(' + that.x + 'px,' + that.y + 'px) scale(' + scale + ')' + translateZ;
that.zoomed = false;
},
isReady: function () {
return !this.moved && !this.zoomed && !this.animating;
}
};
function prefixStyle (style) {
if ( vendor === '' ) return style;
style = style.charAt(0).toUpperCase() + style.substr(1);
return vendor + style;
}
dummyStyle = null; // for the sake of it
if (typeof exports !== 'undefined') {
module.exports = iScroll
}
else window.iScroll = iScroll;
})(window, document);
/*------------- S 默认必须样式 -------------*/
/**
*
* 下拉样式 Pull down styles
*
*/
#pullDown, #pullUp {
background:#fff;
height:40px;
line-height:40px;
padding:5px 10px;
border-bottom:1px solid #ccc;
font-weight:bold;
font-size:14px;
color:#888;
}
#pullDown .pullDownIcon, #pullUp .pullUpIcon {
display:block; float:left;
width:40px; height:40px;
background:url(~@/lib/iscroll/pull-icon@2x.png) 0 0 no-repeat;
-webkit-background-size:40px 80px; background-size:40px 80px;
-webkit-transition-property:-webkit-transform;
-webkit-transition-duration:250ms;
}
#pullDown .pullDownIcon {
-webkit-transform:rotate(0deg) translateZ(0);
}
#pullUp .pullUpIcon {
-webkit-transform:rotate(-180deg) translateZ(0);
}
#pullDown.flip .pullDownIcon {
-webkit-transform:rotate(-180deg) translateZ(0);
}
#pullUp.flip .pullUpIcon {
-webkit-transform:rotate(0deg) translateZ(0);
}
#pullDown.loading .pullDownIcon, #pullUp.loading .pullUpIcon {
background-position:0 100%;
-webkit-transform:rotate(0deg) translateZ(0);
-webkit-transition-duration:0ms;
-webkit-animation-name:loading;
-webkit-animation-duration:2s;
-webkit-animation-iteration-count:infinite;
-webkit-animation-timing-function:linear;
}
@-webkit-keyframes loading {
from { -webkit-transform:rotate(0deg) translateZ(0); }
to { -webkit-transform:rotate(360deg) translateZ(0); }
}
/*------------- E 默认必须样式 -------------*/
/*------------- S 以下css主要是仿IOS滚动条样式(可选样式) -------------*/
/**
* Horizontal Scrollbar
*/
.myScrollbarH {
position:absolute;
z-index:100;
height:7px;
bottom:1px;
left:2px;
right:7px
}
.myScrollbarH > div {
height:100%;
}
/**
* Vertical Scrollbar
*/
.myScrollbarV {
position:absolute;
z-index:100;
width:7px;bottom:7px;top:2px;right:1px
}
.myScrollbarV > div {
width:100%;
}
/**
* Both Scrollbars
*/
.myScrollbarH > div,
.myScrollbarV > div {
position:absolute;
z-index:100;
/* The following is probably what you want to customize */
-webkit-box-sizing:border-box;
-moz-box-sizing:border-box;
-o-box-sizing:border-box;
box-sizing:border-box;
border-width:3px;
-webkit-border-image:url(~@/lib/iscroll/scrollbar.png) 6 6 6 6;
-moz-border-image:url(~@/lib/iscroll/scrollbar.png) 6 6 6 6;
-o-border-image:url(~@/lib/iscroll/scrollbar.png) 6 6 6 6;
border-image:url(~@/lib/iscroll/scrollbar.png) 6 6 6 6;
}
/*------------- E 以上css主要是仿IOS滚动条样式 -------------*/
# mescroll
## mescroll -- 精致的下拉刷新和上拉加载js框架 (JS framework for pull-refresh and pull-up-loading)
## http://www.mescroll.com
1. 原生js, 支持vue, 不依赖jquery,zepto
2. 一套代码多端运行. 完美运行于android,iOS,手机浏览器,兼容PC主流浏览器
3. 参数自由搭配, 随心定制, 轻松拓展
4. 主流APP案例, 丰富经典
5. MIT协议, 免费商用, 欢迎pull requests ~
6. <a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=1067896895dabdf6cf11f4decb0be8bfd3687d3d208730bf2757238ba1948469">mescroll交流群: 633126761</a>
## 目录:
* <a href="https://github.com/mescroll/mescroll/releases" target="_blank">最新版本:1.3.8 (2018-09-29) 重要升级</a> <br/><br/>
* <a href="#功能亮点-">功能亮点 </a> <br/>
* <a href="#快速入门-">快速入门 </a> <br/>
* <a href="#图片懒加载-">图片懒加载 </a> <br/>
* <a href="#vue-cli">vue单文件 (理解原理)</a>
* <a href="#mescroll组件" target="_blank">mescroll组件 (推荐使用)</a>
* <a href="https://github.com/mescroll/mescroll/tree/master/vue-demo" target="_blank">vue-cli demo (建议看看)</a>
* <a href="http://www.mescroll.com/preview.html?name=list-products-vue" target="_blank">vue在线示例 (了解即可)</a>
* <a href="#基础案例-base-demos-"><b>基础案例 base demos</b></a> <br/>
* <a href="#中级案例-intermediate-demos-"><b>中级案例 intermediate demos</b></a> <br/>
* <a href="#高级案例-senior-demos-"><b>高级案例 senior demos</b></a> <br/><br/>
* <a href="#下载基础中级案例源码-">下载基础中级案例 </a> <br/>
* <a href="#获取高级案例源码-">获取高级案例 </a> <br/><br/>
* <a href="#api文档-">API文档 </a> <br/>
* <a href="#常用方法-">常用方法 </a> <br/>
* <a href="#其他方法-">其他方法 </a> <br/><br/>
* <a href="http://www.mescroll.com/qa.html?v=0929">常见问题 </a> <br/>
* <a href="http://www.mescroll.com/reward.html#tagRank">打赏排行榜 </a> <br/>
## 功能亮点 :
1. 自动判断和提示列表无任何数据或无更多数据
2. 支持监听列表滚动事件,无需手动判断处理列表的页码,时间等变量
3. 可指定列表滚动到任何位置,附带平滑效果一键滚动到顶部或底部
4. 可配置列表数据不满屏时,自动加载下一页
5. 一个界面可支持多个下拉刷新,上拉加载
6. 可临时锁定下拉刷新和上拉加载
7. 支持图片懒加载,可配置各种占位图与显示动画,上手超简单
## NPM
#### 特别感谢 @<a href="https://github.com/channg">channg</a> 帮忙整理发布NPM
```
npm install --save mescroll.js //不要使用cnpm安装
```
## 快速入门 :
#### 1. 引用 **mescroll.min.css** , **mescroll.min.js**
#### 2. 拷贝以下布局结构:
```
<div id="mescroll" class="mescroll"> //id可以改,而"mescroll"的class不能删
<div> //这个div不能删, 可以改成ul或者其他容器标签.
//内容...
</div>
</div>
```
#### 3. 固定mescroll的div高度. 推荐通过定位的方式,简单快捷: <a href="http://www.mescroll.com/qa.html#q2">(点此查看其他方法)</a>
```
.mescroll{
position: fixed;
top: 44px;
bottom: 0;
height: auto; /*如设置bottom:50px,则需height:auto才能生效*/
}
```
#### 4. 创建MeScroll对象:
```
var mescroll = new MeScroll("mescroll", { //第一个参数"mescroll"对应上面布局结构div的id (1.3.5版本支持传入dom对象)
down: {
callback: downCallback //下拉刷新的回调,别写成downCallback(),多了括号就自动执行方法了
},
up: {
callback: upCallback, //上拉加载回调,简写callback:function(page){upCallback(page);}
//以下是一些常用的配置,当然不写也可以的.
page: {
num: 0, //当前页 默认0,回调之前会加1; 即callback(page)会从1开始
size: 10, //每页数据条数,默认10
},
htmlNodata: '<p class="upwarp-nodata">亲,没有更多数据了~</p>',
noMoreSize: 5, //如果列表已无数据,可设置列表的总数量要大于5才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看.这就是为什么无更多数据 有时候不显示的原因了.
toTop: {
//回到顶部按钮
src: "../img/mescroll-totop.png", //图片路径,默认null,支持网络图
offset: 1000, //列表滚动1000px才显示回到顶部按钮
},
empty: {
//列表第一页无任何数据时,显示的空提示布局; 需配置warpId才显示
warpId: "xxid", //父布局的id (1.3.5版本支持传入dom元素)
icon: "../img/mescroll-empty.png", //图标,默认null,支持网络图
tip: "暂无相关数据~" //提示
},
lazyLoad: {
use: true, // 是否开启懒加载,默认false
attr: 'imgurl', // 网络图片地址的属性名 (图片加载成功会自动移除改属性): <img imgurl='网络图 src='占位图''/>
offset: 200 // 超出可视区域多少px的图片仍可触发懒加载 默认200. 目的是提前加载可视区域外的部分图片
}
}
});
```
###### 温馨提示:
###### 1. 如果您的下拉刷新是重置列表数据,那么down完全可以不用配置,具体用法参考<a class="blue" href="http://www.mescroll.com/demo.html?v=0929">第一个基础案例</a>
###### 解析: down内部默认调用的是mescroll.resetUpScroll(),而resetUpScroll会将page.num=1,再触发up.callback,从而实现刷新列表数据
###### 2. 如果您的项目是在iOS的微信,QQ,Safari等浏览器访问的,建议配置up的isBounce为false,禁止ios的回弹效果; <a class="blue" href="http://www.mescroll.com/qa.html?v=0929#q10">解析(必读)</a>
#### 5. 处理回调:
```
//下拉刷新的回调
function downCallback(){
$.ajax({
url: 'xxxxxx',
success: function(data){
//联网成功的回调,隐藏下拉刷新的状态;
mescroll.endSuccess();//无参,注意此处无参
//设置数据
//setXxxx(data);//自行实现 TODO
},
error: function(data){
//联网失败的回调,隐藏下拉刷新的状态
mescroll.endErr();
}
});
}
//上拉加载的回调 page = {num:1, size:10}; num:当前页 从1开始, size:每页数据条数
function upCallback(page){
$.ajax({
url: 'xxxxxx?num='+ page.num +"&size="+ page.size,
success: function(curPageData){
//联网成功的回调,隐藏下拉刷新和上拉加载的状态;
//mescroll会根据传的参数,自动判断列表如果无任何数据,则提示空;列表无下一页数据,则提示无更多数据;
//方法一(推荐): 后台接口有返回列表的总页数 totalPage
//必传参数(当前页的数据个数, 总页数)
//mescroll.endByPage(curPageData.length, totalPage);
//方法二(推荐): 后台接口有返回列表的总数据量 totalSize
//必传参数(当前页的数据个数, 总数据量)
//mescroll.endBySize(curPageData.length, totalSize);
//方法三(推荐): 您有其他方式知道是否有下一页 hasNext
//必传参数(当前页的数据个数, 是否有下一页true/false)
//mescroll.endSuccess(curPageData.length, hasNext);
//方法四 (不推荐),会存在一个小问题:比如列表共有20条数据,每页加载10条,共2页.
//如果只根据当前页的数据个数判断,则需翻到第三页才会知道无更多数据
//如果传了hasNext,则翻到第二页即可显示无更多数据.
//mescroll.endSuccess(curPageData.length);
//提示:curPageData.length必传的原因:
// 1.使配置的noMoreSize生效
// 2.判断是否有下一页的首要依据: 当传的值小于page.size时,则一定会认为无更多数据. 比传入的totalPage, totalSize, hasNext具有更高的判断优先级
// 3.当传的值等于page.size时,才会取totalPage, totalSize, hasNext判断是否有下一页. 传totalPage, totalSize, hasNext主要目的是避免方法四描述的小问题
//设置列表数据
//setListData(curPageData);//自行实现 TODO
},
error: function(){
//联网失败的回调,隐藏下拉刷新和上拉加载的状态
mescroll.endErr();
}
});
}
```
--- 以上为mescroll最基本的用法,强烈建议您下载并查看 <a href="#基础案例-base-demos-">mescroll基础案例</a> , 发现mescroll更强大的功能 ~<br/>
--- 基础案例一共6个, 每个案例3分钟, 一共花您18分钟; 这18分钟您将了解mescroll在不同情况下应如何快速配置 ~<br/>
--- 特别建议您, 手动改改 <a href="http://www.mescroll.com/preview.html?name=mescroll-options">mescroll-options</a> 的每项配置, 观察修改后的效果, 轻松理解各项参数, 还会有意想不到的发现哦 ~<br/>
--- 磨刀不误砍柴工,心急吃不了热豆腐. 请静下心来体验与理解mescroll, 一定会让您事半功倍 ~<br/>
--- 如使用中有疑问, 请先查看 <a href="http://www.mescroll.com/qa.html?v=0929">常见问题专区</a> ~<br/><br/>
## 图片懒加载
mescroll的图片懒加载功能是1.3.6新增的,使用超简单 :
##### 1. 确保mescroll至少更新到1.3.6版本
##### 2. 初始化mescroll的时候,在up中配置lazyLoad的use为true :
```
var mescroll = new MeScroll("mescroll", {
up: {
lazyLoad: {
use: true, // 是否开启懒加载,默认false
attr: 'imgurl', // 网络图片地址的属性名 (图片加载成功会自动移除改属性): <img imgurl='网络图 src='占位图''/>
showClass: 'mescroll-lazy-in', // 图片加载成功的显示动画: 渐变显示,参见mescroll.css
delay: 500, // 列表滚动的过程中每500ms检查一次图片是否在可视区域,如果在可视区域则加载图片
offset: 200 // 超出可视区域200px的图片仍可触发懒加载,目的是提前加载部分图片
}
}
})
```
##### 3. 设置img或div的 imgurl 属性, 值为图片的网络地址
```
img标签: <img imgurl="网络图" src="占位图"/> // 占位图直接在src设置; 图片加载成功,就会替换src的占位图
div或其他标签: <div imgurl="网络图" style="background-image: url(占位图)"></div>; // 占位图在css中设置; 图片以背景图的形式展示
```
##### 4. 至此mescroll的懒加载功能已经可以正常使用了,mescroll在列表滚动时会自动加载可视区域内的图片.另外,有时候您可能会动态添加或修改图片,希望手动触发一下懒加载, 那么只需调用 mescroll.lazyLoad() 或 mescroll.endByPage() 或 mescroll.endBySize() 或 mescroll.endSuccess() 即可.
##### 5. mescroll的所有案例都开启了懒加载,您可参考体验. <a href="http://www.mescroll.com/preview.html?name=list-mescroll-lazy" target="_blank">当然这里还有专门介绍懒加载的案例~</a>
## vue-cli
在vue单文件中的使用步骤 (至少更新到1.3.5版本):
##### 1. 执行npm命令安装mescroll : &nbsp; &nbsp; **npm install --save mescroll.js** //不要使用cnpm安装
##### 2. 引入mescroll.min.js : &nbsp; &nbsp; **import MeScroll from 'mescroll.js'**
##### 3. 引入mescroll.min.css : &nbsp; &nbsp; **import 'mescroll.js/mescroll.min.css'**
##### 4. vue单文件示例 :
```
<template>
<div>
<!--mescroll滚动区域的基本结构,为避免id重复导致的多次初始化,这里使用ref-->
<div ref="mescroll" class="mescroll">
<div>
<!--内容...-->
</div>
</div>
</div>
</template>
<script>
//引入mescroll.min.js和mescroll.min.css
import MeScroll from 'mescroll.js'
import 'mescroll.js/mescroll.min.css'
export default {
name: 'xxx',
data() {
return {
mescroll: null, //mescroll实例对象
dataList:[] //列表数据
}
},
mounted: function () {
//创建MeScroll对象
this.mescroll = new MeScroll(this.$refs.mescroll, { // 在vue的mounted生命周期初始化mescroll,确保此处配置的ref有值
// down:{}, //下拉刷新的配置. (如果下拉刷新和上拉加载处理的逻辑是一样的,则down可不用写了)
up: {
callback: this.upCallback,
// 以下是一些常用的配置,当然不写也可以的.
page: {
num: 0, //当前页 默认0,回调之前会加1; 即callback(page)会从1开始
size: 10, //每页数据条数,默认10
},
htmlNodata: '<p class="upwarp-nodata">亲,没有更多数据了~</p>',
noMoreSize: 5, //如果列表已无数据,可设置列表总数大于5才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看
toTop: {
//回到顶部按钮
src: "./static/mescroll/mescroll-totop.png", //图片路径,默认null,支持网络图
offset: 1000, //列表滚动1000px才显示回到顶部按钮
},
empty: {
//列表第一页无任何数据时,显示的空提示布局; 需配置warpId才显示
warpId: "xxid", //父布局的id (1.3.5版本支持传入dom元素)
icon: "./static/mescroll/mescroll-empty.png", //图标,默认null,支持网络图
tip: "暂无相关数据~", //提示
}
}
});
},
methods: {
//上拉回调 page = {num:1, size:10}; num:当前页 ,默认从1开始; size:每页数据条数,默认10
upCallback(page) {
//联网请求
axios.get("xxxxxx", {
params: {
num: page.num, //页码
size: page.size //每页长度
}
}).then((response)=> {
//请求的列表数据
let arr = response.data;
//如果是第一页需手动制空列表
if (page.num == 1) this.dataList = [];
//把请求到的数据添加到列表
this.dataList = this.dataList.concat(arr);
//数据渲染成功后,隐藏下拉刷新的状态
this.$nextTick(() => {
this.mescroll.endSuccess(arr.length);
})
}).catch((e)=> {
//联网失败的回调,隐藏下拉刷新和上拉加载的状态;
this.mescroll.endErr();
})
}
},
// 进入路由时,恢复列表状态
beforeRouteEnter (to, from, next) { // 如果没有配置回到顶部按钮或isBounce,则beforeRouteEnter不用写
next(vm => {
if (vm.mescroll) {
// 恢复到之前设置的isBounce状态
if (vm.mescroll.lastBounce != null) vm.mescroll.setBounce(vm.mescroll.lastBounce)
// 滚动到之前列表的位置 (注意:路由使用keep-alive才生效)
if (vm.mescroll.lastScrollTop) {
vm.mescroll.setScrollTop(vm.mescroll.lastScrollTop)
setTimeout(() => { // 需延时,因为setScrollTop内部会触发onScroll,可能会渐显回到顶部按钮
vm.mescroll.setTopBtnFadeDuration(0)// 设置回到顶部按钮显示时无渐显动画
}, 16)
}
}
})
},
// 离开路由时,记录列表状态
beforeRouteLeave (to, from, next) { // 如果没有配置回到顶部按钮或isBounce,则beforeRouteLeave不用写
if (this.mescroll) {
this.mescroll.lastBounce = this.mescroll.optUp.isBounce// 记录当前是否禁止ios回弹
this.mescroll.setBounce(true) // 允许bounce
this.mescroll.lastScrollTop = this.mescroll.getScrollTop()// 记录当前滚动条的位置
this.mescroll.hideTopBtn(0)// 隐藏回到顶部按钮,无渐隐动画
}
next()
}
}
</script>
<style scope>
/*通过fixed固定mescroll的高度*/
.mescroll {
position: fixed;
top: 44px;
bottom: 0;
height: auto;
}
</style>
```
##### 以上写法有些繁琐,在vue中强烈建议使用mescroll组件,简单快捷:
## mescroll组件
mescroll组件使用步骤 (至少更新到1.3.5版本):
##### 1. 执行npm命令安装mescroll : &nbsp; &nbsp; **npm install --save mescroll.js** //不要使用cnpm安装
##### 2. 引入mescroll组件 : &nbsp; &nbsp; **import MescrollVue from 'mescroll.js/mescroll.vue'**
##### 3. vue单文件示例 :
```
<template>
<div>
<!--mescroll滚动区域的基本结构-->
<mescroll-vue ref="mescroll" :down="mescrollDown" :up="mescrollUp" @init="mescrollInit">
<!--内容...-->
</mescroll-vue>
</div>
</template>
<script>
// 引入mescroll的vue组件
import MescrollVue from 'mescroll.js/mescroll.vue'
export default {
name: 'xxx',
components: {
MescrollVue // 注册mescroll组件
},
data () {
return {
mescroll: null, // mescroll实例对象
mescrollDown:{}, //下拉刷新的配置. (如果下拉刷新和上拉加载处理的逻辑是一样的,则mescrollDown可不用写了)
mescrollUp: { // 上拉加载的配置.
callback: this.upCallback, // 上拉回调,此处可简写; 相当于 callback: function (page, mescroll) { getListData(page); }
//以下是一些常用的配置,当然不写也可以的.
page: {
num: 0, //当前页 默认0,回调之前会加1; 即callback(page)会从1开始
size: 10 //每页数据条数,默认10
},
htmlNodata: '<p class="upwarp-nodata">亲,没有更多数据了~</p>',
noMoreSize: 5, //如果列表已无数据,可设置列表总数大于5才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看
toTop: {
//回到顶部按钮
src: "./static/mescroll/mescroll-totop.png", //图片路径,默认null,支持网络图
offset: 1000 //列表滚动1000px才显示回到顶部按钮
},
empty: {
//列表第一页无任何数据时,显示的空提示布局; 需配置warpId才显示
warpId: "xxid", //父布局的id (1.3.5版本支持传入dom元素)
icon: "./static/mescroll/mescroll-empty.png", //图标,默认null,支持网络图
tip: "暂无相关数据~" //提示
}
},
dataList: [] // 列表数据
}
},
beforeRouteEnter (to, from, next) { // 如果没有配置回到顶部按钮或isBounce,则beforeRouteEnter不用写
next(vm => {
vm.$refs.mescroll.beforeRouteEnter() // 进入路由时,滚动到原来的列表位置,恢复回到顶部按钮和isBounce的配置
})
},
beforeRouteLeave (to, from, next) { // 如果没有配置回到顶部按钮或isBounce,则beforeRouteLeave不用写
this.$refs.mescroll.beforeRouteLeave() // 退出路由时,记录列表滚动的位置,隐藏回到顶部按钮和isBounce的配置
next()
},
methods: {
// mescroll组件初始化的回调,可获取到mescroll对象
mescrollInit (mescroll) {
this.mescroll = mescroll
},
// 上拉回调 page = {num:1, size:10}; num:当前页 ,默认从1开始; size:每页数据条数,默认10
upCallback (page, mescroll) {
// 联网请求
axios.get('xxxxxx', {
params: {
num: page.num, // 页码
size: page.size // 每页长度
}
}).then((response) => {
// 请求的列表数据
let arr = response.data
// 如果是第一页需手动制空列表
if (page.num === 1) this.dataList = []
// 把请求到的数据添加到列表
this.dataList = this.dataList.concat(arr)
// 数据渲染成功后,隐藏下拉刷新的状态
this.$nextTick(() => {
mescroll.endSuccess(arr.length)
})
}).catch((e) => {
// 联网失败的回调,隐藏下拉刷新和上拉加载的状态;
mescroll.endErr()
})
}
}
}
</script>
<style scope>
/*以fixed的方式固定mescroll的高度*/
.mescroll {
position: fixed;
top: 44px;
bottom: 0;
height: auto;
}
</style>
```
## API文档 :
#### <a href="http://www.mescroll.com/api.html?v=0929#options" target="_blank">前往官网查看 >> </a>
```
//创建mescroll对象
var mescroll = new MeScroll(id或dom对象, { down: {下拉刷新的配置参数}, up: {上拉加载的配置参数} });
```
<table border="1" cellspacing="0">
<tr align="center"><td colspan="3"><b>down 下拉刷新的配置参数</b></td></tr>
<tr align="center">
<td>参数名</td>
<td>默认值</td>
<td>说明</td>
</tr>
<tr align="center">
<td>use</td>
<td>true</td>
<td>是否启用下拉刷新</td>
</tr>
<tr align="center">
<td>auto</td>
<td>true</td>
<td>是否在初始化完毕之后自动执行下拉刷新的回调</td>
</tr>
<tr align="center">
<td>autoShowLoading</td>
<td>false</td>
<td>当设置auto=true时(在初始化完毕之后自动执行下拉刷新的回调)<br/>是否显示下拉刷新的进度<br/>需配置down的callback才生效</td>
</tr>
<tr align="center">
<td>isLock</td>
<td>false</td>
<td>是否锁定下拉刷新</td>
</tr>
<tr align="center">
<td>isBoth</td>
<td>false</td>
<td>下拉刷新时,如果滑动到列表底部是否可以同时触发上拉加载</td>
</tr>
<tr align="center">
<td>offset</td>
<td>80</td>
<td>在列表顶部,下拉大于80px,松手即可触发下拉刷新的回调</td>
</tr>
<tr align="center">
<td>outOffsetRate</td>
<td>0.2</td>
<td>在列表顶部,下拉的距离大于offset时,改变下拉区域高度比例;值越接近0,高度变化越小,表现为越往下越难拉</td>
</tr>
<tr align="center">
<td>bottomOffset</td>
<td>20</td>
<td>当手指touchmove位置在距离body底部20px范围内的时候结束上拉刷新,避免Webview嵌套导致touchend事件不执行<br/>这是1.2.1版本新增的配置,请检查最新版~</td>
</tr>
<tr align="center">
<td>minAngle</td>
<td>45</td>
<td>触发下拉最少要偏移的角度(滑动的轨迹与水平线的锐角值),取值区间 [0,90];默认45度,即向下滑动的角度大于45度(方位角为45°~145°及225°~315°)则触发下拉;而小于45度,将不触发下拉,避免与左右滑动的轮播等组件冲突;<br/>注意:没有必要配置超出[0,90]区间的值,否则角度限制无效; 因为假设配置60, 生效的方位角就已经是60°到120° 和 240°到300°的范围了;<br/>这是1.1.6版本新增的配置,请检查最新版~</td>
</tr>
<tr align="center">
<td>hardwareClass</td>
<td>"mescroll-hardware"</td>
<td>硬件加速样式,解决iOS下拉因隐藏进度条而闪屏的问题,参见mescroll.css</td>
</tr>
<tr align="center">
<td>warpClass</td>
<td>"mescroll-downwarp"</td>
<td>下拉刷新的布局容器样式,参见mescroll.css</td>
</tr>
<tr align="center">
<td>mustToTop<br/>1.3.7版本新增</td>
<td>false</td>
<td>是否滚动条必须在顶部,才可以下拉刷新.默认false. 当您发现下拉刷新会闪白屏时,设置true即可修复.</td>
</tr>
<tr align="center">
<td>warpId</td>
<td>null</td>
<td>可配置下拉刷新的布局添加到指定id的div <br/> 默认不配置,默认添加到mescrollId</td>
</tr>
<tr align="center">
<td>resetClass</td>
<td>"mescroll-downwarp-reset"</td>
<td>下拉刷新高度重置的动画,参见mescroll.css</td>
</tr>
<tr align="center">
<td>textInOffset<br/>1.3.7版本新增</td>
<td>'下拉刷新'</td>
<td>下拉的距离在offset范围内的提示文本</td>
</tr>
<tr align="center">
<td>textOutOffset<br/>1.3.7版本新增</td>
<td>'释放更新'</td>
<td>下拉的距离大于offset范围的提示文本</td>
</tr>
<tr align="center">
<td>textLoading<br/>1.3.7版本新增</td>
<td>'加载中 ...'</td>
<td>加载中的提示文本</td>
</tr>
<tr align="center">
<td>htmlContent</td>
<td>'&lt;p class="downwarp-progress"&gt;&lt;/p&gt;&lt;p class="downwarp-tip"&gt;&lt;/p&gt;'</td>
<td>下拉刷新的布局内容</td>
</tr>
<tr align="center">
<td>inited</td>
<td>function(mescroll, downwarp) { ... }</td>
<td>下拉刷新初始化完毕的回调(mescroll实例对象,下拉刷新容器dom对象)</td>
</tr>
<tr align="center">
<td>inOffset</td>
<td>function(mescroll) { ... }</td>
<td>下拉的距离进入offset范围内那一刻的回调(mescroll实例对象)</td>
</tr>
<tr align="center">
<td>outOffset</td>
<td>function(mescroll) { ... }</td>
<td>下拉的距离大于offset那一刻的回调(mescroll实例对象)</td>
</tr>
<tr align="center">
<td>onMoving</td>
<td>function(mescroll, rate, downHight) { ... }</td>
<td>下拉过程中的回调,滑动过程一直在执行; rate下拉区域当前高度与指定距离的比值(inOffset: rate<1; outOffset: rate>=1); downHight当前下拉区域的高度</td>
</tr>
<tr align="center">
<td>beforeLoading</td>
<td>function(mescroll, downwarp) { return false; }</td>
<td>准备触发下拉刷新的回调; 如果要完全自定义下拉刷新,那么return true,此时将不触发showLoading和callback回调; 参考案例【淘宝 v6.8.0】</td>
</tr>
<tr align="center">
<td>showLoading</td>
<td>function(mescroll) { ... }</td>
<td>显示下拉刷新进度的回调</td>
</tr>
<tr align="center">
<td>afterLoading</td>
<td>function(mescroll) { return 0 }</td>
<td>结束加载中,准备隐藏下拉的回调 <br/>返回结束下拉的延时执行时间,默认0ms<br/>常用于结束下拉之前再显示另外一小段动画,才去隐藏下拉刷新的场景, 参考案例【dotJump】</td>
</tr>
<tr align="center">
<td>callback</td>
<td>function(mescroll) { mescroll.resetUpScroll(); }</td>
<td>下拉刷新的回调; 默认重置上拉加载列表为第一页</td>
</tr>
</table>
<br/>
<table border="1" cellspacing="0">
<tr align="center"><td colspan="3"><b>up 上拉加载的配置参数</b></td></tr>
<tr align="center">
<td>参数名</td>
<td>默认值</td>
<td>说明</td>
</tr>
<tr align="center">
<td>use</td>
<td>true</td>
<td>是否启用上拉加载</td>
</tr>
<tr align="center">
<td>auto</td>
<td>false</td>
<td>是否在初始化完毕之后自动执行上拉加载的回调</td>
</tr>
<tr align="center">
<td>isLock</td>
<td>false</td>
<td>是否锁定上拉加载</td>
</tr>
<tr align="center">
<td>isBoth</td>
<td>false</td>
<td>上拉加载时,如果滑动到列表顶部是否可以同时触发下拉刷新</td>
</tr>
<tr align="center">
<td>isBounce</td>
<td>true</td>
<td>是否允许ios的bounce回弹;默认true,允许回弹 (v 1.3.0新增)</td>
</tr>
<tr align="center">
<td>offset</td>
<td>100</td>
<td>列表滚动到距离底部小于100px,即可触发上拉加载的回调</td>
</tr>
<tr align="center">
<td>noMoreSize</td>
<td>5</td>
<td>如果列表已无数据,可设置列表的总数量要大于5条才显示无更多数据;避免列表数据过少(比如只有一条数据),显示无更多数据会不好看</td>
</tr>
<tr align="center">
<td>toTop</td>
<td align="left">{ <br/>
warpId: null, <br/>
src: null, <br/>
html: null, <br/>
offset: 1000, <br/>
warpClass: "mescroll-totop", <br/>
showClass: "mescroll-fade-in", <br/>
hideClass: "mescroll-fade-out", <br/>
duration: 300, <br/>
supportTap: false <br/>
btnClick : null <br/>
}</td>
<td align="left">回到顶部按钮的配置: <br/>
warpId: 父布局的id; 默认添加在body中 (1.3.5版本支持传入dom元素) <br/>
src: 图片路径,必须配置src才会显示回到顶部按钮,不配置不显示 <br/>
html: 标签内容,默认null; 如果同时设置了src,则优先取src (2017/12/10新增) <br/>
offset: 列表滚动1000px显示回到顶部按钮 <br/>
warpClass: 按钮样式,参见mescroll.css <br/>
showClass: 显示样式,参见mescroll.css <br/>
hideClass: 隐藏样式,参见mescroll.css <br/>
duration: 回到顶部的动画时长,默认300ms <br/>
supportTap: 如果您的运行环境支持tap,则可配置true,可减少点击延时,快速响应事件;默认false,通过onclick添加点击事件; (v 1.3.0 新增) (注:微信和PC无法响应tap事件) <br/>
btnClick: 点击按钮的回调; 提示:如果在回调里return true,将不执行回到顶部的操作
</td>
</tr>
<tr align="center">
<td>loadFull</td>
<td align="left">{ <br/>
use: false, <br/>
delay: 500 <br/>
}</td>
<td align="left">
use: 列表数据过少,不足以滑动触发上拉加载,是否自动加载下一页,直到满屏或者无更多数据为止; 默认false,因为可通过调高page.size避免这个情况 <br/>
delay: 延时执行的毫秒数; 延时是为了保证列表数据或占位的图片都已初始化完成,且下拉刷新上拉加载中区域动画已执行完毕;
</td>
</tr>
<tr align="center">
<td>empty</td>
<td align="left">{ <br/>
warpId: null, <br/>
icon: null, <br/>
tip: "暂无相关数据~", <br/>
btntext: "", <br/>
btnClick: null, <br/>
supportTap: false <br/>
}</td>
<td align="left">列表第一页无任何数据时,显示的空提示布局; 需配置warpId或clearEmptyId才生效 <br/>
warpId: 父布局的id; 如果此项有值,将不使用clearEmptyId的值; (1.3.5版本支持传入dom元素) <br/>
icon: 空布局的图标路径 <br/>
tip: 提示文本 <br/>
btntext: 按钮文本 <br/>
btnClick: 点击按钮的回调 <br/>
supportTap: 如果您的运行环境支持tap,则可配置true,可减少点击延时,快速响应事件;默认false,通过onclick添加点击事件; (v 1.3.0 新增) (注:微信和PC无法响应tap事件) <br/>
</td>
</tr>
<tr align="center">
<td>clearId</td>
<td>null</td>
<td>加载第一页时需清空数据的列表id; 如果此项有值,将不使用clearEmptyId的值; 在vue中使用,则无需配置此项</td>
</tr>
<tr align="center">
<td>clearEmptyId</td>
<td>null</td>
<td>相当于同时设置了clearId和empty.warpId; 简化写法; 在vue中使用,不能配置此项 (1.3.5版本支持传入dom元素)</td>
</tr>
<tr align="center">
<td>hardwareClass</td>
<td>"mescroll-hardware"</td>
<td>硬件加速样式,使动画更流畅,参见mescroll.css</td>
</tr>
<tr align="center">
<td>warpClass</td>
<td>"mescroll-upwarp"</td>
<td>上拉加载的布局容器样式,参见mescroll.css</td>
</tr>
<tr align="center">
<td>warpId</td>
<td>null</td>
<td>可配置上拉加载的布局添加到指定id的div;默认不配置,默认添加到mescrollId</td>
</tr>
<tr align="center">
<td>htmlLoading</td>
<td>'&lt;p class="upwarp-progress mescroll-rotate"&gt;&lt;/p&gt;&lt;p class="upwarp-tip"&gt;加载中..&lt;/p&gt;'</td>
<td>上拉加载中的布局,参见mescroll.css</td>
</tr>
<tr align="center">
<td>htmlNodata</td>
<td>'&lt;p class="upwarp-nodata"&gt;-- END --&lt;/p&gt;'</td>
<td>无数据的布局,参见mescroll.css</td>
</tr>
<tr align="center">
<td>inited</td>
<td>function(mescroll, upwarp){}</td>
<td>初始化完毕的回调; 回调(mescroll实例, upwarp上拉加载的布局Dom对象)</td>
</tr>
<tr align="center">
<td>showLoading</td>
<td>function(mescroll, upwarp){ ... }</td>
<td>显示上拉加载中的回调; 回调(mescroll实例, upwarp上拉加载的布局Dom对象)</td>
</tr>
<tr align="center">
<td>showNoMore</td>
<td>function(mescroll, upwarp){ ... }</td>
<td>显示无更多数据的回调; 回调(mescroll实例, upwarp上拉加载的布局Dom对象)</td>
</tr>
<tr align="center">
<td>onScroll</td>
<td>null</td>
<td>列表滑动监听, 默认null<br/>例 onScroll : function(mescroll, y, isUp){ ... };<br/>y为列表当前滚动条的位置;<br/>isUp=true向上滑,isUp=false向下滑)<br/>isUp是1.2.1版本新增的配置,请检查最新版~</td>
</tr>
<tr align="center">
<td>callback</td>
<td>function(page,mescroll){}</td>
<td>上拉加载的回调; 回调(page对象,mescroll实例), 其中page={num:页码, size:每页数据的数量, time:第一页数据的时间}</td>
</tr>
<tr align="center">
<td>page</td>
<td align="left">{ <br/>num:0, <br/> size:10, <br/> time:null <br/>}</td>
<td align="left">num: 当前页码,默认0,回调之前会加1,即callback(page)会从1开始; <br/>size: 每页数据的数量; <br/>time: 加载第一页数据服务器返回的时间;防止用户翻页时,后台新增了数据从而导致下一页数据重复;</td>
</tr>
<tr>
<td align="center">scrollbar</td>
<td>{<br/>&nbsp; use : ... , <br/>&nbsp; barClass : "mescroll-bar" <br/>}</td>
<td>use : 是否开启自定义滚动条; PC端默认true开启自定义滚动条; 移动端默认false不使用 <br/>barClass : 自定义滚动条的样式; 参见mescroll.css</td>
</tr>
<tr>
<td align="center">lazyLoad<br/>(1.3.6新增)</td>
<td>
{<br/>
use: false,<br/>
attr: 'imgurl',<br/>
showClass: 'mescroll-lazy-in',<br/>
delay: 500,<br/>
offset: 200<br/>
}
</td>
<td>
use: 是否开启懒加载,默认false<br/>
attr: 标签中网络图片地址的属性名,默认"imgurl"<br/>
showClass: 显示样式:渐变显示,参见mescroll.css<br/>
delay: 列表滚动的过程中检查一次图片是否在可视区域的时间间隔,默认500 (单位ms)<br/>
offset: 超出可视区域多少px的图片仍可触发懒加载 默认200
</td>
</tr>
</table>
## 常用方法 :
#### <a href="http://www.mescroll.com/api.html#methods" target="_blank">前往官网查看 >> </a>
<table border="1" cellspacing="0">
<tr align="center">
<td>方法名</td>
<td>说明</td>
</tr>
<tr align="center">
<td align="left">mescroll.endByPage(dataSize, totalPage, systime);<br/>(v 1.2.1 新增)</td>
<td align="left">隐藏下拉刷新和上拉加载的状态, 在联网获取数据成功后调用<br />
dataSize : 当前页获取的数据总数(注意是当前页)<br />
totalPage : 列表的总页数<br/>
systime : 加载第一页数据的服务器时间 (可空);
</td>
</tr>
<tr align="center">
<td align="left">mescroll.endBySize(dataSize, totalSize, systime);<br/>(v 1.2.1 新增)</td>
<td align="left">隐藏下拉刷新和上拉加载的状态, 在联网获取数据成功后调用<br />
dataSize : 当前页获取的数据总数(注意是当前页)<br />
totalSize : 列表的总数据量<br/>
systime : 加载第一页数据的服务器时间 (可空);
</td>
</tr>
<tr align="center">
<td align="left">mescroll.endSuccess(dataSize, hasNext, systime);<br/>(v 1.2.1 调整)</td>
<td align="left">隐藏下拉刷新和上拉加载的状态, 在联网获取数据成功后调用<br />
dataSize : 当前页获取的数据量(注意是当前页)<br />
hasNext : 是否有下一页数据true/false<br/>
systime : 加载第一页数据的服务器时间 (可空);
</td>
</tr>
<tr align="center">
<td>mescroll.endErr();</td>
<td>隐藏下拉刷新和上拉加载的状态, 在联网获取数据失败后调用;<br/>mescroll内部会自动恢复原来的页码,时间等变量;</td>
</tr>
<tr align="center">
<td>mescroll.resetUpScroll( isShowLoading );</td>
<td>重置列表为第一页 (常用于列表筛选条件变化或切换菜单时重新刷新列表数据)<br />内部实现: 把page.num=1,再主动触发up.callback<br />isShowLoading 是否显示进度布局; <br />1.默认null,不传参,则显示上拉加载的进度布局 <br />2.传参true, 则显示下拉刷新的进度布局<br />3.传参false,则不显示上拉和下拉的进度 (常用于静默更新列表数据)</td>
</tr>
<tr align="center">
<td>mescroll.triggerDownScroll();</td>
<td>主动触发下拉刷新</td>
</tr>
<tr align="center">
<td>mescroll.triggerUpScroll();</td>
<td>主动触发上拉加载</td>
</tr>
<tr align="center">
<td>mescroll.setPageNum(num);<br/>(v 1.2.5 新增)</td>
<td>设置当前page.num的值</td>
</tr>
<tr align="center">
<td>mescroll.setPageSize(size);<br/>(v 1.2.5 新增)</td>
<td>设置当前page.size的值</td>
</tr>
<tr align="center">
<td>mescroll.scrollTo( y, t );</td>
<td>滚动列表到指定位置 ( y=0回到列表顶部; 如需滚动到列表底部,可设置y很大的值,比如y=99999 ); t时长,单位ms,默认300</td>
</tr>
<tr align="center">
<td>mescroll.optDown;</td>
<td>获取下拉刷新的配置</td>
</tr>
<tr align="center">
<td>mescroll.optUp;</td>
<td>获取上拉加载的配置</td>
</tr>
<tr align="center">
<td>mescroll.lockDownScroll( isLock );</td>
<td>锁定下拉刷新 ( isLock=ture,null 锁定 ; isLock=false 解锁 )</td>
</tr>
<tr align="center">
<td>mescroll.lockUpScroll( isLock );</td>
<td>锁定上拉加载 ( isLock=ture,null 锁定 ; isLock=false 解锁 )</td>
</tr>
<tr align="center">
<td>mescroll.os<br/>(v 1.2.5 新增)</td>
<td>
<b>mescroll.os.ios</b> 为true, 则是ios设备;<br/>
<b>mescroll.os.android</b> 为true, 则是android设备;<br/>
<b>mescroll.os.pc</b> 为true, 则是PC端;
</td>
</tr>
<tr align="center">
<td>mescroll.setBounce(boolean)<br/>(v 1.3.0 新增)</td>
<td>
<b>mescroll.setBounce(true)</b> 允许bounce;<br/>
<b>mescroll.setBounce(false)</b> 禁止bounce
</td>
</tr>
<tr align="center">
<td>mescroll.lazyLoad(delay)<br/>(v 1.3.6 新增)</td>
<td>
主动触发懒加载: 自动加载可视区域的图片.<br />
delay:延时加载图片的时间,默认500ms.目的是确保dom元素已渲染完成.
</td>
</tr>
</table>
## 其他方法 :
#### <a href="http://www.mescroll.com/api.html#others" target="_blank">前往官网查看 >> </a>
<table border="1" cellspacing="0">
<tr align="center"><td colspan="2">以下方法不常用,您可灵活运用于更复杂的场景</tr>
<tr align="center">
<td width="288px">mescroll.showDownScroll();</td>
<td width="600px">显示下拉刷新的进度布局<br/>
mescroll.triggerDownScroll() 和 mescroll.resetUpScroll() 内部有调用</td>
</tr>
<tr align="center">
<td>mescroll.endDownScroll();</td>
<td>隐藏下拉刷新的进度布局<br/>
mescroll.endSuccess() 和 mescroll.endErr() 内部有调用</td>
</tr>
<tr align="center">
<td>mescroll.showUpScroll();</td>
<td>显示上拉加载的进度布局<br/>
mescroll.triggerDownScroll() 和 mescroll.resetUpScroll() 内部有调用</td>
</tr>
<tr align="center">
<td>mescroll.showNoMore();</td>
<td>显示上拉无更多数据的布局<br/>
mescroll.endUpScroll() 内部有调用</td>
</tr>
<tr align="center">
<td>mescroll.hideUpScroll(displayAble);</td>
<td>隐藏上拉加载的布局<br/>
mescroll.endUpScroll() 内部有调用<br/>
1.3.5新增参数 displayAble: 是否通过display:none隐藏, 默认false通过visibility:hidden的方式隐藏
</td>
</tr>
<tr align="center">
<td>mescroll.clearDataList();</td>
<td>清空上拉加载的数据列表<br/>
mescroll.resetUpScroll() 和 mescroll.endSuccess() 内部有调用</td>
</tr>
<tr align="center">
<td>mescroll.loadFull();</td>
<td>检查如果加载的数据过少,无法触发上拉加载时,则自动加载下一页,直到满屏或无数据<br/>
此方法最好在列表的图片数据加载完成之后调用,以便计算列表内容高度的准确性<br/>
mescroll.endSuccess() 内部有调用</td>
</tr>
<tr align="center">
<td>mescroll.showEmpty();</td>
<td>显示无任何数据的空布局<br/>
mescroll.endSuccess() 内部有调用</td>
</tr>
<tr align="center">
<td>mescroll.removeEmpty();</td>
<td>移除无任何数据的空布局<br/>
mescroll.endSuccess() 内部有调用</td>
</tr>
<tr align="center">
<td>mescroll.showTopBtn(time);</td>
<td>显示回到顶部的按钮<br/>time: 显示的动画时长,默认0.5秒 (1.3.5版本新增参数)</td>
</tr>
<tr align="center">
<td>mescroll.hideTopBtn(time);</td>
<td>隐藏回到顶部的按钮 <br/>time: 隐藏的动画时长,默认0.5秒 (1.3.5版本新增参数)</td>
</tr>
<tr align="center">
<td>mescroll.setTopBtnFadeDuration(time);<br/>(1.3.5版本新增)</td>
<td>设置回到顶部按钮的显示和隐藏的动画时长 <br/>time: 显示隐藏动画时长,默认0.5秒</td>
</tr>
<tr align="center">
<td>mescroll.getScrollTop();</td>
<td>获取滚动条的位置y; 也可以在up配置onScroll监听滚动条的位置</td>
</tr>
<tr align="center">
<td>mescroll.getBodyHeight();</td>
<td>获取body的高度 </td>
</tr>
<tr align="center">
<td>mescroll.getClientHeight();</td>
<td>获取滚动容器的高度 </td>
</tr>
<tr align="center">
<td>mescroll.getScrollHeight();</td>
<td>获取滚动内容的高度 </td>
</tr>
<tr align="center">
<td>mescroll.getToBottom();<br/>(v 1.3.0新增)</td>
<td>获取当前滚动条到底部的距离 </td>
</tr>
<tr align="center">
<td>mescroll.getStep(star, end, callback, t, rate);<br/>(v 1.2.8 新增) </td>
<td align="left">
star : 开始值; <br/>
end : 结束值; <br/>
callback(step,timer) : 回调 function(step,timer), <br/>
t : 计步时长; 传0则直接回调end值; 不传则默认300ms ; <br/>
rate : 周期; 不传则默认30ms计步一次 ; <br/>
此方法相当于默认在300ms内,每30ms返回star到end之间的阶梯值step; 可用于模拟帧动画 <br/>
比如mescroll的回到顶部缓冲动画,轮播导航案例的顶部菜单滚动都是通过getStep实现<br/>
(注: 您可根据实际情况在 callback 通过 window.clearInterval(timer) 提前结束计步器)
</td>
</tr>
<tr align="center">
<td>mescroll.version;<br/>(v 1.3.0新增)</td>
<td>mescroll的版本号</td>
</tr>
<tr align="center">
<td>mescroll.destroy();</td>
<td>销毁mescroll</td>
</tr>
</table>
## 基础案例 base demos :
#### <a href="http://www.mescroll.com/demo.html" target="_blank">前往官网查看 >> </a>
#### 1. 【商品列表】演示下拉刷新重置列表数据
#### ---------- <a href="http://www.mescroll.com/preview.html?name=list-products" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/base/list-products.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508205320970list-products.gif)
<br/><br/>
#### 2. 【新闻列表】演示下拉刷新添加新数据到列表顶部
#### ---------- <a href="http://www.mescroll.com/preview.html?name=list-news" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/base/list-news.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508205314004list-news.gif)
<br/><br/>
#### 3. 【单mescroll】演示每次切换菜单都重置列表,不缓存数据
#### ---------- <a href="http://www.mescroll.com/preview.html?name=list-mescroll-one" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/base/list-mescroll-one.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508205310491list-mescroll-one.gif)
<br/><br/>
#### 4. 【多mescroll】演示每个菜单列表仅初始化一次,切换菜单缓存数据
#### ---------- <a href="http://www.mescroll.com/preview.html?name=list-mescroll-more" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/base/list-mescroll-more.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508205306072list-mescroll-more.gif)
<br/><br/>
#### 5. 【满屏加载与锁定滑动】演示自动满屏加载,可临时锁定上拉刷新和下拉加载
#### ---------- <a href="http://www.mescroll.com/preview.html?name=list-full-lock" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/base/list-full-lock.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508205101076list-full-lock.gif)
<br/><br/>
#### 6. 【mescroll所有配置项】源码展示mescroll所有配置项, 快速理解与调试mescroll
#### ---------- <a href="http://www.mescroll.com/preview.html?name=mescroll-options" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/base/mescroll-options.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508205347926mescroll-options.gif)
<br/><br/>
## 中级案例 intermediate demos :
#### <a href="http://www.mescroll.com/demo.html#middle" target="_blank">前往官网查看 >> </a>
#### 1. 【知乎 v3.53.0】APP的下拉刷新上拉加载
#### ---------- <a href="http://www.mescroll.com/preview.html?name=zhihu" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/zhihu/zhihu.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508204842656zhihu.gif)
<br/><br/>
#### 2. 【新浪微博 v7.6.1】APP的下拉刷新上拉加载
#### ---------- <a href="http://www.mescroll.com/preview.html?name=xinlang" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/xinlang/xinlang.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508205006290xinlang.gif)
<br/><br/>
#### 3. 【贝贝 v6.0.0】APP的下拉刷新上拉加载
#### ---------- <a href="http://www.mescroll.com/preview.html?name=beibei" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/beibei/beibei.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508205298057beibei.gif)
<br/><br/>
#### 4. 【雅布力 v2.4.0】APP的下拉刷新上拉加载
#### ---------- <a href="http://www.mescroll.com/preview.html?name=yabuli" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/yabuli/yabuli.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1508204995995yabuli.gif)
<br/><br/>
#### 5. 【吸顶悬浮效果】
#### ---------- <a href="http://www.mescroll.com/preview.html?name=sticky" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/sticky/mescroll-sticky.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1512487870668IMG_4195.GIF)
<br/><br/>
#### 6. 【关键词搜索】
#### ---------- <a href="http://www.mescroll.com/preview.html?name=search" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/search/mescroll-search.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1512835307876IMG_4217.GIF)
<br/><br/>
#### 7. 【轮播切换效果】
#### ---------- <a href="http://www.mescroll.com/preview.html?name=swiper-tap" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/swiper/mescroll-swiper-tap.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1512487862014IMG_4194.GIF)
<br/><br/>
#### 8. 【轮播导航菜单】
#### ---------- <a href="http://www.mescroll.com/preview.html?name=swiper-nav" target="_blank">在线体验 </a> ---------- [查看源码](https://github.com/mescroll/mescroll/blob/master/demo/swiper/mescroll-swiper-nav.html) ----------
![](http://oux5x2xxe.bkt.clouddn.com/1512487862014IMG_4194.GIF)
<br/><br/>
## 高级案例 senior demos :
#### <a href="http://www.mescroll.com/demo.html#hight" target="_blank">前往官网查看 >> </a>
#### 1. 【淘宝 v6.8.0】APP的下拉刷新上拉加载
![](http://oux5x2xxe.bkt.clouddn.com/1508205033359taobao.gif)
<br/><br/>
#### 2. 【京东 v6.1.0】APP的下拉刷新上拉加载
![](http://oux5x2xxe.bkt.clouddn.com/1508205090739jingdong.gif)
<br/><br/>
#### 3. 【美团 v8.2.3】APP的下拉刷新上拉加载
![](http://oux5x2xxe.bkt.clouddn.com/1508205067956meituan.gif)
<br/><br/>
#### 4. 【美囤妈妈 v2.0.5】APP的下拉刷新上拉加载
![](http://oux5x2xxe.bkt.clouddn.com/1508205054953meitunmama.gif)
<br/><br/>
## 下载基础中级案例源码 :
<table border="1" cellspacing="0" width="100%">
<tr align="center" height="80px">
<td>mescroll.css</td>
<td>mescroll.js</td>
<td>mescroll所有基础案例源码</td>
<td>mescroll所有中级案例源码</td>
</tr>
<tr align="center" height="80px">
<td colspan="4"> <a href="https://codeload.github.com/mescroll/mescroll/zip/master" target="_blank">【立即下载】</a> </td>
</tr>
</table>
## 获取高级案例源码 :
<table border="1" cellspacing="0" width="100%">
<tr align="center">
<td rowspan="4" width="400px">
mescroll高级案例源码 -- 淘宝 v6.8.0<br/>
mescroll高级案例源码 -- 京东 v6.1.0<br/>
mescroll高级案例源码 -- 美团 v8.2.3<br/>
mescroll高级案例源码 -- 美囤妈妈 v2.0.5
</td>
</tr>
<tr align="center">
<td width="480px">
【 获取方法一 】<br/>
我是大神 , 我为mescroll添砖加瓦<br/>
在 GitHub 上 Star 和 Fork 了 mescroll<br/>
并提出优化或改进建议,获得了采纳 ~
</td>
</tr>
<tr align="center">
<td width="480px">
【 获取方法二 】<br/>
我爱分享 , 编写mescroll相关案例<br/>
联系 QQ 2260429223 投稿<br/>
评审优化后,在mescroll官网展示<br/>
源码指向您的GitHub
</td>
</tr>
<tr align="center">
<td width="480px">
【 获取方法三 】<br/>
我不做伸手党, 打赏任意金额<br/>
联系 QQ 2260429223 获取高级案例源码<br/>
<a href="http://www.mescroll.com/reward.html#tagRank">打赏排行 榜上有名</a>
</td>
</tr>
</table>
![](http://oux5x2xxe.bkt.clouddn.com/1508204975143pay-wx.jpg)
![](http://oux5x2xxe.bkt.clouddn.com/1508204974529pay-zfb.jpg)
/*! mescroll -- 精致的下拉刷新和上拉加载js框架 ( a great JS framework for pull-refresh and pull-up-loading )
* version 1.3.8
* 2018-09-29
* author: wenju < mescroll@qq.com > 文举
* *
* 官网: http://www.mescroll.com
* 动态: https://github.com/mescroll/mescroll/releases
* 问答: http://www.mescroll.com/qa.html
* issues: https://github.com/mescroll/mescroll/issues
* QQ交流群: 633126761
*
* 温馨提示: mescroll唯一的全局样式: html,body{height:100%},用于固定body的高度满屏; 如果影响到您原本的项目样式,可自行删除
*
*
* ----- mescroll的html结构解析 ----
*
<body>
<div id="mescroll" class="mescroll">
<div>
//下拉刷新区域 ( mescroll初始化之后自动创建 )
<div class="mescroll-downwarp">
<div class="downwarp-content">
<p class="downwarp-progress"></p> <p class="downwarp-tip">下拉刷新 </p>
</div>
</div>
//界面的具体内容
//<div>界面内容</div>
//数据列表..
//<ul id="dataList" class="data-list">
// <li>数据列表</li>
//空布局 ( 列表无任何数据时, 且配置了warpId时, 会自动创建显示 )
<div class="mescroll-empty">
<img class="empty-icon" src="../img/mescroll-empty.png"/>
<p class="empty-tip">暂无相关数据~</p>
<p class="empty-btn">去逛逛 ></p>
</div>
//</ul>
//上拉加载区域 ( mescroll初始化之后自动创建 )
<div class="mescroll-upwarp">
//加载中..
<p class="upwarp-progress mescroll-rotate"></p><p class="upwarp-tip">加载中..</p>
//无数据
<p class="upwarp-nodata">-- END --</p>
</div>
</div>
</div>
//回到顶部按钮 ( 列表滚动到配置的距离时, 且配置了warpId时, 会自动创建显示, 注意是添加在body中的 )
<img class="mescroll-totop" src="../img/mescroll-totop.png"/>
</body>
*/
html,body{height:100%}body{-webkit-overflow-scrolling:touch}.mescroll{width:100%;height:100%;overflow-y:auto}.mescroll-hardware{-webkit-transform:translateZ(0);-webkit-transform-style:preserve-3d;-webkit-backface-visibility:hidden;-webkit-perspective:1000}.mescroll-downwarp{position:relative;width:100%;height:0;overflow:hidden;text-align:center}.mescroll-downwarp-reset{-webkit-transition:height 300ms;transition:height 300ms}.mescroll-downwarp .downwarp-content{position:absolute;left:0;bottom:0;width:100%;min-height:30px;padding:10px 0}.mescroll-upwarp{min-height:30px;padding:15px 0;text-align:center;visibility:hidden}.mescroll-downwarp .downwarp-tip,.mescroll-upwarp .upwarp-tip,.mescroll-upwarp .upwarp-nodata{display:inline-block;font-size:12px;color:gray;vertical-align:middle}.mescroll-downwarp .downwarp-tip,.mescroll-upwarp .upwarp-tip{margin-left:8px}.mescroll-downwarp .downwarp-progress,.mescroll-upwarp .upwarp-progress{display:inline-block;width:16px;height:16px;border-radius:50%;border:1px solid gray;border-bottom-color:transparent;vertical-align:middle}.mescroll-rotate{-webkit-animation:mescrollRotate .6s linear infinite;animation:mescrollRotate .6s linear infinite}@-webkit-keyframes mescrollRotate{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(360deg)}}@keyframes mescrollRotate{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}.mescroll-empty{width:100%;padding-top:20px;text-align:center}.mescroll-empty .empty-icon{width:45%}.mescroll-empty .empty-tip{margin-top:6px;font-size:14px;color:gray}.mescroll-empty .empty-btn{max-width:50%;margin:20px auto;padding:10px;border:1px solid #65aadd;border-radius:6px;background-color:white;color:#65aadd}.mescroll-empty .empty-btn:active{opacity:.75}.mescroll-totop{z-index:9990;position:fixed;right:10px;bottom:30px;width:36px;height:36px;border-radius:50%;opacity:0}.mescroll-lazy-in,.mescroll-fade-in{-webkit-animation:mescrollFadeIn .5s linear forwards;animation:mescrollFadeIn .5s linear forwards}@-webkit-keyframes mescrollFadeIn{0%{opacity:0}100%{opacity:1}}@keyframes mescrollFadeIn{0%{opacity:0}100%{opacity:1}}.mescroll-fade-out{pointer-events:none;-webkit-animation:mescrollFadeOut .5s linear forwards;animation:mescrollFadeOut .5s linear forwards}@-webkit-keyframes mescrollFadeOut{0%{opacity:1}100%{opacity:0}}@keyframes mescrollFadeOut{0%{opacity:1}100%{opacity:0}}.mescroll-bar::-webkit-scrollbar-track{background-color:transparent}.mescroll-bar::-webkit-scrollbar{width:6px}.mescroll-bar::-webkit-scrollbar-thumb{border-radius:6px;background-color:#ccc}.mescroll-bar::-webkit-scrollbar-thumb:hover{background-color:#aaa}
\ No newline at end of file
/*! mescroll -- 精致的下拉刷新和上拉加载js框架 ( a great JS framework for pull-refresh and pull-up-loading )
* version 1.3.8
* 2018-09-29
* author: wenju < mescroll@qq.com > 文举
* *
* 官网: http://www.mescroll.com
* 动态: https://github.com/mescroll/mescroll/releases
* 问答: http://www.mescroll.com/qa.html
* issues: https://github.com/mescroll/mescroll/issues
* QQ交流群: 633126761
*/
(function(a,b){if(typeof define==="function"){define(b)}else{if(typeof module!=="undefined"&&module.exports){module.exports=b()}else{this[a]=b()}}})("MeScroll",function(){var a=function(b,e){var h=this;h.version="1.3.8";h.isScrollBody=(!b||b==="body");h.scrollDom=h.isScrollBody?document.body:h.getDomById(b);if(!h.scrollDom){return}h.options=e||{};var d=navigator.userAgent;var c=!!d.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);var i=typeof window.orientation==="undefined";var g=d.indexOf("Android")>-1||d.indexOf("Adr")>-1;h.os={ios:c,pc:i,android:g};h.isDownScrolling=false;h.isUpScrolling=false;var f=h.options.down&&h.options.down.callback;h.initDownScroll();h.initUpScroll();setTimeout(function(){if(h.optDown.use&&h.optDown.auto&&f){if(h.optDown.autoShowLoading){h.triggerDownScroll()}else{h.optDown.callback&&h.optDown.callback(h)}}h.optUp.use&&h.optUp.auto&&!h.isUpAutoLoad&&h.triggerUpScroll()},30)};a.prototype.extendDownScroll=function(b){a.extend(b,{use:true,auto:true,autoShowLoading:false,isLock:false,isBoth:false,offset:80,outOffsetRate:0.2,bottomOffset:20,minAngle:45,hardwareClass:"mescroll-hardware",mustToTop:false,warpId:null,warpClass:"mescroll-downwarp",resetClass:"mescroll-downwarp-reset",textInOffset:"下拉刷新",textOutOffset:"释放更新",textLoading:"加载中 ...",htmlContent:'<p class="downwarp-progress"></p><p class="downwarp-tip"></p>',inited:function(d,c){d.downTipDom=c.getElementsByClassName("downwarp-tip")[0];d.downProgressDom=c.getElementsByClassName("downwarp-progress")[0]},inOffset:function(c){if(c.downTipDom){c.downTipDom.innerHTML=c.optDown.textInOffset}if(c.downProgressDom){c.downProgressDom.classList.remove("mescroll-rotate")}},outOffset:function(c){if(c.downTipDom){c.downTipDom.innerHTML=c.optDown.textOutOffset}},onMoving:function(d,f,c){if(d.downProgressDom){var e=360*f;d.downProgressDom.style.webkitTransform="rotate("+e+"deg)";d.downProgressDom.style.transform="rotate("+e+"deg)"}},beforeLoading:function(d,c){return false},showLoading:function(c){if(c.downTipDom){c.downTipDom.innerHTML=c.optDown.textLoading}if(c.downProgressDom){c.downProgressDom.classList.add("mescroll-rotate")}},afterLoading:function(c){return 0},callback:function(c){c.resetUpScroll()}})};a.prototype.extendUpScroll=function(b){var c=this.os.pc;a.extend(b,{use:true,auto:true,isLock:false,isBoth:false,isBounce:true,callback:null,page:{num:0,size:10,time:null},noMoreSize:5,offset:100,toTop:{warpId:null,src:null,html:null,offset:1000,warpClass:"mescroll-totop",showClass:"mescroll-fade-in",hideClass:"mescroll-fade-out",fadeDuration:0.5,duration:300,supportTap:false,btnClick:null},loadFull:{use:false,delay:500},empty:{warpId:null,icon:null,tip:"暂无相关数据~",btntext:"",btnClick:null,supportTap:false},clearId:null,clearEmptyId:null,hardwareClass:"mescroll-hardware",warpId:null,warpClass:"mescroll-upwarp",htmlLoading:'<p class="upwarp-progress mescroll-rotate"></p><p class="upwarp-tip">加载中..</p>',htmlNodata:'<p class="upwarp-nodata">-- END --</p>',inited:function(d,e){},showLoading:function(d,e){e.innerHTML=d.optUp.htmlLoading},showNoMore:function(d,e){e.innerHTML=d.optUp.htmlNodata},onScroll:null,scrollbar:{use:c,barClass:"mescroll-bar"},lazyLoad:{use:false,attr:"imgurl",showClass:"mescroll-lazy-in",delay:500,offset:200}})};a.extend=function(d,b){if(!d){return b}for(var c in b){if(d[c]==null){d[c]=b[c]}else{if(typeof d[c]==="object"){a.extend(d[c],b[c])}}}return d};a.prototype.initDownScroll=function(){var c=this;c.optDown=c.options.down||{};c.extendDownScroll(c.optDown);c.touchstartEvent=function(f){if(c.isScrollTo){c.preventDefault(f)}c.startPoint=c.getPoint(f);c.lastPoint=c.startPoint;c.maxTouchmoveY=c.getBodyHeight()-c.optDown.bottomOffset;c.inTouchend=false;var d=c.getScrollTop();c.isKeepTop=d===0;if(c.os.pc&&d<=0){c.scrollDom.addEventListener("mousemove",c.touchmoveEvent,{passive:false});document.ondragstart=function(){return false}}};c.scrollDom.addEventListener("mousedown",c.touchstartEvent);c.scrollDom.addEventListener("touchstart",c.touchstartEvent);c.touchmoveEvent=function(l){if(!c.startPoint){return}var d=c.getScrollTop();if(d>0){c.isKeepTop=false}var h=c.getPoint(l);var f=h.y-c.startPoint.y;if(f>0){if(d<=0){c.preventDefault(l);if(c.optDown.use&&!c.inTouchend&&!c.isDownScrolling&&!c.optDown.isLock&&(!c.isUpScrolling||(c.isUpScrolling&&c.optUp.isBoth))){if(c.optDown.mustToTop&&!c.isKeepTop){return}var o=Math.abs(c.lastPoint.x-h.x);var n=Math.abs(c.lastPoint.y-h.y);var m=Math.sqrt(o*o+n*n);if(m!==0){var g=Math.asin(n/m)/Math.PI*180;if(g<c.optDown.minAngle){return}}if(c.maxTouchmoveY>0&&h.y>=c.maxTouchmoveY){c.inTouchend=true;c.touchendEvent();return}var p=h.y-c.lastPoint.y;if(!c.downHight){c.downHight=0}if(c.downHight<c.optDown.offset){if(c.movetype!==1){c.movetype=1;c.optDown.inOffset(c);c.downwarp.classList.remove(c.optDown.resetClass);c.isMoveDown=true;if(c.os.ios&&!c.isKeepTop){c.scrollDom.classList.add(c.optDown.hardwareClass);c.scrollDom.style.webkitOverflowScrolling="auto";c.isSetScrollAuto=true}}c.downHight+=p}else{if(c.movetype!==2){c.movetype=2;c.optDown.outOffset(c);c.downwarp.classList.remove(c.optDown.resetClass);c.isMoveDown=true;if(c.os.ios&&!c.isKeepTop){c.scrollDom.classList.add(c.optDown.hardwareClass);c.scrollDom.style.webkitOverflowScrolling="auto";c.isSetScrollAuto=true}}if(p>0){c.downHight+=p*c.optDown.outOffsetRate}else{c.downHight+=p}}c.downwarp.style.height=c.downHight+"px";var k=c.downHight/c.optDown.offset;c.optDown.onMoving(c,k,c.downHight)}}}else{if(f<0){var q=c.getScrollHeight();var j=c.getClientHeight();var i=q-j-d;if(!c.optUp.isBounce&&i<=0){c.preventDefault(l)}if(c.optUp.use&&!c.optUp.isLock&&c.optUp.hasNext&&!c.isUpScrolling&&(!c.isDownScrolling||(c.isDownScrolling&&c.optDown.isBoth))&&(j+c.optUp.offset>=q||i<=0)){c.triggerUpScroll()}}}c.lastPoint=h};c.scrollDom.addEventListener("touchmove",c.touchmoveEvent,{passive:false});c.touchendEvent=function(){if(c.optDown.use&&c.isMoveDown){if(c.downHight>=c.optDown.offset){c.triggerDownScroll()}else{c.downwarp.classList.add(c.optDown.resetClass);c.downHight=0;c.downwarp.style.height=0}if(c.isSetScrollAuto){c.scrollDom.style.webkitOverflowScrolling="touch";c.scrollDom.classList.remove(c.optDown.hardwareClass);c.isSetScrollAuto=false}c.movetype=0;c.isMoveDown=false}if(c.os.pc){c.scrollDom.removeEventListener("mousemove",c.touchmoveEvent);document.ondragstart=function(){return true}}};c.scrollDom.addEventListener("mouseup",c.touchendEvent);c.scrollDom.addEventListener("mouseleave",c.touchendEvent);c.scrollDom.addEventListener("touchend",c.touchendEvent);c.scrollDom.addEventListener("touchcancel",c.touchendEvent);if(c.optDown.use){c.downwarp=document.createElement("div");c.downwarp.className=c.optDown.warpClass;c.downwarp.innerHTML='<div class="downwarp-content">'+c.optDown.htmlContent+"</div>";var b=c.optDown.warpId?c.getDomById(c.optDown.warpId):c.scrollDom;if(c.optDown.warpId&&b){b.appendChild(c.downwarp)}else{if(!b){b=c.scrollDom}b.insertBefore(c.downwarp,c.scrollDom.firstChild)}setTimeout(function(){c.optDown.inited(c,c.downwarp)},0)}};a.prototype.preventDefault=function(b){if(b&&b.cancelable&&!b.defaultPrevented){b.preventDefault()}};a.prototype.getPoint=function(b){return{x:b.touches?b.touches[0].pageX:b.clientX,y:b.touches?b.touches[0].pageY:b.clientY}};a.prototype.triggerDownScroll=function(){if(!this.optDown.beforeLoading(this,this.downwarp)){this.showDownScroll();this.optDown.callback&&this.optDown.callback(this)}};a.prototype.showDownScroll=function(){this.isDownScrolling=true;this.optDown.showLoading(this);this.downHight=this.optDown.offset;this.downwarp.classList.add(this.optDown.resetClass);this.downwarp.style.height=this.optDown.offset+"px"};a.prototype.endDownScroll=function(){var d=this;var c=function(){d.downHight=0;d.downwarp.style.height=0;d.isDownScrolling=false;if(d.downProgressDom){d.downProgressDom.classList.remove("mescroll-rotate")}};var b=d.optDown.afterLoading(d);if(typeof b==="number"&&b>0){setTimeout(c,b)}else{c()}};a.prototype.lockDownScroll=function(b){if(b==null){b=true}this.optDown.isLock=b};a.prototype.initUpScroll=function(){var c=this;c.optUp=c.options.up||{use:false};c.extendUpScroll(c.optUp);if(c.optUp.scrollbar.use){c.scrollDom.classList.add(c.optUp.scrollbar.barClass)}if(!c.optUp.isBounce){c.setBounce(false)}if(c.optUp.use===false){return}c.optUp.hasNext=true;c.upwarp=document.createElement("div");c.upwarp.className=c.optUp.warpClass;var b;if(c.optUp.warpId){b=c.getDomById(c.optUp.warpId)}if(!b){b=c.scrollDom}b.appendChild(c.upwarp);c.preScrollY=0;c.lazyStartTime=new Date().getTime();c.lazyTag="mescroll-lazying";c.scrollEvent=function(){var g=c.getScrollTop();var f=g-c.preScrollY>0;c.preScrollY=g;if(!c.isUpScrolling&&(!c.isDownScrolling||(c.isDownScrolling&&c.optDown.isBoth))){if(!c.optUp.isLock&&c.optUp.hasNext){var d=c.getScrollHeight()-c.getClientHeight()-g;if(d<=c.optUp.offset&&f){c.triggerUpScroll()}}}var h=c.optUp.toTop;if(h.src||h.html){if(g>=h.offset){c.showTopBtn()}else{c.hideTopBtn()}}if(c.optUp.lazyLoad.use){var e=new Date().getTime();c.lazyTimer&&clearTimeout(c.lazyTimer);if(e-c.lazyStartTime>=c.optUp.lazyLoad.delay){c.lazyStartTime=e;c.lazyLoad(0)}else{c.lazyTimer=c.lazyLoad()}}c.optUp.onScroll&&c.optUp.onScroll(c,g,f)};if(c.isScrollBody){window.addEventListener("scroll",c.scrollEvent)}else{c.scrollDom.addEventListener("scroll",c.scrollEvent)}setTimeout(function(){c.optUp.inited(c,c.upwarp)},0)};a.prototype.setBounce=function(b){if(this.isScrollBody||!this.os.ios){return}if(b===false){this.optUp.isBounce=false;window.addEventListener("touchmove",this.bounceTouchmove,{passive:false})}else{this.optUp.isBounce=true;window.removeEventListener("touchmove",this.bounceTouchmove)}};a.prototype.bounceTouchmove=function(h){var j=this;var d=h.target;var f=true;while(d!==document.body&&d!==document){var m=d.classList;if(m){if(m.contains("mescroll")||m.contains("mescroll-touch")){f=false;break}else{if(m.contains("mescroll-touch-x")||m.contains("mescroll-touch-y")){var c=h.touches?h.touches[0].pageX:h.clientX;var b=h.touches?h.touches[0].pageY:h.clientY;if(!j.preWinX){j.preWinX=c}if(!j.preWinY){j.preWinY=b}var l=Math.abs(j.preWinX-c);var k=Math.abs(j.preWinY-b);var i=Math.sqrt(l*l+k*k);j.preWinX=c;j.preWinY=b;if(i!==0){var g=Math.asin(k/i)/Math.PI*180;if((g<=45&&m.contains("mescroll-touch-x"))||(g>45&&m.contains("mescroll-touch-y"))){f=false;break}}}}}d=d.parentNode}if(f&&h.cancelable&&!h.defaultPrevented){h.preventDefault()}};a.prototype.triggerUpScroll=function(){if(this.optUp.callback&&!this.isUpScrolling){this.showUpScroll();this.optUp.page.num++;this.isUpAutoLoad=true;this.optUp.callback(this.optUp.page,this)}};a.prototype.showUpScroll=function(){this.isUpScrolling=true;this.upwarp.classList.add(this.optUp.hardwareClass);this.upwarp.style.visibility="visible";this.upwarp.style.display="block";this.optUp.showLoading(this,this.upwarp)};a.prototype.showNoMore=function(){this.upwarp.style.visibility="visible";this.upwarp.style.display="block";this.optUp.hasNext=false;this.optUp.showNoMore(this,this.upwarp)};a.prototype.hideUpScroll=function(b){if(b){this.upwarp.style.display="none"}else{this.upwarp.style.visibility="hidden"}this.upwarp.classList.remove(this.optUp.hardwareClass);var c=this.upwarp.getElementsByClassName("upwarp-progress")[0];if(c){c.classList.remove("mescroll-rotate")}};a.prototype.endUpScroll=function(c,b){if(c!=null){if(c){this.showNoMore()}else{this.hideUpScroll(b)}}this.isUpScrolling=false};a.prototype.resetUpScroll=function(c){if(this.optUp&&this.optUp.use){var b=this.optUp.page;this.prePageNum=b.num;this.prePageTime=b.time;b.num=1;b.time=null;if(!this.isDownScrolling&&c!==false){if(c==null){this.removeEmpty();this.clearDataList();this.showUpScroll()}else{this.showDownScroll()}}this.isUpAutoLoad=true;this.optUp.callback&&this.optUp.callback(b,this)}};a.prototype.setPageNum=function(b){this.optUp.page.num=b-1};a.prototype.setPageSize=function(b){this.optUp.page.size=b};a.prototype.clearDataList=function(){var c=this.optUp.clearId||this.optUp.clearEmptyId;if(c){var b=this.getDomById(c);if(b){b.innerHTML=""}}};a.prototype.endByPage=function(c,e,d){var b;if(this.optUp.use&&e!=null){b=this.optUp.page.num<e}this.endSuccess(c,b,d)};a.prototype.endBySize=function(d,c,e){var b;if(this.optUp.use&&c!=null){var f=(this.optUp.page.num-1)*this.optUp.page.size+d;b=f<c}this.endSuccess(d,b,e)};a.prototype.endSuccess=function(c,b,i){var f=this;if(f.isDownScrolling){f.endDownScroll()}if(f.optUp.use){var j;if(c!=null){var e=f.optUp.page.num;var g=f.optUp.page.size;if(e===1){f.clearDataList();if(i){f.optUp.page.time=i}}if(c<g||b===false){f.optUp.hasNext=false;if(c===0&&e===1){j=false;f.showEmpty()}else{var d=(e-1)*g+c;if(d<f.optUp.noMoreSize){j=false}else{j=true}f.removeEmpty()}}else{j=false;f.optUp.hasNext=true;f.removeEmpty()}}var h=!f.optUp.hasNext;f.endUpScroll(j,h);f.loadFull();f.optUp.lazyLoad.use&&f.lazyLoad()}};a.prototype.endErr=function(){if(this.isDownScrolling){var b=this.optUp.page;if(b&&this.prePageNum){b.num=this.prePageNum;b.time=this.prePageTime}this.endDownScroll()}if(this.isUpScrolling){this.optUp.page.num--;this.endUpScroll(false)}};a.prototype.loadFull=function(){var b=this;if(b.optUp.loadFull.use&&!b.optUp.isLock&&b.optUp.hasNext&&b.optUp.callback&&b.getScrollHeight()<=b.getClientHeight()){setTimeout(function(){if(b.getScrollHeight()<=b.getClientHeight()){b.triggerUpScroll()}},b.optUp.loadFull.delay)}};a.prototype.lockUpScroll=function(b){if(b==null){b=true}this.optUp.isLock=b};a.prototype.showEmpty=function(){var c=this;var d=c.optUp.empty;var b=d.warpId||c.optUp.clearEmptyId;if(b==null){return}var g=c.getDomById(b);if(g){c.removeEmpty();var f="";if(d.icon){f+='<img class="empty-icon" src="'+d.icon+'"/>'}if(d.tip){f+='<p class="empty-tip">'+d.tip+"</p>"}if(d.btntext){f+='<p class="empty-btn">'+d.btntext+"</p>"}c.emptyDom=document.createElement("div");c.emptyDom.className="mescroll-empty";c.emptyDom.innerHTML=f;g.appendChild(c.emptyDom);if(d.btnClick){var e=c.emptyDom.getElementsByClassName("empty-btn")[0];if(d.supportTap){e.addEventListener("tap",function(h){h.stopPropagation();c.preventDefault(h);d.btnClick()})}else{e.onclick=function(){d.btnClick()}}}}};a.prototype.removeEmpty=function(){this.removeChild(this.emptyDom)};a.prototype.showTopBtn=function(c){if(!this.topBtnShow){this.topBtnShow=true;var d=this;var e=d.optUp.toTop;if(d.toTopBtn==null){if(e.html){d.toTopBtn=document.createElement("div");d.toTopBtn.innerHTML=e.html}else{d.toTopBtn=document.createElement("img");d.toTopBtn.src=e.src}d.toTopBtn.className=e.warpClass;if(e.supportTap){d.toTopBtn.addEventListener("tap",function(g){g.stopPropagation();d.preventDefault(g);var f=e.btnClick&&e.btnClick();if(f!==true){d.scrollTo(0,d.optUp.toTop.duration)}})}else{d.toTopBtn.onclick=function(){var f=e.btnClick&&e.btnClick();if(f!==true){d.scrollTo(0,d.optUp.toTop.duration)}}}var b;if(e.warpId){b=d.getDomById(e.warpId)}if(!b){b=document.body}b.appendChild(d.toTopBtn)}d.toTopBtn.classList.remove(e.hideClass);d.toTopBtn.classList.add(e.showClass);d.setTopBtnFadeDuration(c)}};a.prototype.hideTopBtn=function(b){if(this.topBtnShow&&this.toTopBtn){this.topBtnShow=false;this.toTopBtn.classList.remove(this.optUp.toTop.showClass);this.toTopBtn.classList.add(this.optUp.toTop.hideClass);this.setTopBtnFadeDuration(b)}};a.prototype.setTopBtnFadeDuration=function(b){if(this.toTopBtn){var c=(b!=null?b:this.optUp.toTop.fadeDuration)+"s";this.toTopBtn.style.animationDuration=c;this.toTopBtn.style.webkitAnimationDuration=c}};a.prototype.scrollTo=function(g,c){var d=this;var f=d.getScrollTop();var b=g;if(b>0){var e=d.getScrollHeight()-d.getClientHeight();if(b>e){b=e}}else{b=0}d.isScrollTo=true;d.scrollDom.style.webkitOverflowScrolling="auto";d.getStep(f,b,function(h){d.setScrollTop(h);if(h===b){d.scrollDom.style.webkitOverflowScrolling="touch";d.isScrollTo=false}},c)};a.prototype.getStep=function(f,d,k,l,h){var j=d-f;if(l===0||j===0){k&&k(d);return}l=l||300;h=h||30;var g=l/h;var c=j/g;var e=0;var b=window.setInterval(function(){if(e<g-1){f+=c;k&&k(f,b);e++}else{k&&k(d,b);window.clearInterval(b)}},h)};a.prototype.lazyLoad=function(b){var d=this;var c=b!=null?b:d.optUp.lazyLoad.delay;var e=setTimeout(function(){var k=d.scrollDom.querySelectorAll("["+d.optUp.lazyLoad.attr+"]");var f=k.length;for(var j=0;j<f;j++){var l=k[j];if(l.getAttribute(d.lazyTag)!=="true"&&d.isInSee(l,d.optUp.lazyLoad.offset)){var h=l.getAttribute(d.optUp.lazyLoad.attr);var g=new Image();g.onload=function(){var i=this.src;var n=this.dom;var m=d.optUp.lazyLoad.showClass;m&&n.classList.add(m);if(n.tagName==="IMG"){n.src=i}else{n.style.backgroundImage="url("+i+")"}n.removeAttribute(d.optUp.lazyLoad.attr);n.removeAttribute(d.lazyTag)};g.onerror=function(){this.dom.removeAttribute(d.lazyTag)};g.onabort=function(){this.dom.removeAttribute(d.lazyTag)};g.src=h;l.setAttribute(d.lazyTag,"true");g.dom=l}}},c);return e};a.prototype.isInSee=function(f,e){e=e||0;var b=this.getOffsetTop(f);var d=this.getScrollTop()-e;var g=b+f.offsetHeight;var c=d+e+this.getClientHeight()+e;return(b<c&&b>=d)||(g<=c&&g>d)};a.prototype.getOffsetTop=function(d){var c=d.offsetTop;var b=d.offsetParent;while(b!=null&&b!==this.scrollDom){c+=b.offsetTop+b.clientTop;b=b.offsetParent}return c};a.prototype.getScrollHeight=function(){return this.scrollDom.scrollHeight};a.prototype.getClientHeight=function(){if(this.isScrollBody&&document.compatMode==="CSS1Compat"){return document.documentElement.clientHeight}else{return this.scrollDom.clientHeight}};a.prototype.getBodyHeight=function(){return document.body.clientHeight||document.documentElement.clientHeight};a.prototype.getScrollTop=function(){if(this.isScrollBody){return document.documentElement.scrollTop||document.body.scrollTop}else{return this.scrollDom.scrollTop}};a.prototype.getToBottom=function(){return this.getScrollHeight()-this.getClientHeight()-this.getScrollTop()};a.prototype.setScrollTop=function(b){if(typeof b==="number"){if(this.isScrollBody){document.documentElement.scrollTop=b;document.body.scrollTop=b}else{this.scrollDom.scrollTop=b}}};a.prototype.getDomById=function(c){var b;if(c){if(typeof c==="string"){b=document.getElementById(c)}else{if(c.nodeType){b=c}}}if(!b){console.error('the element with id as "'+c+'" can not be found: document.getElementById("'+c+'")==null')}return b};a.prototype.removeChild=function(c){if(c){var b=c.parentNode;b&&b.removeChild(c);c=null}};a.prototype.destroy=function(){var b=this;b.scrollDom.removeEventListener("touchstart",b.touchstartEvent);b.scrollDom.removeEventListener("touchmove",b.touchmoveEvent);b.scrollDom.removeEventListener("touchend",b.touchendEvent);b.scrollDom.removeEventListener("touchcancel",b.touchendEvent);b.scrollDom.removeEventListener("mousedown",b.touchstartEvent);b.scrollDom.removeEventListener("mousemove",b.touchmoveEvent);b.scrollDom.removeEventListener("mouseup",b.touchendEvent);b.scrollDom.removeEventListener("mouseleave",b.touchendEvent);b.removeChild(b.downwarp);if(b.isScrollBody){window.removeEventListener("scroll",b.scrollEvent)}else{b.scrollDom.removeEventListener("scroll",b.scrollEvent)}b.removeChild(b.upwarp);b.removeChild(b.toTopBtn);b.setBounce(true)};return a});
\ No newline at end of file
<template>
<div ref="mescroll" class="mescroll">
<div>
<slot></slot>
</div>
</div>
</template>
<script>
// 引入mescroll.min.js和mescroll.min.css
import MeScroll from 'mescroll.js'
import 'mescroll.js/mescroll.min.css'
export default {
name: 'MeScrollVue',
data: function () {
return {
mescroll: null,
lastScrollTop: 0, // 路由切换时滚动条的位置
lastBounce: null // 路由切换时是否禁止ios回弹
}
},
props: {
up: Object,
down: Object
},
mounted: function () {
this.mescroll = new MeScroll(this.$refs.mescroll, {
up: this.up,
down: this.down
})
this.$emit('init', this.mescroll) // init回调mescroll对象
},
methods: {
beforeRouteEnter () {
if (this.mescroll) {
// 滚动到之前列表的位置
if (this.lastScrollTop) {
this.mescroll.setScrollTop(this.lastScrollTop)
setTimeout(() => { // 需延时,因为setScrollTop内部会触发onScroll,可能会渐显回到顶部按钮
this.mescroll.setTopBtnFadeDuration(0) // 设置回到顶部按钮显示时无渐显动画
}, 16)
}
// 恢复到之前设置的isBounce状态
if (this.lastBounce != null) this.mescroll.setBounce(this.lastBounce)
}
},
beforeRouteLeave () {
if (this.mescroll) {
this.lastScrollTop = this.mescroll.getScrollTop() // 记录当前滚动条的位置
this.mescroll.hideTopBtn(0) // 隐藏回到顶部按钮,无渐隐动画
this.lastBounce = this.mescroll.optUp.isBounce // 记录当前是否禁止ios回弹
this.mescroll.setBounce(true) // 允许bounce
}
}
}
}
</script>
<style>
</style>
{
"name": "mescroll.js",
"version": "1.3.8",
"description": "精致的下拉刷新和上拉加载 js框架.支持vue,完美运行于移动端和主流PC浏览器 ( a great JS framework for pull-refresh and pull-up-loading )",
"main": "mescroll.min.js",
"scripts": {},
"repository": {
"type": "git",
"url": "git+https://github.com/mescroll/mescroll.git"
},
"author": "wenju",
"license": "MIT",
"bugs": {
"url": "https://github.com/mescroll/mescroll/issues"
},
"homepage": "https://github.com/mescroll/mescroll#readme",
"_from": "mescroll.js@1.3.8",
"_resolved": "http://registry.npm.taobao.org/mescroll.js/download/mescroll.js-1.3.8.tgz"
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment