core.js
10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
import {
noop,
extend,
selector,
} from '../util/lang';
import osMixin from '../mixin/os';
import Scroll from './scroll';
const defaultSetting = {
// 下拉有关
down: {
// 默认没有锁定,可以通过API动态设置
isLock: false,
// 是否自动下拉刷新
isAuto: false,
// 设置isAuto=true时生效,是否在初始化的下拉刷新触发事件中显示动画,如果是false,初始化的加载只会触发回调,不会触发动画
isAllowAutoLoading: true,
// 是否不管任何情况下都能触发下拉刷新,为false的话当上拉时不会触发下拉
isAways: false,
// 是否scroll在下拉时会进行移动(css3),通过关闭它可以实现自定义动画
isScrollCssTranslate: true,
// 是否每次下拉完毕后默认重置上拉
isAutoResetUpLoading: true,
// 下拉要大于多少长度后再下拉刷新
offset: 75,
// 阻尼系数,下拉小于offset时的阻尼系数,值越接近0,高度变化越小,表现为越往下越难拉
dampRateBegin: 1,
// 阻尼系数,下拉的距离大于offset时,改变下拉区域高度比例;值越接近0,高度变化越小,表现为越往下越难拉
dampRate: 0.3,
// 回弹动画时间
bounceTime: 300,
successAnim: {
// 下拉刷新结束后是否有成功动画,默认为false,如果想要有成功刷新xxx条数据这种操作,请设为true,并实现对应hook函数
isEnable: false,
duration: 300,
},
// 下拉时会提供回调,默认为null不会执行
onPull: null,
// 取消时回调
onCalcel: null,
callback: noop,
},
// 上拉有关
up: {
// 默认没有锁定,可以通过API动态设置
isLock: false,
// 是否自动上拉加载-初始化是是否自动
isAuto: true,
// 是否默认显示上拉进度条,可以通过API改变
isShowUpLoading: true,
// 距离底部高度(到达该高度即触发)
offset: 100,
loadFull: {
// 开启配置后,只要没满屏幕,就会自动加载
isEnable: true,
delay: 300,
},
// 滚动时会提供回调,默认为null不会执行
onScroll: null,
callback: noop,
},
// 容器
container: '#minirefresh',
// 是否锁定横向滑动,如果锁定则原生滚动条无法滑动
isLockX: true,
// 是否显示滚动条
isScrollBar: true,
// 是否使用body对象的scroll而不是minirefresh-scroll对象的scroll
// 开启后一个页面只能有一个下拉刷新,否则会有冲突
isUseBodyScroll: false,
};
const CLASS_HIDDEN_SCROLLBAR = 'minirefresh-hide-scrollbar';
class Core {
/**
* 构造函数
* @param {Object} options 配置信息
* @constructor
*/
constructor(options) {
osMixin(this);
this.options = extend(true, {}, defaultSetting, options);
this.container = selector(this.options.container);
// scroll的dom-wrapper下的第一个节点,作用是down动画时的操作
this.contentWrap = this.container.children[0];
// 默认是整个container进行滚动
// 但是为了兼容body的滚动,拆分为两个对象方便处理
// 如果是使用body的情况,scrollWrap恒为body
// 注意,滑动不是指下拉时的translate(这时候时contentWrap),而是只默认的原生滑动
this.scrollWrap = this.options.isUseBodyScroll ? document.body : this.container;
if (!this.options.isScrollBar) {
this.container.classList.add(CLASS_HIDDEN_SCROLLBAR);
}
// 初始化的hook
this._initHook && this._initHook(this.options.down.isLock, this.options.up.isLock);
// 生成一个Scroll对象 ,对象内部处理滑动监听
this.scroller = new Scroll(this);
// 内部处理scroll
this._initEvent();
// 如果初始化时锁定了,需要触发锁定,避免没有锁定时解锁(会触发逻辑bug)
this.options.up.isLock && this._lockUpLoading(this.options.up.isLock);
this.options.down.isLock && this._lockDownLoading(this.options.down.isLock);
}
_initEvent() {
// 缓存options,这部分的配置是不允许reset的
const options = this.options;
this.scroller.on('initScroll', () => {
this._initScrollHook && this._initScrollHook();
});
this.scroller.on('downLoading', (isHideLoading) => {
!isHideLoading && this._downLoaingHook && this._downLoaingHook();
options.down.callback && options.down.callback();
});
this.scroller.on('cancelLoading', () => {
this._cancelLoaingHook && this._cancelLoaingHook();
options.down.onCalcel && options.down.onCalcel();
});
this.scroller.on('pull', (downHight, downOffset) => {
this._pullHook && this._pullHook(downHight, downOffset);
options.down.onPull && options.down.onPull(downHight, downOffset);
});
this.scroller.on('upLoading', () => {
this._upLoaingHook && this._upLoaingHook(this.options.up.isShowUpLoading);
options.up.callback && options.up.callback(this.options.up.isShowUpLoading);
});
this.scroller.on('resetUpLoading', () => {
this._resetUpLoadingHook && this._resetUpLoadingHook();
});
this.scroller.on('scroll', (scrollTop) => {
this._scrollHook && this._scrollHook(scrollTop);
options.up.onScroll && options.up.onScroll(scrollTop);
});
// 检查是否允许普通的加载中,如果返回false,就代表自定义下拉刷新,通常自己处理
this.scroller.hook('beforeDownLoading', (downHight, downOffset) => (
!this._beforeDownLoadingHook
|| this._beforeDownLoadingHook(downHight, downOffset)));
}
/**
* 内部执行,结束下拉刷新
* @param {Boolean} isSuccess 是否下拉请求成功
* @param {String} successTips 需要更新的成功提示
* 在开启了成功动画时,往往成功的提示是需要由外传入动态更新的,譬如 update 10 news
*/
_endDownLoading(isSuccess, successTips) {
if (!this.options.down) {
// 防止没传down导致错误
return;
}
if (this.scroller.downLoading) {
// 必须是loading时才允许执行对应hook
const successAnim = this.options.down.successAnim.isEnable;
let successAnimTime = this.options.down.successAnim.duration;
if (successAnim) {
// 如果有成功动画
this._downLoaingSuccessHook && this._downLoaingSuccessHook(isSuccess, successTips);
} else {
// 默认为没有成功动画
successAnimTime = 0;
}
setTimeout(() => {
// 成功动画结束后就可以重置位置了
this.scroller.endDownLoading();
// 触发结束hook
this._downLoaingEndHook && this._downLoaingEndHook(isSuccess);
}, successAnimTime);
}
}
/**
* 锁定上拉加载
* 将开启和禁止合并成一个锁定API
* @param {Boolean} isLock 是否锁定
*/
_lockUpLoading(isLock) {
this.options.up.isLock = isLock;
this._lockUpLoadingHook && this._lockUpLoadingHook(isLock);
}
/**
* 锁定下拉刷新
* @param {Boolean} isLock 是否锁定
*/
_lockDownLoading(isLock) {
this.options.down.isLock = isLock;
this._lockDownLoadingHook && this._lockDownLoadingHook(isLock);
}
/**
* 刷新minirefresh的配置,关键性的配置请不要更新,如容器,回调等
* @param {Object} options 新的配置,会覆盖原有的
*/
refreshOptions(options) {
this.options = extend(true, {}, this.options, options);
this.scroller.refreshOptions(this.options);
this._lockUpLoading(this.options.up.isLock);
this._lockDownLoading(this.options.down.isLock);
this._refreshHook && this._refreshHook();
}
/**
* 结束下拉刷新
* @param {Boolean} isSuccess 是否请求成功,这个状态会中转给对应主题
* @param {String} successTips 需要更新的成功提示
* 在开启了成功动画时,往往成功的提示是需要由外传入动态更新的,譬如 update 10 news
*/
endDownLoading(isSuccess = true, successTips) {
this._endDownLoading(isSuccess, successTips);
// 同时恢复上拉加载的状态,注意,此时没有传isShowUpLoading,所以这个值不会生效
if (this.options.down.isAutoResetUpLoading) {
this.resetUpLoading();
}
}
/**
* 重置上拉加载状态,如果是没有更多数据后重置,会变为可以继续上拉加载
*/
resetUpLoading() {
this.scroller.resetUpLoading();
}
/**
* 结束上拉加载
* @param {Boolean} isFinishUp 是否结束上拉加载,如果结束,就相当于变为了没有更多数据,无法再出发上拉加载了
* 结束后必须reset才能重新开启
*/
endUpLoading(isFinishUp) {
if (this.scroller.upLoading) {
this.scroller.endUpLoading(isFinishUp);
this._upLoaingEndHook && this._upLoaingEndHook(isFinishUp);
}
}
triggerUpLoading() {
this.scroller.triggerUpLoading();
}
triggerDownLoading() {
this.scroller.scrollTo(0);
this.scroller.triggerDownLoading();
}
/**
* 滚动到指定的y位置
* @param {Number} y 需要滑动到的top值
* @param {Number} duration 单位毫秒
*/
scrollTo(y, duration) {
this.scroller.scrollTo(y, duration);
}
/**
* 获取当前的滚动位置
* @return {Number} 返回当前的滚动位置
*/
getPosition() {
return this.scrollWrap.scrollTop;
}
}
export default Core;