123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- (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);
|