NGToolsCSharp/NGTools/Scripts/MUI/js/mui.pullToRefresh.js
2024-09-13 16:44:30 +08:00

407 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(function($, window, document) {
var STATE_BEFORECHANGEOFFSET = 'beforeChangeOffset';
var STATE_AFTERCHANGEOFFSET = 'afterChangeOffset';
var EVENT_PULLSTART = 'pullstart';
var EVENT_PULLING = 'pulling';
var EVENT_BEFORECHANGEOFFSET = STATE_BEFORECHANGEOFFSET;
var EVENT_AFTERCHANGEOFFSET = STATE_AFTERCHANGEOFFSET;
var EVENT_DRAGENDAFTERCHANGEOFFSET = 'dragEndAfterChangeOffset';
var CLASS_TRANSITIONING = $.className('transitioning');
var CLASS_PULL_TOP_TIPS = $.className('pull-top-tips');
var CLASS_PULL_BOTTOM_TIPS = $.className('pull-bottom-tips');
var CLASS_PULL_LOADING = $.className('pull-loading');
var CLASS_SCROLL = $.className('scroll');
var CLASS_PULL_TOP_ARROW = $.className('pull-loading') + ' ' + $.className('icon') + ' ' + $.className('icon-pulldown');
var CLASS_PULL_TOP_ARROW_REVERSE = CLASS_PULL_TOP_ARROW + ' ' + $.className('reverse');
var CLASS_PULL_TOP_SPINNER = $.className('pull-loading') + ' ' + $.className('spinner');
var CLASS_HIDDEN = $.className('hidden');
var SELECTOR_PULL_LOADING = '.' + CLASS_PULL_LOADING;
$.PullToRefresh = $.Class.extend({
init: function(element, options) {
this.element = element;
this.options = $.extend(true, {
down: {
height: 75,
callback: false,
},
up: {
auto: false,
offset: 100, //距离底部高度(到达该高度即触发)
show: true,
contentinit: '上拉显示更多',
contentdown: '上拉显示更多',
contentrefresh: '正在加载...',
contentnomore: '没有更多数据了',
callback: false
},
preventDefaultException: {
tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/
}
}, options);
this.stopped = this.isNeedRefresh = this.isDragging = false;
this.state = STATE_BEFORECHANGEOFFSET;
this.isInScroll = this.element.classList.contains(CLASS_SCROLL);
this.initPullUpTips();
this.initEvent();
},
_preventDefaultException: function(el, exceptions) {
for (var i in exceptions) {
if (exceptions[i].test(el[i])) {
return true;
}
}
return false;
},
initEvent: function() {
if ($.isFunction(this.options.down.callback)) {
this.element.addEventListener($.EVENT_START, this);
this.element.addEventListener('drag', this);
this.element.addEventListener('dragend', this);
}
if (this.pullUpTips) {
this.element.addEventListener('dragup', this);
if (this.isInScroll) {
this.element.addEventListener('scrollbottom', this);
} else {
window.addEventListener('scroll', this);
}
}
},
handleEvent: function(e) {
switch (e.type) {
case $.EVENT_START:
this.isInScroll && this._canPullDown() && e.target && !this._preventDefaultException(e.target, this.options.preventDefaultException) && e.preventDefault();
break;
case 'drag':
this._drag(e);
break;
case 'dragend':
this._dragend(e);
break;
case 'webkitTransitionEnd':
this._transitionEnd(e);
break;
case 'dragup':
case 'scroll':
this._dragup(e);
break;
case 'scrollbottom':
if (e.target === this.element) {
this.pullUpLoading(e);
}
break;
}
},
initPullDownTips: function() {
var self = this;
if ($.isFunction(self.options.down.callback)) {
self.pullDownTips = (function() {
var element = document.querySelector('.' + CLASS_PULL_TOP_TIPS);
if (element) {
element.parentNode.removeChild(element);
}
if (!element) {
element = document.createElement('div');
element.classList.add(CLASS_PULL_TOP_TIPS);
element.innerHTML = '<div class="mui-pull-top-wrapper"><span class="mui-pull-loading mui-icon mui-icon-pulldown"></span></div>';
element.addEventListener('webkitTransitionEnd', self);
}
self.pullDownTipsIcon = element.querySelector(SELECTOR_PULL_LOADING);
document.body.appendChild(element);
return element;
}());
}
},
initPullUpTips: function() {
var self = this;
if ($.isFunction(self.options.up.callback)) {
self.pullUpTips = (function() {
var element = self.element.querySelector('.' + CLASS_PULL_BOTTOM_TIPS);
if (!element) {
element = document.createElement('div');
element.classList.add(CLASS_PULL_BOTTOM_TIPS);
if (!self.options.up.show) {
element.classList.add(CLASS_HIDDEN);
}
element.innerHTML = '<div class="mui-pull-bottom-wrapper"><span class="mui-pull-loading">' + self.options.up.contentinit + '</span></div>';
self.element.appendChild(element);
}
self.pullUpTipsIcon = element.querySelector(SELECTOR_PULL_LOADING);
return element;
}());
}
},
_transitionEnd: function(e) {
if (e.target === this.pullDownTips && this.removing) {
this.removePullDownTips();
}
},
_dragup: function(e) {
var self = this;
if (self.loading) {
return;
}
if (e && e.detail && $.gestures.session.drag) {
self.isDraggingUp = true;
} else {
if (!self.isDraggingUp) { //scroll event
return;
}
}
if (!self.isDragging) {
if (self._canPullUp()) {
self.pullUpLoading(e);
}
}
},
_canPullUp: function() {
if (this.removing) {
return false;
}
if (this.isInScroll) {
var scrollId = this.element.parentNode.getAttribute('data-scroll');
if (scrollId) {
var scrollApi = $.data[scrollId];
return scrollApi.y === scrollApi.maxScrollY;
}
}
return window.pageYOffset + window.innerHeight + this.options.up.offset >= document.documentElement.scrollHeight;
},
_canPullDown: function() {
if (this.removing) {
return false;
}
if (this.isInScroll) {
var scrollId = this.element.parentNode.getAttribute('data-scroll');
if (scrollId) {
var scrollApi = $.data[scrollId];
return scrollApi.y === 0;
}
}
return document.body.scrollTop === 0;
},
_drag: function(e) {
if (this.loading || this.stopped) {
e.stopPropagation();
e.detail.gesture.preventDefault();
return;
}
var detail = e.detail;
if (!this.isDragging) {
if (detail.direction === 'down' && this._canPullDown()) {
if (document.querySelector('.' + CLASS_PULL_TOP_TIPS)) {
e.stopPropagation();
e.detail.gesture.preventDefault();
return;
}
this.isDragging = true;
this.removing = false;
this.startDeltaY = detail.deltaY;
$.gestures.session.lockDirection = true; //锁定方向
$.gestures.session.startDirection = detail.direction;
this._pullStart(this.startDeltaY);
}
}
if (this.isDragging) {
e.stopPropagation();
e.detail.gesture.preventDefault();
var deltaY = detail.deltaY - this.startDeltaY;
deltaY = Math.min(deltaY, 1.5 * this.options.down.height);
this.deltaY = deltaY;
this._pulling(deltaY);
var state = deltaY > this.options.down.height ? STATE_AFTERCHANGEOFFSET : STATE_BEFORECHANGEOFFSET;
if (this.state !== state) {
this.state = state;
if (this.state === STATE_AFTERCHANGEOFFSET) {
this.removing = false;
this.isNeedRefresh = true;
} else {
this.removing = true;
this.isNeedRefresh = false;
}
this['_' + state](deltaY);
}
if ($.os.ios && parseFloat($.os.version) >= 8) {
var clientY = detail.gesture.touches[0].clientY;
if ((clientY + 10) > window.innerHeight || clientY < 10) {
this._dragend(e);
return;
}
}
}
},
_dragend: function(e) {
var self = this;
if (self.isDragging) {
self.isDragging = false;
self._dragEndAfterChangeOffset(self.isNeedRefresh);
}
if (self.isPullingUp) {
if (self.pullingUpTimeout) {
clearTimeout(self.pullingUpTimeout);
}
self.pullingUpTimeout = setTimeout(function() {
self.isPullingUp = false;
}, 1000);
}
},
_pullStart: function(startDeltaY) {
this.pullStart(startDeltaY);
$.trigger(this.element, EVENT_PULLSTART, {
api: this,
startDeltaY: startDeltaY
});
},
_pulling: function(deltaY) {
this.pulling(deltaY);
$.trigger(this.element, EVENT_PULLING, {
api: this,
deltaY: deltaY
});
},
_beforeChangeOffset: function(deltaY) {
this.beforeChangeOffset(deltaY);
$.trigger(this.element, EVENT_BEFORECHANGEOFFSET, {
api: this,
deltaY: deltaY
});
},
_afterChangeOffset: function(deltaY) {
this.afterChangeOffset(deltaY);
$.trigger(this.element, EVENT_AFTERCHANGEOFFSET, {
api: this,
deltaY: deltaY
});
},
_dragEndAfterChangeOffset: function(isNeedRefresh) {
this.dragEndAfterChangeOffset(isNeedRefresh);
$.trigger(this.element, EVENT_DRAGENDAFTERCHANGEOFFSET, {
api: this,
isNeedRefresh: isNeedRefresh
});
},
removePullDownTips: function() {
if (this.pullDownTips) {
try {
this.pullDownTips.parentNode && this.pullDownTips.parentNode.removeChild(this.pullDownTips);
this.pullDownTips = null;
this.removing = false;
} catch (e) {}
}
},
pullStart: function(startDeltaY) {
this.initPullDownTips(startDeltaY);
},
pulling: function(deltaY) {
this.pullDownTips.style.webkitTransform = 'translate3d(0,' + deltaY + 'px,0)';
},
beforeChangeOffset: function(deltaY) {
this.pullDownTipsIcon.className = CLASS_PULL_TOP_ARROW;
},
afterChangeOffset: function(deltaY) {
this.pullDownTipsIcon.className = CLASS_PULL_TOP_ARROW_REVERSE;
},
dragEndAfterChangeOffset: function(isNeedRefresh) {
if (isNeedRefresh) {
this.pullDownTipsIcon.className = CLASS_PULL_TOP_SPINNER;
this.pullDownLoading();
} else {
this.pullDownTipsIcon.className = CLASS_PULL_TOP_ARROW;
this.endPullDownToRefresh();
}
},
pullDownLoading: function() {
if (this.loading) {
return;
}
if (!this.pullDownTips) {
this.initPullDownTips();
this.dragEndAfterChangeOffset(true);
return;
}
this.loading = true;
this.pullDownTips.classList.add(CLASS_TRANSITIONING);
this.pullDownTips.style.webkitTransform = 'translate3d(0,' + this.options.down.height + 'px,0)';
this.options.down.callback.apply(this);
},
pullUpLoading: function(e) {
if (this.loading || this.finished) {
return;
}
this.loading = true;
this.isDraggingUp = false;
this.pullUpTips.classList.remove(CLASS_HIDDEN);
e && e.detail && e.detail.gesture && e.detail.gesture.preventDefault();
this.pullUpTipsIcon.innerHTML = this.options.up.contentrefresh;
this.options.up.callback.apply(this);
},
endPullDownToRefresh: function() {
this.loading = false;
this.pullUpTips && this.pullUpTips.classList.remove(CLASS_HIDDEN);
this.pullDownTips.classList.add(CLASS_TRANSITIONING);
this.pullDownTips.style.webkitTransform = 'translate3d(0,0,0)';
if (this.deltaY <= 0) {
this.removePullDownTips();
} else {
this.removing = true;
}
if (this.isInScroll) {
$(this.element.parentNode).scroll().refresh();
}
},
endPullUpToRefresh: function(finished) {
if (finished) {
this.finished = true;
this.pullUpTipsIcon.innerHTML = this.options.up.contentnomore;
this.element.removeEventListener('dragup', this);
window.removeEventListener('scroll', this);
} else {
this.pullUpTipsIcon.innerHTML = this.options.up.contentdown;
}
this.loading = false;
if (this.isInScroll) {
$(this.element.parentNode).scroll().refresh();
}
},
setStopped: function(stopped) {
if (stopped != this.stopped) {
this.stopped = stopped;
this.pullUpTips && this.pullUpTips.classList[stopped ? 'add' : 'remove'](CLASS_HIDDEN);
}
},
refresh: function(isReset) {
if (isReset && this.finished && this.pullUpTipsIcon) {
this.pullUpTipsIcon.innerHTML = this.options.up.contentdown;
this.element.addEventListener('dragup', this);
window.addEventListener('scroll', this);
this.finished = false;
}
}
});
$.fn.pullToRefresh = function(options) {
var pullRefreshApis = [];
options = options || {};
this.each(function() {
var self = this;
var pullRefreshApi = null;
var id = self.getAttribute('data-pullToRefresh');
if (!id) {
id = ++$.uuid;
$.data[id] = pullRefreshApi = new $.PullToRefresh(self, options);
self.setAttribute('data-pullToRefresh', id);
} else {
pullRefreshApi = $.data[id];
}
if (options.up && options.up.auto) { //如果设置了auto则自动上拉一次
pullRefreshApi.pullUpLoading();
}
pullRefreshApis.push(pullRefreshApi);
});
return pullRefreshApis.length === 1 ? pullRefreshApis[0] : pullRefreshApis;
}
})(mui, window, document);