├── .babelrc
├── .gitignore
├── .project
├── LICENSE
├── README.md
├── dist
├── _debug
│ ├── css
│ │ ├── images
│ │ │ ├── img_pulltorefresh_skin2_1.png
│ │ │ ├── img_pulltorefresh_skin2_2.png
│ │ │ └── img_pulltorefresh_skin2_3.png
│ │ └── pulltorefresh.skin.css
│ ├── pulltorefresh.bizlogic.impl.js
│ ├── pulltorefresh.bizlogic.impl2.js
│ ├── pulltorefresh.core.js
│ ├── pulltorefresh.skin.default.js
│ ├── pulltorefresh.skin.native.js
│ ├── pulltorefresh.skin.type1.js
│ ├── pulltorefresh.skin.type2.js
│ ├── pulltorefresh.skin.type3.js
│ ├── pulltorefresh.skin.type4.js
│ └── pulltorefresh.skin.type5.js
├── css
│ ├── images
│ │ ├── img_pulltorefresh_skin2_1.png
│ │ ├── img_pulltorefresh_skin2_2.png
│ │ └── img_pulltorefresh_skin2_3.png
│ └── pulltorefresh.skin.css
├── pulltorefresh.bizlogic.impl.js
├── pulltorefresh.bizlogic.impl2.js
├── pulltorefresh.core.js
├── pulltorefresh.skin.default.js
├── pulltorefresh.skin.native.js
├── pulltorefresh.skin.type1.js
├── pulltorefresh.skin.type2.js
├── pulltorefresh.skin.type3.js
├── pulltorefresh.skin.type4.js
└── pulltorefresh.skin.type5.js
├── examples
├── README.md
├── css
│ ├── common.css
│ ├── common_search.css
│ ├── demo_pullRefresh_skin_bizlogic_multi.css
│ ├── demo_pullRefresh_skin_multi_iscroll5.css
│ └── mui.min.css
├── fonts
│ └── mui.ttf
├── html
│ ├── bizlogic-impl
│ │ ├── demo_pullRefresh_skin_bizlogic_complex.html
│ │ ├── demo_pullRefresh_skin_bizlogic_default.html
│ │ ├── demo_pullRefresh_skin_bizlogic_default_Interface.html
│ │ └── demo_pullRefresh_skin_bizlogic_default_Interface_custom.html
│ ├── index.html
│ ├── multi-scroller
│ │ ├── demo_pullRefresh_skin_multi_Iscroll5.html
│ │ ├── demo_pullRefresh_skin_multi_bizlogic_default.html
│ │ └── demo_pullRefresh_skin_multi_skin_default.html
│ ├── other
│ │ ├── demo_elasticCircle.html
│ │ ├── demo_pullRefresh_only_pulldown.html
│ │ └── demo_pullRefresh_only_pullup.html
│ ├── skin
│ │ ├── demo_pullRefresh_skin_default.html
│ │ ├── demo_pullRefresh_skin_native.html
│ │ ├── demo_pullRefresh_skin_type1.html
│ │ ├── demo_pullRefresh_skin_type2.html
│ │ ├── demo_pullRefresh_skin_type3.html
│ │ ├── demo_pullRefresh_skin_type4.html
│ │ └── demo_pullRefresh_skin_type5.html
│ └── 可以参考不基于IScroll的.js
├── img
│ └── gallery
│ │ ├── img_testgallery1.jpg
│ │ ├── img_testgallery2.jpg
│ │ ├── img_testgallery3.jpg
│ │ └── img_testgallery4.jpg
├── js
│ ├── demo_pullRefresh_multi_skin.js
│ ├── demo_pullRefresh_skin.js
│ ├── epoint.moapi.v2.min.js
│ ├── mui.js
│ └── mustache.min.js
└── json
│ └── testList.json
├── gulpfile.js
├── package.json
├── src
├── README.md
├── core
│ ├── handedata.js
│ ├── pulltorefresh.core.js
│ ├── pulltorefresh.iscroll.probe.js
│ └── pulltorefresh.js
├── css
│ ├── images
│ │ ├── img_pulltorefresh_skin2_1.png
│ │ ├── img_pulltorefresh_skin2_2.png
│ │ └── img_pulltorefresh_skin2_3.png
│ └── pulltorefresh.skin.css
├── pulltorefresh.bizlogic.impl.js
├── pulltorefresh.bizlogic.impl2.js
├── pulltorefresh.skin.default.js
├── pulltorefresh.skin.native.js
├── pulltorefresh.skin.type1.js
├── pulltorefresh.skin.type2.js
├── pulltorefresh.skin.type3.js
├── pulltorefresh.skin.type4.js
└── pulltorefresh.skin.type5.js
└── staticresource
└── img
├── effect1.gif
├── effect2.gif
├── effect3.gif
├── effect4.gif
├── effect5.gif
└── effect6.gif
/.babelrc:
--------------------------------------------------------------------------------
1 | { "presets": ["es2015"] }
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | *.project
61 | .svn
62 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | demo.webpack.pulltorefresh
4 |
5 |
6 |
7 |
8 |
9 | com.aptana.ide.core.unifiedBuilder
10 |
11 |
12 |
13 |
14 |
15 | com.aptana.projects.webnature
16 |
17 |
18 |
19 | 1491361987988
20 |
21 | 26
22 |
23 | org.eclipse.ui.ide.multiFilter
24 | 1.0-name-matches-false-false-node_modules
25 |
26 |
27 |
28 | 1496904618570
29 |
30 | 26
31 |
32 | org.eclipse.ui.ide.multiFilter
33 | 1.0-name-matches-false-false-node_modules
34 |
35 |
36 |
37 | 1496988019611
38 |
39 | 26
40 |
41 | org.eclipse.ui.ide.multiFilter
42 | 1.0-name-matches-false-false-node_modules
43 |
44 |
45 |
46 | 1497925692470
47 |
48 | 26
49 |
50 | org.eclipse.ui.ide.multiFilter
51 | 1.0-name-matches-false-false-node_modules
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Lichun Dai
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## H5下拉刷新皮肤系列
2 | 基于`IScroll`的全套下拉刷新皮肤。各式各样的皮肤。以及下拉刷新实现基类供自定义UI实现。
3 |
4 | ### Notice
5 |
6 | 这个老版本的已经不再维护了,后续维护新版下拉刷新
7 |
8 | 地址:
9 |
10 | [https://github.com/minirefresh/minirefresh](https://github.com/minirefresh/minirefresh)
11 |
12 | 特点:
13 |
14 | 零依赖(原生JS实现,不依赖于任何库)
15 |
16 | 多主题,官方提供多种主题(包括默认,applet-仿小程序,drawer3d-3d抽屉效果,taobao-仿淘宝等)
17 |
18 | 易拓展,三层架构,专门抽取UI层面,方便实现各种的主题,实现一套主题非常方便,并且几乎可以实现任何效果
19 |
20 | 高性能,良好的兼容性。动画采用css3+硬件加速,在大部分手机上都非常流畅,支持和各种Scroll的嵌套(包括mui scroll,IScroll,Swipe等),支持Vue
21 |
22 | 优雅的API和源码,API设计科学,简单,源码严谨,所有源码通过ESlint检测,并提供完善的showcase和文档
23 |
24 | 另外,Npm上也有相应发布。
25 |
26 | ### Effect(效果)
27 |
28 | * 效果1
29 | 
30 |
31 | * 效果2
32 | 
33 |
34 | * 效果3
35 | 
36 |
37 | * 效果4
38 | 
39 |
40 | * 效果5
41 | 
42 |
43 | * 效果6
44 | 
45 |
46 | * 示例页面
47 | [下拉刷新皮肤示例](https://dailc.github.io/pulltorefresh-h5-iscroll/examples/html/)
48 |
49 | ### How To Use(使用)
50 |
51 | * Require(引入脚本)
52 |
53 | ```
54 |
55 | ```
56 | 可以将`skin.default`替换为对应的皮肤
57 |
58 | * HTML Structure(页面结构)
59 |
60 | ```
61 |
66 | ```
67 | 譬如,如果基于mui的,就可以是`mui-scroller-wrapper`,其它的自己定义对应scroll样式即可
68 |
69 | * JS Initialization(JS初始化)
70 |
71 | ```
72 | var pullToRefreshObj = new PullToRefreshTools.skin.default({
73 | // 这里用默认设置
74 | container: '#pullrefresh',
75 | // down为null表示不要下拉刷新
76 | down: {
77 | callback: pullDownRefreshCallback,
78 | // 是否显示成功动画
79 | isSuccessTips: true,
80 | },
81 | // up为null为不要上拉
82 | // 上拉有关
83 | up: {
84 | // 是否自动上拉加载-初始化是是否自动
85 | auto: true,
86 |
87 | callback: pullUpRefreshCallback
88 | },
89 | scroll: {
90 | bounceTime: 500,
91 | // 回弹动画时间
92 | // 下拉刷新和上拉加载成功动画的时间
93 | successAnimationTime: 500
94 | },
95 | });
96 | ```
97 | 具体可以将`PullToRefreshTools.skin.default`换为其它皮肤,其它更多操作参考示例
98 |
99 | * API(暴露出来的方法)
100 |
101 | ```
102 | * finished //这是一个属性,用来控制当前上拉加载是否可用
103 | * refresh() //重置状态。譬如上拉加载关闭后需要手动refresh重置finished状态
104 | * pulldownLoading() //主动触发一个下拉刷新的动画(同时会触发下拉回调)
105 | * pullupLoading() //主动触发一个上拉加载的动画(同时会触发上拉回调)
106 | * endPullDownToRefresh() //关闭下拉刷新动画,重置状态
107 | * endPullUpToRefresh(finished) //关闭上拉加载动画,重置状态,如果finished,则不允许在上拉,除非再次refresh()
108 | ```
109 | 关于更多的使用说明(如自定义UI类的实现,请参考最后的更多说明)
110 |
111 | * (Notice)注意
112 | * `default`皮肤和`type1`皮肤依赖于`mui.css`
113 | * 其它皮肤依赖于样式文件`pulltorefresh.skin.css`
114 | * 另外,也支持`require`方式引入,`require`后,请通过全局变量方式来使用,如`PullToRefresh.skin.defaults`
115 |
116 | * (Global Variable)相应的全局变量与JS文件
117 |
118 | ```
119 | IScroll // 内部的IScroll5保留的全局变量
120 | PullToRefreshTools.core // pulltorefresh.core.js,可以通过这个文件实现自定义皮肤
121 | PullToRefreshTools.skin.defaults // pulltorefresh.skin.default.js 需要和关键字区分
122 | PullToRefreshTools.skin.type1 // pulltorefresh.skin.type1.js
123 | PullToRefreshTools.skin.type2 // pulltorefresh.skin.type2.js
124 | PullToRefreshTools.skin.type3 // pulltorefresh.skin.type3.js
125 | PullToRefreshTools.skin.type4 // pulltorefresh.skin.type4.js
126 | PullToRefreshTools.skin.natives // pulltorefresh.skin.native.js 需要和保留字区分
127 | PullToRefreshTools.bizlogic // pulltorefresh.bizlogic.implxx.js 系列,依赖于核心下拉刷新文件(随便一个皮肤即可)
128 | ```
129 |
130 |
131 | ### 关于
132 | 下拉刷新所有皮肤内部都默认引入了IScroll5 **但是进行了一些轻微改动(主要是增加了功能,用来方便下拉刷新的实现,并不影响原本使用)**
133 | 因此如果项目中其它地方有用到IScroll5,无需在引入,直接通过`IScroll`即可使用
134 |
135 | 后续会定期更新皮肤
136 |
137 | ### 更多说明
138 |
139 | * [examples目录结构说明](https://github.com/dailc/pulltorefresh-h5-iscroll/tree/master/examples/html)
140 | * [源码使用说明](https://github.com/dailc/pulltorefresh-h5-iscroll/tree/master/src/)
141 |
142 | #### 相关博文
143 |
144 | * [H5下拉刷新,多种皮肤,便于拓展!](http://www.jianshu.com/p/ef3183adb896)
145 |
146 | ## 更新日志
147 |
148 | * 20170410
149 | * 版本`1.0.0`
150 | * 增加cmd引入支持
151 | * 修复IScroll内部`maxScrollY`引起的冲突
152 | * 20170518
153 | * 修复关闭上拉加载后,重复下拉刷新报错的bug
154 | * 20170526
155 | * 版本`2.0.0`
156 | * 从源码层面重新修改命名空间
157 | * 后续命名层面不会再有大的改动
158 | * 20170601
159 | * 内部源码优化
160 | * 不影响以前的使用
161 | * 20170608
162 | * 修改项目名称,同步修改示例资源路径
163 | * 20170609
164 | * 源码目录结构微调,不影响使用
165 | * 20170612
166 | * showcase将`targetPullToRefresh`简化为`skin`
167 | * 20170615
168 | * 版本`3.0.0`
169 | * API设计简化
170 | * 去除不推荐使用的mui皮肤
171 | * IScroll打包到内部
172 | * 20170621
173 | * 更新`native`皮肤引入时的bug-由于重复打包core,导致命名冲突
174 | * 20170626
175 | * 下拉刷新内部优化,调用方式默认变为`new`的使用方式
176 | * 20170711
177 | * 下拉刷新`bizlogic`的重构,优化代码
178 | * 20170814
179 | * 新增`type5`皮肤,仿照微信小程序的下拉效果
180 | * 20170830
181 | * 这个库已经不再维护,全力维护更好的下拉刷新[minirefresh](https://github.com/minirefresh/minirefresh)
182 |
183 | ## License (MIT)
--------------------------------------------------------------------------------
/dist/_debug/css/images/img_pulltorefresh_skin2_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/dist/_debug/css/images/img_pulltorefresh_skin2_1.png
--------------------------------------------------------------------------------
/dist/_debug/css/images/img_pulltorefresh_skin2_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/dist/_debug/css/images/img_pulltorefresh_skin2_2.png
--------------------------------------------------------------------------------
/dist/_debug/css/images/img_pulltorefresh_skin2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/dist/_debug/css/images/img_pulltorefresh_skin2_3.png
--------------------------------------------------------------------------------
/dist/_debug/pulltorefresh.skin.native.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 创建时间: 2017/03/28
4 | * 版本: [1.0, 2017/05/26 ]
5 | * 版权: dailc
6 | * 描述: 这个皮肤是ejs或钉钉下的下拉刷新,使用了他们自带提供的原生下拉刷新,以及自定义生成上拉加载
7 | * 注意:分别在ejs下或者钉钉下依赖对应的库文件
8 | */
9 | (function(exports, CommonTools) {
10 |
11 | var isSupportTouch = "ontouchend" in document ? true : false;
12 | //默认的下拉刷新每一个页面只支持一个,所以是单例模式
13 | var instance;
14 | //这里的isPullDown是指从上往下拉
15 | //pullup是指从下往上拉
16 | var isTouch = false,
17 | isPullDown = false;
18 | //定义一个global
19 | var global = {};
20 | /**
21 | * 默认的设置参数
22 | */
23 | var defaultSetting = {
24 | //下拉有关
25 | down: {
26 | callback: CommonTools.noop
27 | },
28 | //上拉有关
29 | up: {
30 | //是否自动上拉加载-初始化是是否自动
31 | auto: false,
32 | //是否隐藏那个加载更多动画,达到默认加载效果
33 | show: true,
34 | contentrefresh: '正在加载...',
35 | callback: CommonTools.noop
36 | },
37 | //注意,传给Mui时可以传 #id形式或者是 原生dom对象
38 | element: '#pullrefresh'
39 | };
40 | var pulluploadingTips = '{{contentrefresh}}
';
41 | /**
42 | * @description 兼容ejs情况下的下拉刷新
43 | * 去除多余dom
44 | * @param {HTMLElement} elem 对应的dom
45 | */
46 | function compatibleNative(elem) {
47 | //计划改变,ejs下拉刷新不使用scroll,否则不好计算什么时候可以滑动,而是直接去除这个dom
48 | // mui(elem).scroll({
49 | // deceleration: 0.0005 //flick 减速系数,系数越大,滚动速度越慢,滚动距离越小,默认值0.0006
50 | // });
51 | if (typeof elem === 'string') {
52 | elem = document.querySelector(elem);
53 | }
54 | if (CommonTools.os.ejs || CommonTools.os.dd) {
55 | //去除dom,ejs下拉刷新不需要scroll
56 | var pullRefreshDom = elem;
57 | pullRefreshDom.classList.remove('mui-scroll-wrapper');
58 | var scrollDom = pullRefreshDom.querySelector('.mui-scroll');
59 | if (scrollDom) {
60 | //pullRefreshDom.innerHTML = scrollDom.innerHTML;
61 | scrollDom.classList.remove('mui-scroll');
62 | }
63 | } else {
64 |
65 | }
66 |
67 | }
68 |
69 | /**
70 | * @description 将string字符串转为html对象,默认创一个div填充
71 | * @param {String} strHtml 目标字符串
72 | * @return {HTMLElement} 返回处理好后的html对象,如果字符串非法,返回null
73 | */
74 | function pareseStringToHtml(strHtml) {
75 | if (strHtml == null || typeof(strHtml) != "string") {
76 | return null;
77 | }
78 | //创一个灵活的div
79 | var i, a = document.createElement("div");
80 | var b = document.createDocumentFragment();
81 | a.innerHTML = strHtml;
82 | while (i = a.firstChild) b.appendChild(i);
83 | return b;
84 | }
85 | /**
86 | * @description 浏览器视口的高度
87 | * @return {Number} 返回具体高度
88 | */
89 | function getWinHeight() {
90 | var windowHeight = 0;
91 | if (document.compatMode == "CSS1Compat") {
92 | windowHeight = document.documentElement.clientHeight;
93 | } else {
94 | windowHeight = document.body.clientHeight;
95 | }
96 | return windowHeight;
97 | }
98 | /**
99 | * @description 获取滚动条在Y轴上的滚动距离
100 | * @return {Number} 返回具体距离
101 | */
102 | function getScrollTop() {
103 | var scrollTop = 0,
104 | bodyScrollTop = 0,
105 | documentScrollTop = 0;
106 | if (document.body) {
107 | bodyScrollTop = document.body.scrollTop || 0;
108 | }
109 | if (document.documentElement) {
110 | documentScrollTop = document.documentElement.scrollTop || 0;
111 | }
112 | scrollTop = (bodyScrollTop > documentScrollTop) ? bodyScrollTop : documentScrollTop;
113 | return scrollTop;
114 | }
115 | /**
116 | * @description 获取文档的总高度
117 | * @return {Number} 返回具体高度
118 | */
119 | function getScrollHeight() {
120 | var scrollHeight = 0,
121 | bodyScrollHeight = 0,
122 | documentScrollHeight = 0;
123 | if (document.body) {
124 | bodyScrollHeight = document.body.scrollHeight;
125 | }
126 |
127 | if (document.documentElement) {
128 | documentScrollHeight = document.documentElement.scrollHeight;
129 | }
130 | scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
131 | return scrollHeight;
132 | }
133 | /**
134 | * @constructor 构造函数
135 | * @description 定义下拉刷新构造函数
136 | * @param {HTMLElement} elem
137 | * @param {JSON} options
138 | */
139 | function PullRefresh(options) {
140 | options = CommonTools.extend(true, {}, defaultSetting, options);
141 |
142 | var $this = this;
143 | var elem = options.container;
144 | $this.loadingUp = false;
145 | $this.finished = false;
146 | $this.options = options;
147 | if (typeof elem === 'string') {
148 | elem = document.querySelector(elem);
149 | }
150 | $this.elem = elem;
151 |
152 | //增加class
153 | $this.elem.classList.add('pulltorefresh-native-type');
154 | setPullDownFunc();
155 |
156 | if ($this.options.down) {
157 | if (CommonTools.os.dd) {
158 | //钉钉的下拉刷新
159 | //开启下拉刷新
160 | dd.ui.pullToRefresh.enable({
161 | onSuccess: function() {
162 | //alert('下拉刷新成功,立刻收起');
163 | $this.options.down.callback && $this.options.down.callback();
164 | },
165 | onFail: function() {
166 | //alert('下拉刷新失败');
167 | dd.ui.pullToRefresh.stop();
168 | }
169 | });
170 | } else {
171 | //ejs的下拉刷新
172 | //开启下拉刷新
173 | if (ejs.nativeUI) {
174 | ejs.nativeUI.pullToRefresh.enable(function() {
175 | $this.options.down.callback && $this.options.down.callback();
176 | });
177 | } else {
178 | ejs.ui.pullToRefresh.enable({
179 | success: function() {
180 | $this.options.down.callback && $this.options.down.callback();
181 | },
182 | error: function() {
183 | //alert('下拉刷新失败');
184 | ejs.ui.pullToRefresh.stop();
185 | }
186 | });
187 | }
188 |
189 | }
190 | }
191 |
192 | //兼容原生环境下的处理
193 | compatibleNative($this.elem || '#pullrefresh');
194 | }
195 | /**
196 | * @description 主动上拉加载更多
197 | */
198 | PullRefresh.prototype.pullupLoading = function() {
199 | if (instance.options.up) {
200 | //加载更多
201 | loadMoreAnimation(true);
202 | //触发上拉回调
203 | instance.options.up.callback && instance.options.up.callback();
204 | }
205 | };
206 | PullRefresh.prototype.endPullUpToRefresh = function(isNoMore) {
207 | if (isNoMore) {
208 | this.finished = true;
209 | }
210 | if (instance.options.up) {
211 | //去除加载更多动画
212 | loadMoreAnimation(false);
213 | }
214 | };
215 | PullRefresh.prototype.endPullDownToRefresh = function() {
216 | //关闭下拉刷新
217 | if (CommonTools.os.dd) {
218 | dd.ui.pullToRefresh.stop();
219 | } else if (CommonTools.os.ejs) {
220 | if (ejs.nativeUI) {
221 | ejs.nativeUI.pullToRefresh.stop();
222 | } else {
223 | ejs.ui.pullToRefresh.stop();
224 | }
225 | }
226 |
227 | };
228 | PullRefresh.prototype.refresh = function(refresh) {
229 | this.finished = false;
230 | };
231 | /**
232 | * @description 设置下拉刷新相关
233 | */
234 | function setPullDownFunc() {
235 | var x = 0,
236 | y = 0,
237 | scrollTop = 0;
238 | var b = document.body;
239 | //监听touch时间,模拟下拉
240 | var touchStartEvt = isSupportTouch ? 'touchstart' : 'mousedown';
241 | b.addEventListener(touchStartEvt, function(evt) {
242 | //console.log('touchstart');
243 | var touch;
244 | if (isSupportTouch) {
245 | touch = evt.touches[0]; //获取第一个触点
246 | } else {
247 | touch = evt;
248 | }
249 | x = Number(touch.pageX); //页面触点X坐标
250 | y = Number(touch.pageY); //页面触点Y坐标
251 | scrollTop = b.scrollTop;
252 | isTouch = true;
253 | //console.log('x = ' + x);
254 | //console.log('y = ' + y);
255 | //console.log('scrollTop = ' + scrollTop);
256 | });
257 | var touchEndEvt = isSupportTouch ? 'touchend' : 'mouseup';
258 | b.addEventListener(touchEndEvt, function(evt) {
259 | //console.log('touchend');
260 | isTouch = false;
261 | isPullDown = false;
262 | });
263 | var touchMoveEvt = isSupportTouch ? 'touchmove' : 'mousemove';
264 | b.addEventListener(touchMoveEvt, function(evt) {
265 | //console.log('touchmove');
266 | var touch;
267 | if (isSupportTouch) {
268 | touch = evt.touches[0]; //获取第一个触点
269 | } else {
270 | touch = evt;
271 | }
272 | var mx = Number(touch.pageX); //页面触点X坐标
273 | var my = Number(touch.pageY); //页面触点Y坐标
274 |
275 | //console.log("isTouch = " + isTouch)
276 | //console.log("y-my = " + (y-my))
277 | //console.log("b.scrollTop = " + b.scrollTop);
278 | if (isTouch) {
279 | if (my - y > 30) {
280 | if (b.scrollTop == 0) {
281 | if (!isPullDown) {
282 | console.log("PullDown");
283 | isPullDown = true;
284 | }
285 | }
286 | }
287 | //alert('scrollTop:'+scrollTop+',b.scrollTop:'+b.scrollTop+',y:'+y+',my:'+my);
288 | if (y - my > 100) {
289 |
290 | if (scrollTop == b.scrollTop) {
291 | if (!instance.loadingUp) {
292 | //console.log('my = ' + my);
293 | //console.log('y = ' + y);
294 | //console.log('scrollTop = ' + scrollTop);
295 | //console.log('b.scrollTop = ' + b.scrollTop);
296 | //console.log("pullup,finish:"+instance.finished);
297 | if (!instance.finished) {
298 | if (instance.options.up) {
299 | //加载更多
300 | loadMoreAnimation(true);
301 | //触发上拉回调
302 | instance.options.up.callback && instance.options.up.callback();
303 | }
304 | }
305 |
306 | }
307 | }
308 | }
309 |
310 | }
311 | });
312 |
313 | //ios下的补救措施
314 | var scrollFunc = function() {
315 | var y = getScrollTop();
316 | var slider = document.getElementById('sliderSegmentedControl');
317 |
318 | if ((y + getWinHeight()) === getScrollHeight()) {
319 | if (!instance.loadingUp) {
320 | if (!instance.finished) {
321 | if (instance.options.up) {
322 | //加载更多
323 | loadMoreAnimation(true);
324 | //触发上拉回调
325 | instance.options.up.callback && instance.options.up.callback();
326 | }
327 | }
328 | }
329 |
330 | }
331 | };
332 | document.onscroll = scrollFunc;
333 | }
334 | /**
335 | * @description 控制加载更多
336 | * @param {Boolean} more
337 | */
338 | function loadMoreAnimation(more) {
339 |
340 | var dom = instance.elem;
341 | if (!dom) {
342 | return;
343 | }
344 |
345 | if (more) {
346 | if (!instance.loadingUp) {
347 | //显示loading
348 | var content = instance.options.up.contentrefresh || '正在加载...';
349 | pulluploadingTips = pulluploadingTips.replace('{{contentrefresh}}', content);
350 | dom.appendChild(pareseStringToHtml(pulluploadingTips));
351 | instance.loadingUp = true;
352 | }
353 | } else {
354 | if (instance.loadingUp) {
355 | //隐藏loading
356 | var loadingDom = dom.querySelector('.mui-pull-bottom-tips');
357 | loadingDom && loadingDom.parentNode.removeChild(loadingDom);
358 | instance.loadingUp = false;
359 | }
360 | }
361 | }
362 |
363 | function initPullToRefresh(options) {
364 | if(instance) {
365 | return instance;
366 | }
367 | instance = new PullRefresh(options);
368 |
369 | if (options.up && options.up.auto) {
370 | // 如果设置了auto,则自动上拉一次
371 | instance.pullupLoading();
372 | }
373 |
374 | return instance;
375 | }
376 |
377 | CommonTools.namespace('skin.natives', initPullToRefresh);
378 |
379 | })({}, PullToRefreshTools);
--------------------------------------------------------------------------------
/dist/css/images/img_pulltorefresh_skin2_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/dist/css/images/img_pulltorefresh_skin2_1.png
--------------------------------------------------------------------------------
/dist/css/images/img_pulltorefresh_skin2_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/dist/css/images/img_pulltorefresh_skin2_2.png
--------------------------------------------------------------------------------
/dist/css/images/img_pulltorefresh_skin2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/dist/css/images/img_pulltorefresh_skin2_3.png
--------------------------------------------------------------------------------
/dist/css/pulltorefresh.skin.css:
--------------------------------------------------------------------------------
1 | /**
2 | * pulltorefresh-h5-iscroll - 一款基于IScroll5的H5下拉刷新实现,包括多种皮肤的实现
3 | * @version v3.0.0
4 | * @author
5 | */
6 | .hidden{visibility:hidden}.pull-bottom-pocket,.pull-top-pocket{width:100%;height:74px;font-weight:700;font-size:.8em;background:inherit;overflow:hidden}.pull-block{text-align:center}.pull-caption{display:inline-block;margin-left:5px;text-align:center;vertical-align:middle;color:#777}.pull-bottom-pocket.loading .pull-loading-icon,.pulltorefresh-type2 .pull-top-pocket .pull-loading-icon{display:inline-block;vertical-align:middle;opacity:.5;width:40px;height:40px;background:url(images/img_pulltorefresh_skin2_1.png) 0 0 no-repeat;-webkit-background-size:40px 80px;-ms-background-size:40px 80px;background-size:40px 80px;-webkit-transition-property:-webkit-transform;-ms-transition-property:-webkit-transform;-webkit-transition-duration:250ms;-ms-transition-duration:250ms}.pulltorefresh-type2 .pull-top-pocket .pull-loading-icon{-webkit-transform:rotate(0) translateZ(0);-ms-transform:rotate(0) translateZ(0)}.pulltorefresh-type2 .pull-top-pocket.flip .pull-loading-icon{-webkit-transform:rotate(-180deg) translateZ(0);-ms-transform:rotate(-180deg) translateZ(0)}.pulltorefresh-type2 .pull-top-pocket.success .pull-loading-icon{display:inline-block;width:30px;height:30px;background:url(images/img_pulltorefresh_skin2_3.png) 0 0 no-repeat}.pulltorefresh-type2 .pull-top-pocket.error .pull-loading-icon{display:inline-block;width:30px;height:30px;background:url(images/img_pulltorefresh_skin2_2.png) 0 0 no-repeat}.pull-bottom-pocket.loading .pull-loading-icon,.pulltorefresh-type2 .loading .pull-loading-icon{background-position:0 100%;-webkit-transform:rotate(0) translateZ(0);-ms-transform:rotate(0) translateZ(0);-webkit-transition-duration:0s;-ms-transition-duration:0s;-webkit-animation-name:loading;-ms-animation-name:loading;-webkit-animation-duration:1s;-ms-animation-duration:1s;-webkit-animation-iteration-count:infinite;-ms-animation-iteration-count:infinite;-webkit-animation-timing-function:linear;-ms-animation-timing-function:linear}.pull-bottom-pocket.nomore .pull-loading-icon{display:none}.pulltorefresh-type3 .pull-top-pocket .pull-loading-icon{position:absolute;top:10px;left:50%;margin-left:-50px;width:40px;height:40px;border-radius:100%;z-index:100}.pulltorefresh-type3 .pull-top-pocket .pull-caption{position:absolute;top:10px;left:50%;line-height:40px}.pulltorefresh-type3 .pull-top-canvas{overflow:hidden;background-color:#fafafa;border-radius:40px;box-shadow:0 4px 10px #bbb;width:40px;height:40px;margin:0 auto}.pulltorefresh-type3 .pull-top-canvas canvas{width:40px}@-webkit-keyframes loading{from{-webkit-transform:rotate(0) translateZ(0)}to{-webkit-transform:rotate(360deg) translateZ(0)}}@-ms-keyframes loading{from{-ms-transform:rotate(0) translateZ(0)}to{-ms-transform:rotate(360deg) translateZ(0)}}.pulltorefresh-type4 .pull-top-pocket{position:absolute;height:100%}.pulltorefresh-type4 .pull-top-pocket .pull-caption{position:absolute;top:40px;width:100%;margin-left:0;line-height:40px;color:#d00324;text-align:center}.pulltorefresh-type4 .pie-anim-container{position:absolute;width:100%}.pie-anim-container .pie{position:absolute;width:40px;height:40px;left:50%;top:50%;margin-left:-20px;margin-top:-20px;border-radius:50%;-webkit-border-radius:50%;background:#d00324;color:#f2f3f4}.pie-anim-container .left-pie{display:block;background:currentColor;position:#d00324;left:0;top:0;height:100%;border-radius:100% 0 0 100%/50%;border-width:0;width:50%;transform-origin:left;-webkit-transform-origin:left;-moz-transform-origin:left}.pie-anim-container .anim-pie{position:absolute;top:0;left:0;width:50%;height:100%;display:block;border-width:0;border-radius:100% 0 0 100%/50%;-webkit-border-radius:100% 0 0 100%/50%;background:#d00324;transform-origin:right;-webkit-transform-origin:right;-moz-transform-origin:right}.pie-anim-container .fresh-progress{position:absolute;left:50%;top:50%;width:24px;height:24px;display:block;margin-left:-12px;margin-top:-12px;border:3px solid transparent;border-radius:50%;-webkit-border-radius:50%;border-right-color:#fff;border-top-color:#fff;border-left-color:#fff;border-left:2px;z-index:10}.pie-anim-container .progress-arrow{position:absolute;bottom:-4px;right:-1px;width:0;height:0;border-top:6px solid transparent;border-bottom:6px solid transparent;border-right:6px solid #fff;transform:rotate(-48deg);-webkit-transform:rotate(-48deg);-moz-transform:rotate(-48deg)}.pie-anim-container .error-tips{position:absolute;left:50%;top:50%;margin-left:-7px;margin-top:-15px;opacity:0}.pie-anim-container .error-tips .txt{color:#fff}.pie-anim-container .error-tips .left.txt{margin-left:-5px}.pie-anim-container .error-tips .right.txt{margin-left:10px}.pie-anim-container .moon{position:absolute;left:-2px;top:22px;width:18px;height:18px;border-radius:38%;-webkit-border-radius:38%;box-shadow:0 -3px 0 0 #fff;-webkit-box-shadow:0 -3px 0 0 #fff}.pie-anim-container .success-tips{opacity:0}.pie-anim-container .arrow-left{position:absolute;top:50%;left:50%;width:0;height:0;margin-left:-7px;margin-top:-11px;border-top:10px solid transparent;border-bottom:15px solid transparent;border-right:15px solid #fff;transform:rotate(-88deg);-webkit-transform:rotate(-88deg);-moz-transform:rotate(-88deg)}.pie-anim-container .arrow-right{position:absolute;top:50%;left:50%;width:0;height:0;margin-left:-9px;margin-top:-17px;border-top:15px solid transparent;border-bottom:15px solid transparent;border-right:15px solid #d00324;transform:rotate(-88deg);-webkit-transform:rotate(-88deg);-moz-transform:rotate(-88deg)}@keyframes progressrotate{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0);-moz-transform:rotate(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg);-moz-transform:rotate(360deg)}}@-webkit-keyframes progressrotate{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0);-moz-transform:rotate(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg);-moz-transform:rotate(360deg)}}@keyframes piebackground{0%{background:#d00324}100%{background:currentcolor}}@-webkit-keyframes piebackground{0%{background:#d00324}100%{background:currentcolor}}@keyframes pieanimaindex{0%{z-index:10;transform:rotate(360deg);-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg)}50%{z-index:0;transform:rotate(180deg);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg)}100%{z-index:0;transform:rotate(0);-webkit-transform:rotate(0);-moz-transform:rotate(0)}}@-webkit-keyframes pieanimaindex{0%{z-index:10;transform:rotate(360deg);-webkit-transform:rotate(360deg);-moz-transform:rotate(360deg)}50%{z-index:0;transform:rotate(180deg);-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg)}100%{z-index:0;transform:rotate(0);-webkit-transform:rotate(0);-moz-transform:rotate(0)}}.pulltorefresh-mui-type .mui-pull-top-tips{position:absolute;top:-20px;left:50%;margin-left:-25px;width:40px;height:40px;border-radius:100%;z-index:100}.pulltorefresh-mui-type .mui-bar~.mui-pull-top-tips{top:24px}.pulltorefresh-mui-type .mui-pull-top-wrapper{width:42px;height:42px;display:block;text-align:center;background-color:#efeff4;border:1px solid #ddd;border-radius:25px;background-clip:padding-box;box-shadow:0 4px 10px #bbb;overflow:hidden}.pulltorefresh-mui-type .mui-pull-top-tips.mui-transitioning{-webkit-transition-duration:.2s;transition-duration:.2s}.pulltorefresh-mui-type .mui-pull-top-tips .mui-pull-loading{margin:0}.pulltorefresh-mui-type .mui-pull-top-wrapper .mui-icon,.pulltorefresh-mui-type .mui-pull-top-wrapper .mui-spinner{margin-top:7px}.pulltorefresh-mui-type .mui-pull-bottom-tips{text-align:center;background-color:inherit;font-size:15px;line-height:40px;color:#777}.pulltorefresh-mui-type .mui-pull-top-canvas{overflow:hidden;background-color:#fafafa;border-radius:40px;box-shadow:0 4px 10px #bbb;width:40px;height:40px;margin:0 auto}.pulltorefresh-mui-type .mui-pull-top-canvas canvas{width:40px}.pulltorefresh-native-type .mui-pull-bottom-tips{position:relative;height:auto;width:100%;background-color:inherit;font-size:15px;color:#777}.pulltorefresh-native-type .mui-pull-bottom-tips .mui-spinner{position:absolute;top:0;left:40%}.pulltorefresh-native-type .mui-pull-bottom-tips .mui-pull-loading{position:absolute;top:2px;left:40%;margin-left:30px}.pulltorefresh-type5 .pull-top-pocket{position:absolute;top:0;left:0;height:50px}.ball-beat>div{opacity:.3;background-color:#444;width:8px;height:8px;border-radius:100%;margin:2px;display:inline-block}.loading .ball-beat div{-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation:ball-beat 1s 0s infinite linear;animation:ball-beat 1s 0s infinite linear}.loading .ball-beat>div:nth-child(2){-webkit-animation-delay:.3s!important;animation-delay:.3s!important}.loading .ball-beat>div:nth-child(3){-webkit-animation-delay:.6s!important;animation-delay:.6s!important}.pulltorefresh-type5 .pull-block{margin-top:10px}.pulltorefresh-type5 .pull-top-pocket .pull-block{margin-top:20px}.pulltorefresh-type5 .pull-caption{margin-left:0;font-size:13px}.pulltorefresh-type5 .loading .pull-loading-icon{display:inline-block;width:16px;height:16px;background:0 0;border-radius:50%;border:1px solid gray;margin-right:8px;border-bottom-color:transparent;vertical-align:middle}.pulltorefresh-type5 .loading .rotate{-webkit-animation:progressrotate .6s linear infinite;animation:progressrotate .6s linear infinite}@-webkit-keyframes ball-beat{50%{opacity:1;-webkit-transform:scale(.75);transform:scale(.75)}100%{opacity:.3;-webkit-transform:scale(1);transform:scale(1)}}@keyframes ball-beat{50%{opacity:1;-webkit-transform:scale(.75);transform:scale(.75)}100%{opacity:.3;-webkit-transform:scale(1);transform:scale(1)}}
--------------------------------------------------------------------------------
/dist/pulltorefresh.bizlogic.impl.js:
--------------------------------------------------------------------------------
1 | /**
2 | * pulltorefresh-h5-iscroll - 一款基于IScroll5的H5下拉刷新实现,包括多种皮肤的实现
3 | * @version v3.0.0
4 | * @author
5 | */
6 | !function(e,t){!function(){e.dataProcessFn=[],e.dataProcess=function(t,s){s=s||{};var n=[].slice.call(arguments),i={code:0,message:"",data:null,status:0,debugInfo:{type:"未知数据格式"}};if(null==s.dataPath)return t;"string"==typeof s.dataPath&&(s.dataPath=[s.dataPath]);var a=s.isDebug||!1,o=s.dataPath,r=e.dataProcessFn,l=r.length,u=o.length,c=!1;if(!t)return i.message="接口返回数据为空!",i;n.push(i);for(var h=0;!c&&h0){for(var i="",a=0,o=e.length;a=n.initPageIndex?this.currPage:n.initPageIndex,n.error&&n.error(e,t,s)},_successRequest:function(e){var t=this.options;if(!e)return t.isDebug&&console.log("warning***返回的数据为空,请注意!"),this.isShouldNoMoreData=!1,void this._refreshState(!1);t.isDebug&&console.log("下拉刷新返回数据:"+JSON.stringify(e)),e=t.dataChange?t.dataChange(e):this._dataChangeDefault(e);var s=this._render(e);this.loadingMoreSuccess&&(this.loadingMoreSuccess(),this.loadingMoreSuccess=null),t.success&&"function"==typeof t.success&&t.success(e,this.isPullDown||this.currPage==t.initPageIndex),this._refreshState(!0,s)},_refreshState:function(e,t){var s=this.instance;t=t||0,s.setSuccessTips&&s.setSuccessTips("更新"+t+"条数据"),this.isPullDown&&(s.endPullDownToRefresh(e),s.finished&&(s.refresh(!0),this.isShouldNoMoreData=!0)),this.isShouldNoMoreData?s.endPullUpToRefresh(!1,e):s.endPullUpToRefresh(!0,e),this.loadingDown=!1,this.loadingUp=!1},_addEvent:function(){var e=this.listContainer,t=this.options,s=t.itemClick;"function"==typeof s&&mui(e).on(a,t.itemSelector,s)},refresh:function(){var e=this.options;e.up&&this.instance.enablePullUp?this.loadingUp||(this._clearResponseEl(),this.currPage=e.initPageIndex-1,this.loadingMore()):(this._clearResponseEl(),this._pullDownCallback())},loadingMore:function(e){var t=this.instance;this.loadingMoreSuccess=e,this.instance.finished&&(this.instance.refresh(!0),this.isShouldNoMoreData=!0),t.pullupLoading()},disablePullupToRefresh:function(){this.pullToRefreshInstance.disablePullupToRefresh()},enablePullupToRefresh:function(){this.pullToRefreshInstance.enablePullupToRefresh()},destroy:function(){mui(listContainer).off(),this.container=null,this.listContainer=null,this.instance=null,this.options=null}},e.namespace("bizlogic",s)}(PullToRefreshTools);
--------------------------------------------------------------------------------
/dist/pulltorefresh.bizlogic.impl2.js:
--------------------------------------------------------------------------------
1 | /**
2 | * pulltorefresh-h5-iscroll - 一款基于IScroll5的H5下拉刷新实现,包括多种皮肤的实现
3 | * @version v3.0.0
4 | * @author
5 | */
6 | !function(e,t){!function(){e.dataProcessFn=[],e.dataProcess=function(t,o){o=o||{};var s=[].slice.call(arguments),n={code:0,message:"",data:null,status:0,debugInfo:{type:"未知数据格式"}};if(null==o.dataPath)return t;"string"==typeof o.dataPath&&(o.dataPath=[o.dataPath]);var a=o.isDebug||!1,i=o.dataPath,l=e.dataProcessFn,r=l.length,c=i.length,u=!1;if(!t)return n.message="接口返回数据为空!",n;s.push(n);for(var p=0;!u&&p=s.defaultInitPageNum?s.currPage:s.defaultInitPageNum,s.options.bizlogic.errorRequestCallback&&s.options.bizlogic.errorRequestCallback(e,t,o)},s.prototype.successRequest=function(e,t){var s=this;if(!e)return s.options.isDebug&&console.log("warning***返回的数据为空,请注意!"),s.isShouldNoMoreData=!1,void s.refreshState(!1);if(s.options.isDebug&&console.log("下拉刷新返回数据:"+JSON.stringify(e)),e=s.options.bizlogic.changeResponseDataCallback?s.options.bizlogic.changeResponseDataCallback(e):s.defaultChangeResponseData(e),s.options.bizlogic.isRendLitemplateAuto){s.isPullDown&&s.clearResponseEl();var n=0;if(window.Mustache)if(e&&Array.isArray(e)&&e.length>0){for(var a="",i=0;in?o:n}function i(){var e=0,o=0,n=0;return document.body&&(o=document.body.scrollHeight),document.documentElement&&(n=document.documentElement.scrollHeight),e=o-n>0?o:n}function s(e){e=o.extend(!0,{},h,e);var t=this,l=e.container;t.loadingUp=!1,t.finished=!1,t.options=e,"string"==typeof l&&(l=document.querySelector(l)),t.elem=l,t.elem.classList.add("pulltorefresh-native-type"),c(),t.options.down&&(o.os.dd?dd.ui.pullToRefresh.enable({onSuccess:function(){t.options.down.callback&&t.options.down.callback()},onFail:function(){dd.ui.pullToRefresh.stop()}}):ejs.nativeUI?ejs.nativeUI.pullToRefresh.enable(function(){t.options.down.callback&&t.options.down.callback()}):ejs.ui.pullToRefresh.enable({success:function(){t.options.down.callback&&t.options.down.callback()},error:function(){ejs.ui.pullToRefresh.stop()}})),n(t.elem||"#pullrefresh")}function c(){var e=0,o=0,n=0,t=document.body,s=d?"touchstart":"mousedown";t.addEventListener(s,function(l){var u;u=d?l.touches[0]:l,e=Number(u.pageX),o=Number(u.pageY),n=t.scrollTop,m=!0});var c=d?"touchend":"mouseup";t.addEventListener(c,function(e){m=!1,f=!1});var p=d?"touchmove":"mousemove";t.addEventListener(p,function(e){var l;l=d?e.touches[0]:e;var u=(Number(l.pageX),Number(l.pageY));m&&(u-o>30&&0==t.scrollTop&&(f||(console.log("PullDown"),f=!0)),o-u>100&&n==t.scrollTop&&(a.loadingUp||a.finished||a.options.up&&(r(!0),a.options.up.callback&&a.options.up.callback())))});var h=function(){var e=u();document.getElementById("sliderSegmentedControl");e+l()===i()&&(a.loadingUp||a.finished||a.options.up&&(r(!0),a.options.up.callback&&a.options.up.callback()))};document.onscroll=h}function r(e){var o=a.elem;if(o)if(e){if(!a.loadingUp){var n=a.options.up.contentrefresh||"正在加载...";v=v.replace("{{contentrefresh}}",n),o.appendChild(t(v)),a.loadingUp=!0}}else if(a.loadingUp){var l=o.querySelector(".mui-pull-bottom-tips");l&&l.parentNode.removeChild(l),a.loadingUp=!1}}function p(e){return a?a:(a=new s(e),e.up&&e.up.auto&&a.pullupLoading(),a)}var a,d="ontouchend"in document,m=!1,f=!1,h={down:{callback:o.noop},up:{auto:!1,show:!0,contentrefresh:"正在加载...",callback:o.noop},element:"#pullrefresh"},v='{{contentrefresh}}
';s.prototype.pullupLoading=function(){a.options.up&&(r(!0),a.options.up.callback&&a.options.up.callback())},s.prototype.endPullUpToRefresh=function(e){e&&(this.finished=!0),a.options.up&&r(!1)},s.prototype.endPullDownToRefresh=function(){o.os.dd?dd.ui.pullToRefresh.stop():o.os.ejs&&(ejs.nativeUI?ejs.nativeUI.pullToRefresh.stop():ejs.ui.pullToRefresh.stop())},s.prototype.refresh=function(e){this.finished=!1},o.namespace("skin.natives",p)}({},PullToRefreshTools);
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | ### 说明
2 | 这里是showcase,更多说明请参考src目录的README
--------------------------------------------------------------------------------
/examples/css/common.css:
--------------------------------------------------------------------------------
1 | /**
2 | * 公用css
3 | */
4 |
5 | body,
6 | .mui-content {
7 | background-color: #FFFFFF;
8 | }
9 |
10 |
11 | /*重写头部导航栏bar背景色,颜色为 187bc2*/
12 |
13 | .mui-bar-nav {
14 | background-color: #187bc2;
15 | z-index: 20;
16 | }
17 |
18 |
19 | /*重写title的颜色,666666
20 | title大小为18px*/
21 |
22 | .mui-title {
23 | font-size: 18px;
24 | color: #ffffff;
25 | }
26 |
27 |
28 | /*重写返回按钮颜色*/
29 |
30 | .mui-icon-left-nav {
31 | color: #FFFFFF;
32 | }
33 |
34 |
35 | /*右侧的info图标*/
36 |
37 | .mui-icon-info-filled {
38 | color: #FFFFFF;
39 | }
40 |
41 |
42 | /*右侧文字按钮白色*/
43 |
44 | .mui-bar-nav .mui-text-right {
45 | color: #FFFFFF;
46 | }
47 |
48 |
49 | /*重写按钮*/
50 |
51 | .mui-btn-block {
52 | height: 45px;
53 | line-height: 45px;
54 | padding: 0;
55 | }
56 |
57 | .common-hidden {
58 | display: none;
59 | }
60 |
61 |
62 | /**
63 | *
64 | */
65 |
66 | .tips-container {
67 | width: 100%;
68 | font-size: 15px;
69 | overflow: hidden;
70 | word-break: break-all;
71 | }
72 |
73 | .compare-container {
74 | width: 44%;
75 | }
76 |
77 | .tips-content {
78 | display: block;
79 | color: #007aff;
80 | }
81 |
82 | .show-img img {
83 | width: 200px;
84 | height: 200px;
85 | border: 1px solid #FAFAFA;
86 | }
87 |
88 | .red {
89 | color: red;
90 | }
91 |
92 | .f20 {
93 | font-size: 20px;
94 | }
95 |
96 | .m50 {
97 | margin-top: 50px;
98 | }
99 |
100 | .m15 {
101 | margin: 15px;
102 | }
103 | .mt10 {
104 | margin-top: 10px;
105 | }
106 | .mt35 {
107 | margin-top: 35px;
108 | }
109 |
110 | .mt50 {
111 | margin-top: 50px;
112 | }
113 |
114 | .pt0,
115 | .mui-bar-nav~.pt0 {
116 | padding-top: 0;
117 | }
118 |
119 | img {
120 | max-width: 100%;
121 | }
122 |
123 | /**
124 | * 最小化,变为1*1px挂在左上角
125 | * 之所以要这样是,有些原生如果隐藏不见,无法触发事件
126 | * 比如input file在4.x中隐藏不见无法触发click函数
127 | */
128 | .minSize {
129 | position: absolute;
130 | width: 1px;
131 | height: 1px;
132 | padding: 0;
133 | margin: 0;
134 | border: 0;
135 | opacity: 0;
136 | }
137 |
138 |
139 |
--------------------------------------------------------------------------------
/examples/css/common_search.css:
--------------------------------------------------------------------------------
1 | /**
2 | * 定义搜索的公用样式
3 | * dailc
4 | */
5 | .fixed-searchbar {
6 | /*变为absolute布局,防止ios里有bug*/
7 | position: absolute;
8 | top: 0;
9 | left: 0;
10 | width: 100%;
11 | z-index: 1;
12 | }
13 |
14 | /*************搜索栏目相关**********************/
15 | /***通用样式***/
16 | .common-input-row {
17 | position: relative;
18 | height: 44px;
19 | padding: 6px 10px 6px 10px;
20 | background-color: #eaeaea;
21 | overflow: hidden;
22 | }
23 | .common-input-row .btn-search {
24 | display: block;
25 | float: left;
26 | width: 22px;
27 | height: 22px;
28 | margin: 4px 0 0 8px;
29 | color: #333;
30 | }
31 | .common-input-row .btn-search:active {
32 | color: #8cd2a3;
33 | }
34 | /*输入框*/
35 | .common-input-row input[type=text].common-input-clear {
36 | max-width: 80%;
37 | height: 30px;
38 | margin: 0 0 0 8px;
39 | padding-left: 2px;
40 | font-size: 12px;
41 | line-height: 14px;
42 | border: 0;
43 | }
44 | .common-input-row .common-input {
45 | background-color: #fff;
46 | border: 1px solid #e0e0e0;
47 | border-radius: 30px;
48 | }
49 | /***样式1***/
50 | /*目前无自定义*/
51 | /***样式2***/
52 | /*样式2的搜索框*/
53 | .common-input-type2 .common-input {
54 | margin-right: 30px;
55 | /*定制下border*/
56 | border-radius: 5px;
57 | }
58 | /*样式2 中的右侧文字*/
59 | .common-input-type2 .btn-search-txt {
60 | position: absolute;
61 | right: 5px;
62 | top: 10px;
63 | font-size: 14px;
64 | color: #000000;
65 | }
66 | .common-input-type2 .btn-search-txt:active {
67 | color: #333333;
68 | }
69 | /***样式3***/
70 | .show-simple3 {
71 | background: #469bfe;
72 | }
73 | .common-input-type3 {
74 | height: 52px;
75 | padding: 12px 7px;
76 | border: 0;
77 | background: transparent;
78 | }
79 | .common-input-type3 .common-input {
80 | height: 28px;
81 | font-size: 15px;
82 | border: 0;
83 | border-radius: 6px;
84 | background: #2684f0;
85 | text-align: center;
86 | }
87 | .common-input-type3 .btn-search,
88 | .common-input-type3 .btn-search-txt {
89 | display: inline-block;
90 | float: none;
91 | color: #fff;
92 | }
93 | .common-input-type3 .btn-search {
94 | font-size: 20px;
95 | }
96 | .common-input-type3 .btn-search-txt:active,
97 | .common-input-type3 .btn-search:active {
98 | color: #469bfe;
99 | }
100 | /***样式4,mui的搜索,思路为两层,一层是搜索,一层是placeholder***/
101 | /*去除背景*/
102 | .common-input-type4 .mui-input-row {
103 | margin: 7px;
104 | }
105 | .common-input-type4 .mui-placeholder {
106 | color: #f0f0f0;
107 | }
108 |
109 | .common-input-type4 input[type=search] {
110 | background-color: #f0f0f0;
111 | }
112 |
--------------------------------------------------------------------------------
/examples/css/demo_pullRefresh_skin_bizlogic_multi.css:
--------------------------------------------------------------------------------
1 | /**
2 | * div 自定义下拉刷新
3 | */
4 |
5 | .mui-bar~.mui-content .mui-fullscreen {
6 | top: 44px;
7 | height: auto;
8 | }
9 |
10 |
11 | /******************滑动栏目***************************/
12 |
13 | .mui-control-content {
14 | background-color: #f5f5f5;
15 | }
16 |
17 | .mui-control-content .mui-loading {
18 | margin-top: 50px;
19 | }
20 |
21 |
22 | /*重写一个比较短的滑动条*/
23 |
24 | .mui-segmented-control.mui-segmented-control-inverted~.mui-slider-progress-bar {
25 | background-color: transparent;
26 | }
27 |
28 | .mui-segmented-control.mui-segmented-control-inverted~.mui-slider-progress-bar .custom-progressbar {
29 | height: 2px;
30 | width: 60%;
31 | margin: auto;
32 | background-color: #558fff;
33 | }
34 |
35 | .mui-segmented-control .mui-active {
36 | color: #558fff;
37 | }
38 |
39 |
40 | /*栏目标题*/
41 |
42 | .mui-control-item {
43 | position: relative;
44 | font-size: 15px;
45 | color: #666666;
46 | }
47 |
48 |
49 | /*绘制标题右侧的线*/
50 |
51 | .control-line-item:after {
52 | position: absolute;
53 | top: 25%;
54 | left: 0;
55 | width: 1px;
56 | height: 50%;
57 | content: '';
58 | border-left: 1px solid #e6e6e6;
59 | }
--------------------------------------------------------------------------------
/examples/css/demo_pullRefresh_skin_multi_iscroll5.css:
--------------------------------------------------------------------------------
1 | /**
2 | * div 自定义下拉刷新
3 | */
4 |
5 | .mui-bar~.mui-content .mui-fullscreen {
6 | top: 44px;
7 | height: auto;
8 | }
9 |
10 |
11 | /******************滑动栏目***************************/
12 |
13 | .mui-control-content {
14 | background-color: #f5f5f5;
15 | }
16 |
17 | .mui-control-content .mui-loading {
18 | margin-top: 50px;
19 | }
20 |
21 |
22 | /*重写一个比较短的滑动条*/
23 |
24 | .mui-segmented-control.mui-segmented-control-inverted~.mui-slider-progress-bar {
25 | background-color: transparent;
26 | }
27 |
28 | .mui-segmented-control.mui-segmented-control-inverted~.mui-slider-progress-bar .custom-progressbar {
29 | height: 2px;
30 | width: 60%;
31 | margin: auto;
32 | background-color: #558fff;
33 | }
34 |
35 | .mui-segmented-control .mui-active {
36 | color: #558fff;
37 | }
38 |
39 |
40 | /*栏目标题*/
41 |
42 | .mui-control-item {
43 | position: relative;
44 | font-size: 15px;
45 | color: #666666;
46 | }
47 |
48 |
49 | /*绘制标题右侧的线*/
50 |
51 | .control-line-item:after {
52 | position: absolute;
53 | top: 25%;
54 | left: 0;
55 | width: 1px;
56 | height: 50%;
57 | content: '';
58 | border-left: 1px solid #e6e6e6;
59 | }
60 |
61 | .mui-fullscreen .mui-segmented-control~.mui-slider-group {
62 | position: absolute;
63 | top: 40px;
64 | bottom: 0;
65 | width: 100%;
66 | height: 600px;
67 | }
68 | .mui-slider-scroll {
69 | position: absolute;
70 | z-index: 1;
71 | width: 100%;
72 | height: 100%;
73 | }
74 |
--------------------------------------------------------------------------------
/examples/fonts/mui.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/examples/fonts/mui.ttf
--------------------------------------------------------------------------------
/examples/html/bizlogic-impl/demo_pullRefresh_skin_bizlogic_complex.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 下拉刷新皮肤 bizlogic-complex
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
86 |
87 |
97 |
98 |
99 |
100 |
101 |
102 |
134 |
135 |
--------------------------------------------------------------------------------
/examples/html/bizlogic-impl/demo_pullRefresh_skin_bizlogic_default.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 下拉刷新皮肤 bizlogic-impl
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
30 |
31 |
41 |
42 |
43 |
44 |
45 |
46 |
59 |
60 |
--------------------------------------------------------------------------------
/examples/html/bizlogic-impl/demo_pullRefresh_skin_bizlogic_default_Interface.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 下拉刷新皮肤 bizlogic-impl2
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
30 |
31 |
41 |
42 |
43 |
44 |
45 |
46 |
68 |
69 |
--------------------------------------------------------------------------------
/examples/html/bizlogic-impl/demo_pullRefresh_skin_bizlogic_default_Interface_custom.html:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | 下拉刷新皮肤 bizlogic-impl2
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
29 |
30 |
40 |
41 |
42 |
43 |
44 |
45 |
77 |
78 |
--------------------------------------------------------------------------------
/examples/html/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | H5下拉刷新皮肤系列
8 |
9 |
10 |
11 |
12 |
15 |
16 |
skin
17 |
37 |
multi-scroller
38 |
46 |
other
47 |
61 |
bizlogic
62 |
63 | -
64 | impl
65 |
66 | -
67 | impl2
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/examples/html/multi-scroller/demo_pullRefresh_skin_multi_Iscroll5.html:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 下拉刷新皮肤 multi Iscroll5
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
63 |
64 |
65 |
66 |
67 |
108 |
109 |
--------------------------------------------------------------------------------
/examples/html/multi-scroller/demo_pullRefresh_skin_multi_bizlogic_default.html:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 下拉刷新皮肤 multi bizlogic多div刷新
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
66 |
67 |
68 |
82 |
83 |
84 |
85 |
86 |
87 |
133 |
134 |
--------------------------------------------------------------------------------
/examples/html/multi-scroller/demo_pullRefresh_skin_multi_skin_default.html:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 下拉刷新皮肤 multi skin多div刷新
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
67 |
68 |
69 |
70 |
71 |
72 |
79 |
80 |
--------------------------------------------------------------------------------
/examples/html/other/demo_pullRefresh_only_pulldown.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 下拉刷新皮肤 only-pulldown
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
40 |
41 |
42 |
43 |
44 |
52 |
53 |
--------------------------------------------------------------------------------
/examples/html/other/demo_pullRefresh_only_pullup.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 下拉刷新皮肤 only-pullup
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
25 |
40 |
41 |
42 |
43 |
44 |
52 |
53 |
--------------------------------------------------------------------------------
/examples/html/skin/demo_pullRefresh_skin_default.html:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | 下拉刷新皮肤 default
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
34 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
--------------------------------------------------------------------------------
/examples/html/skin/demo_pullRefresh_skin_native.html:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 下拉刷新皮肤 native
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
32 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
68 |
69 |
--------------------------------------------------------------------------------
/examples/html/skin/demo_pullRefresh_skin_type1.html:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | 下拉刷新皮肤 type1
21 |
22 |
23 |
24 |
30 |
31 |
32 |
33 |
37 |
52 |
53 |
54 |
55 |
56 |
63 |
64 |
--------------------------------------------------------------------------------
/examples/html/skin/demo_pullRefresh_skin_type2.html:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 下拉刷新皮肤 type2
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
--------------------------------------------------------------------------------
/examples/html/skin/demo_pullRefresh_skin_type3.html:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 下拉刷新皮肤 type3
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
--------------------------------------------------------------------------------
/examples/html/skin/demo_pullRefresh_skin_type4.html:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 下拉刷新皮肤 type4
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
--------------------------------------------------------------------------------
/examples/html/skin/demo_pullRefresh_skin_type5.html:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | 下拉刷新皮肤 type5
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
31 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
--------------------------------------------------------------------------------
/examples/html/可以参考不基于IScroll的.js:
--------------------------------------------------------------------------------
1 | + function(t) {
2 | "use strict";
3 | t.support = function() {
4 | var t = {
5 | touch: !!("ontouchstart" in window || window.DocumentTouch && document instanceof window.DocumentTouch)
6 | };
7 | return t
8 | }(), t.touchEvents = {
9 | start: t.support.touch ? "touchstart" : "mousedown",
10 | move: t.support.touch ? "touchmove" : "mousemove",
11 | end: t.support.touch ? "touchend" : "mouseup"
12 | }, t.getTouchPosition = function(t) {
13 | return t = t.originalEvent || t, "touchstart" === t.type || "touchmove" === t.type || "touchend" === t.type ? {
14 | x: t.targetTouches[0].pageX,
15 | y: t.targetTouches[0].pageY
16 | } : {
17 | x: t.pageX,
18 | y: t.pageY
19 | }
20 | }
21 | }($), + function(t) {
22 | "use strict";
23 | var s = function(s) {
24 | this.container = t(s), this.distance = 50, this.attachEvents()
25 | };
26 | s.prototype.touchStart = function(s) {
27 | if(!this.container.hasClass("refreshing")) {
28 | var i = t.getTouchPosition(s);
29 | this.start = i, this.diffX = this.diffY = 0
30 | }
31 | }, s.prototype.touchMove = function(s) {
32 | if(!this.container.hasClass("refreshing")) {
33 | if(!this.start) return !1;
34 | if(!(this.container.scrollTop() > 0)) {
35 | var i = t.getTouchPosition(s);
36 | if(this.diffX = i.x - this.start.x, this.diffY = i.y - this.start.y, !(this.diffY < 0)) return this.container.addClass("touching"), s.preventDefault(), s.stopPropagation(), this.diffY = Math.pow(this.diffY, .8), this.statusArea.css("height", this.diffY), this.diffY < this.distance ? this.container.removeClass("pull-up").addClass("pull-down") : this.container.removeClass("pull-down").addClass("pull-up"), !1
37 | }
38 | }
39 | }, s.prototype.touchEnd = function() {
40 | return this.start = !1, this.diffY <= 0 || this.container.hasClass("refreshing") ? void 0 : (this.container.removeClass("touching"), this.container.removeClass("pull-down pull-up"), Math.abs(this.diffY) <= this.distance ? this.statusArea.css("height", 0) : (this.statusArea.css("height", 50), this.container.addClass("refreshing"), this.container.trigger("pull-to-refresh")), !1)
41 | }, s.prototype.attachEvents = function() {
42 | var s = this.container;
43 | s.addClass("dropload");
44 | var i = ['', '
', '
', '
', '
下拉刷新
', '
释放刷新
', '
正在刷新
'];
45 | this.statusArea = t(i.join("")).prependTo(s), s.on(t.touchEvents.start, t.proxy(this.touchStart, this)), s.on(t.touchEvents.move, t.proxy(this.touchMove, this)), s.on(t.touchEvents.end, t.proxy(this.touchEnd, this))
46 | };
47 | var i = function(t) {
48 | new s(t)
49 | },
50 | o = function(s) {
51 | t(s).removeClass("refreshing"), t(s).find(".dropload-layer").css("height", 0)
52 | };
53 | t.fn.pullToRefresh = function() {
54 | return this.each(function() {
55 | i(this)
56 | })
57 | }, t.fn.pullToRefreshDone = function() {
58 | return this.each(function() {
59 | o(this)
60 | })
61 | }
62 | }($);
--------------------------------------------------------------------------------
/examples/img/gallery/img_testgallery1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/examples/img/gallery/img_testgallery1.jpg
--------------------------------------------------------------------------------
/examples/img/gallery/img_testgallery2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/examples/img/gallery/img_testgallery2.jpg
--------------------------------------------------------------------------------
/examples/img/gallery/img_testgallery3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/examples/img/gallery/img_testgallery3.jpg
--------------------------------------------------------------------------------
/examples/img/gallery/img_testgallery4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/examples/img/gallery/img_testgallery4.jpg
--------------------------------------------------------------------------------
/examples/js/demo_pullRefresh_multi_skin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 时间: 2017-04-05
4 | * 描述: 这里是同时生成多个下拉刷新
5 | */
6 | (function(exports) {
7 | /**
8 | * @description 初始化下拉刷新
9 | */
10 | function initPullRefreshList(pullToRefreshBase, options) {
11 | options = options || {};
12 | isAuto = options.isAuto||false;
13 | var container = options.container;
14 | var listContainer = options.listContainer;
15 | // 以下几个是测试加载更多,没有更多数据功能的
16 | // 当前页
17 | var currpage = 0;
18 | // 每页大小
19 | var pageSize = 10;
20 | // 总共大小,这里用来判断是否可以上拉加载
21 | // 实际业务中,可以不基于totalcount判断的,直接根据接口返回的数据进行判断
22 | var totalCount = 21;
23 | var pullToRefreshObj = new pullToRefreshBase({
24 | // 这里用默认设置
25 | container: container,
26 | down: {
27 | callback: pullDownRefreshCallback,
28 | // 是否显示成功动画
29 | isSuccessTips: true,
30 | },
31 | // down为null表示不要下拉刷新
32 | // down: null,
33 | // 上拉有关
34 | up: {
35 | // 是否自动上拉加载-初始化是是否自动
36 | auto: isAuto || false,
37 |
38 | callback: pullUpRefreshCallback
39 | },
40 | scroll: {
41 | bounceTime: 500, // 回弹动画时间
42 | // 下拉刷新和上拉加载成功动画的时间
43 | successAnimationTime: 500,
44 | // 是否嵌套,嵌套的话就不会preventDefault了
45 | eventPassthrough: 'horizontal'
46 | },
47 | });
48 |
49 | function pullDownRefreshCallback() {
50 | var self = this;
51 | // console.log("下拉刷新");
52 | setTimeout(function() {
53 | // 下拉刷新当前页变为0
54 | currpage = 0;
55 | // 测试每次添加10条
56 | testAppendData(pageSize, true);
57 | resetState(true);
58 | }, 1000);
59 | }
60 |
61 | function pullUpRefreshCallback() {
62 | var self = this;
63 | // console.log("上拉加载");
64 | setTimeout(function() {
65 | //请求数据
66 | //当前页++
67 | currpage++;
68 | //测试每次添加10条
69 | testAppendData(pageSize, false);
70 | resetState(false);
71 | }, 500);
72 |
73 | }
74 | /**
75 | * @description 测试添加数据
76 | * 真实情况添加的数据要根据接口返回数据映射
77 | * @param {Number} count 数量
78 | * @param {Boolean} isPullDown 是否是下拉刷新
79 | */
80 | function testAppendData(count, isPullDown) {
81 | isPullDown = isPullDown || false;
82 | var fragment = document.createDocumentFragment();
83 |
84 | var li;
85 | for(var i = 0; i < count; i++) {
86 | li = document.createElement('li');
87 | li.className = 'mui-table-view-cell';
88 | li.id = 'id_' + i;
89 | li.innerHTML = '测试item' + currpage + '-' + (i + 1);
90 | fragment.appendChild(li);
91 | }
92 |
93 | var dataContainer = document.querySelector(listContainer);
94 | // 添加-下拉刷新时先清除数据
95 | if(isPullDown) {
96 | dataContainer.innerHTML = '';
97 | }
98 | dataContainer.appendChild(fragment);
99 | }
100 | /**
101 | * @description 重置状态
102 | * @param {Boolean} isPullDown 是否是上拉加载
103 | */
104 | function resetState(isPullDown) {
105 | if(isPullDown) {
106 | pullToRefreshObj.endPullDownToRefresh();
107 | if(pullToRefreshObj.finished) {
108 | pullToRefreshObj.refresh(true);
109 | }
110 | }
111 | // 判断当前页的数据是否已经大于totalCount
112 | var itemLength = document.querySelector(listContainer).children.length;
113 | if(itemLength >= totalCount) {
114 | pullToRefreshObj.endPullUpToRefresh(true);
115 | } else {
116 | pullToRefreshObj.endPullUpToRefresh(false);
117 | }
118 | }
119 |
120 | function refresh() {
121 | // 清空dom
122 | document.querySelector(listContainer).innerHTML = '';
123 | currpage = -1; //这个必须要变
124 | // 手动将状态设为可以加载更多
125 | if(pullToRefreshObj.finished) {
126 | pullToRefreshObj.refresh(true);
127 | }
128 | // 当然也可以换为其它的刷新方法
129 | pullToRefreshObj.pullupLoading();
130 | }
131 | return {
132 | refresh: refresh
133 | };
134 | }
135 |
136 |
137 |
138 | exports.init = function(pullToRefreshObj) {
139 | initPullRefreshList(pullToRefreshObj, {
140 | isAuto:true,
141 | container:'#pullrefresh1',
142 | listContainer:'#listdata1'
143 | });
144 | initPullRefreshList(pullToRefreshObj, {
145 | isAuto:false,
146 | container:'#pullrefresh2',
147 | listContainer:'#listdata2'
148 | });
149 | };
150 |
151 | window.demoPullToRefresh = exports;
152 | })({});
--------------------------------------------------------------------------------
/examples/js/demo_pullRefresh_skin.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 时间: 2017-04-05
4 | * 描述: 这里将下拉刷新skin里的通用代码抽取出来了
5 | */
6 | (function(exports) {
7 | var pullToRefreshBiz,
8 | pullToRefreshBase;
9 | /**
10 | * @description 初始化下拉刷新
11 | */
12 | function initPullRefreshList(isAuto,disablePullDown,disablePullUp) {
13 | //以下几个是测试加载更多,没有更多数据功能的
14 | //当前页
15 | var currpage = 0;
16 | //每页大小
17 | var pageSize = 10;
18 | //总共大小,这里用来判断是否可以上拉加载
19 | //实际业务中,可以不基于totalcount判断的,直接根据接口返回的数据进行判断
20 | var totalCount = 21;
21 | var pullToRefreshObj = new pullToRefreshBase({
22 | //这里用默认设置
23 | container: '#pullrefresh',
24 | down: disablePullDown?null:{
25 | callback: pullDownRefreshCallback,
26 | //是否显示成功动画
27 | isSuccessTips: true,
28 | },
29 | //down为null表示不要下拉刷新
30 | //down: null,
31 | //上拉有关
32 | up: disablePullUp?null:{
33 | //是否自动上拉加载-初始化是是否自动
34 | auto: isAuto || false,
35 | isFastLoading: true,
36 | callback: pullUpRefreshCallback
37 | },
38 | scroll: {
39 | bounceTime: 500, //回弹动画时间
40 | //下拉刷新和上拉加载成功动画的时间
41 | successAnimationTime: 500
42 | },
43 | });
44 |
45 | function pullDownRefreshCallback() {
46 | var self = this;
47 | console.log("下拉刷新");
48 | setTimeout(function() {
49 | //下拉刷新当前页变为0
50 | currpage = 0;
51 | //测试每次添加10条
52 | testAppendData(pageSize, true);
53 | resetState(true);
54 | }, 1000);
55 | }
56 |
57 | function pullUpRefreshCallback() {
58 | var self = this;
59 | console.log("上拉加载");
60 | setTimeout(function() {
61 | //请求数据
62 | //当前页++
63 | currpage++;
64 | //测试每次添加10条
65 | testAppendData(pageSize, false);
66 | resetState(false);
67 | }, 500);
68 |
69 | }
70 | /**
71 | * @description 测试添加数据
72 | * 真实情况添加的数据要根据接口返回数据映射
73 | * @param {Number} count 数量
74 | * @param {Boolean} isPullDown 是否是下拉刷新
75 | */
76 | function testAppendData(count, isPullDown) {
77 | isPullDown = isPullDown || false;
78 | var fragment = document.createDocumentFragment();
79 |
80 | var li;
81 | for(var i = 0; i < count; i++) {
82 | li = document.createElement('li');
83 | li.className = 'mui-table-view-cell';
84 | li.id = 'id_' + i;
85 | li.innerHTML = '测试item' + currpage + '-' + (i + 1);
86 | fragment.appendChild(li);
87 | }
88 |
89 | var dataContainer = document.getElementById('listdata');
90 | //添加-下拉刷新时先清除数据
91 | if(isPullDown) {
92 | dataContainer.innerHTML = '';
93 | }
94 | dataContainer.appendChild(fragment);
95 | }
96 | /**
97 | * @description 重置状态
98 | * @param {Boolean} isPullDown 是否是上拉加载
99 | */
100 | function resetState(isPullDown) {
101 | if(isPullDown) {
102 | pullToRefreshObj.endPullDownToRefresh();
103 | if(pullToRefreshObj.finished) {
104 | pullToRefreshObj.refresh(true);
105 | }
106 | }
107 | //判断当前页的数据是否已经大于totalCount
108 | var itemLength = document.getElementById('listdata').children.length;
109 | if(itemLength >= totalCount) {
110 | pullToRefreshObj.endPullUpToRefresh(true);
111 | } else {
112 | pullToRefreshObj.endPullUpToRefresh(false);
113 | }
114 | }
115 |
116 | function refresh() {
117 | //清空dom
118 | document.getElementById('listdata').innerHTML = '';
119 | currpage = -1; //这个必须要变
120 | //手动将状态设为可以加载更多
121 | if(pullToRefreshObj.finished) {
122 | pullToRefreshObj.refresh(true);
123 | }
124 | //当然也可以换为其它的刷新方法
125 | pullToRefreshObj.pullupLoading();
126 | }
127 | return {
128 | refresh: refresh
129 | };
130 |
131 | }
132 |
133 | /**
134 | * @description 初始化
135 | */
136 | function initSearch() {
137 | document.querySelector('#input-searchName').addEventListener('change', function() {
138 | var searchValue = document.getElementById('input-searchName').value;
139 | // 刷新这个业务下拉刷新
140 | pullToRefreshBiz.refresh();
141 | console.log("搜索:" + searchValue);
142 | });
143 |
144 | }
145 |
146 | exports.init = function(pullToRefreshObj,disablePullDown,disablePullUp) {
147 | pullToRefreshBase = pullToRefreshObj;
148 | initSearch();
149 | pullToRefreshBiz = initPullRefreshList(true,disablePullDown,disablePullUp);
150 | };
151 |
152 | window.demoPullToRefresh = exports;
153 | })({});
--------------------------------------------------------------------------------
/examples/js/mustache.min.js:
--------------------------------------------------------------------------------
1 | (function defineMustache(global, factory) {
2 | if (typeof exports === "object" && exports && typeof exports.nodeName !== "string") {
3 | factory(exports)
4 | } else if (typeof define === "function" && define.amd) {
5 | define(["exports"], factory)
6 | } else {
7 | global.Mustache = {};
8 | factory(Mustache)
9 | }
10 | })(this, function mustacheFactory(mustache) {
11 | var objectToString = Object.prototype.toString;
12 | var isArray = Array.isArray || function isArrayPolyfill(object) {
13 | return objectToString.call(object) === "[object Array]"
14 | };
15 |
16 | function isFunction(object) {
17 | return typeof object === "function"
18 | }
19 |
20 | function typeStr(obj) {
21 | return isArray(obj) ? "array" : typeof obj
22 | }
23 |
24 | function escapeRegExp(string) {
25 | return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&")
26 | }
27 |
28 | function hasProperty(obj, propName) {
29 | return obj != null && typeof obj === "object" && propName in obj
30 | }
31 | var regExpTest = RegExp.prototype.test;
32 |
33 | function testRegExp(re, string) {
34 | return regExpTest.call(re, string)
35 | }
36 | var nonSpaceRe = /\S/;
37 |
38 | function isWhitespace(string) {
39 | return !testRegExp(nonSpaceRe, string)
40 | }
41 | var entityMap = {
42 | "&": "&",
43 | "<": "<",
44 | ">": ">",
45 | '"': """,
46 | "'": "'",
47 | "/": "/"
48 | };
49 |
50 | function escapeHtml(string) {
51 | return String(string).replace(/[&<>"'\/]/g, function fromEntityMap(s) {
52 | return entityMap[s]
53 | })
54 | }
55 | var whiteRe = /\s*/;
56 | var spaceRe = /\s+/;
57 | var equalsRe = /\s*=/;
58 | var curlyRe = /\s*\}/;
59 | var tagRe = /#|\^|\/|>|\{|&|=|!/;
60 |
61 | function parseTemplate(template, tags) {
62 | if (!template) return [];
63 | var sections = [];
64 | var tokens = [];
65 | var spaces = [];
66 | var hasTag = false;
67 | var nonSpace = false;
68 |
69 | function stripSpace() {
70 | if (hasTag && !nonSpace) {
71 | while (spaces.length) delete tokens[spaces.pop()]
72 | } else {
73 | spaces = []
74 | }
75 | hasTag = false;
76 | nonSpace = false
77 | }
78 | var openingTagRe, closingTagRe, closingCurlyRe;
79 |
80 | function compileTags(tagsToCompile) {
81 | if (typeof tagsToCompile === "string") tagsToCompile = tagsToCompile.split(spaceRe, 2);
82 | if (!isArray(tagsToCompile) || tagsToCompile.length !== 2) throw new Error("Invalid tags: " + tagsToCompile);
83 | openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + "\\s*");
84 | closingTagRe = new RegExp("\\s*" + escapeRegExp(tagsToCompile[1]));
85 | closingCurlyRe = new RegExp("\\s*" + escapeRegExp("}" + tagsToCompile[1]))
86 | }
87 | compileTags(tags || mustache.tags);
88 | var scanner = new Scanner(template);
89 | var start, type, value, chr, token, openSection;
90 | while (!scanner.eos()) {
91 | start = scanner.pos;
92 | value = scanner.scanUntil(openingTagRe);
93 | if (value) {
94 | for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
95 | chr = value.charAt(i);
96 | if (isWhitespace(chr)) {
97 | spaces.push(tokens.length)
98 | } else {
99 | nonSpace = true
100 | }
101 | tokens.push(["text", chr, start, start + 1]);
102 | start += 1;
103 | if (chr === "\n") stripSpace()
104 | }
105 | }
106 | if (!scanner.scan(openingTagRe)) break;
107 | hasTag = true;
108 | type = scanner.scan(tagRe) || "name";
109 | scanner.scan(whiteRe);
110 | if (type === "=") {
111 | value = scanner.scanUntil(equalsRe);
112 | scanner.scan(equalsRe);
113 | scanner.scanUntil(closingTagRe)
114 | } else if (type === "{") {
115 | value = scanner.scanUntil(closingCurlyRe);
116 | scanner.scan(curlyRe);
117 | scanner.scanUntil(closingTagRe);
118 | type = "&"
119 | } else {
120 | value = scanner.scanUntil(closingTagRe)
121 | } if (!scanner.scan(closingTagRe)) throw new Error("Unclosed tag at " + scanner.pos);
122 | token = [type, value, start, scanner.pos];
123 | tokens.push(token);
124 | if (type === "#" || type === "^") {
125 | sections.push(token)
126 | } else if (type === "/") {
127 | openSection = sections.pop();
128 | if (!openSection) throw new Error('Unopened section "' + value + '" at ' + start);
129 | if (openSection[1] !== value) throw new Error('Unclosed section "' + openSection[1] + '" at ' + start)
130 | } else if (type === "name" || type === "{" || type === "&") {
131 | nonSpace = true
132 | } else if (type === "=") {
133 | compileTags(value)
134 | }
135 | }
136 | openSection = sections.pop();
137 | if (openSection) throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
138 | return nestTokens(squashTokens(tokens))
139 | }
140 |
141 | function squashTokens(tokens) {
142 | var squashedTokens = [];
143 | var token, lastToken;
144 | for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
145 | token = tokens[i];
146 | if (token) {
147 | if (token[0] === "text" && lastToken && lastToken[0] === "text") {
148 | lastToken[1] += token[1];
149 | lastToken[3] = token[3]
150 | } else {
151 | squashedTokens.push(token);
152 | lastToken = token
153 | }
154 | }
155 | }
156 | return squashedTokens
157 | }
158 |
159 | function nestTokens(tokens) {
160 | var nestedTokens = [];
161 | var collector = nestedTokens;
162 | var sections = [];
163 | var token, section;
164 | for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
165 | token = tokens[i];
166 | switch (token[0]) {
167 | case "#":
168 | case "^":
169 | collector.push(token);
170 | sections.push(token);
171 | collector = token[4] = [];
172 | break;
173 | case "/":
174 | section = sections.pop();
175 | section[5] = token[2];
176 | collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
177 | break;
178 | default:
179 | collector.push(token)
180 | }
181 | }
182 | return nestedTokens
183 | }
184 |
185 | function Scanner(string) {
186 | this.string = string;
187 | this.tail = string;
188 | this.pos = 0
189 | }
190 | Scanner.prototype.eos = function eos() {
191 | return this.tail === ""
192 | };
193 | Scanner.prototype.scan = function scan(re) {
194 | var match = this.tail.match(re);
195 | if (!match || match.index !== 0) return "";
196 | var string = match[0];
197 | this.tail = this.tail.substring(string.length);
198 | this.pos += string.length;
199 | return string
200 | };
201 | Scanner.prototype.scanUntil = function scanUntil(re) {
202 | var index = this.tail.search(re),
203 | match;
204 | switch (index) {
205 | case -1:
206 | match = this.tail;
207 | this.tail = "";
208 | break;
209 | case 0:
210 | match = "";
211 | break;
212 | default:
213 | match = this.tail.substring(0, index);
214 | this.tail = this.tail.substring(index)
215 | }
216 | this.pos += match.length;
217 | return match
218 | };
219 |
220 | function Context(view, parentContext) {
221 | this.view = view;
222 | this.cache = {
223 | ".": this.view
224 | };
225 | this.parent = parentContext
226 | }
227 | Context.prototype.push = function push(view) {
228 | return new Context(view, this)
229 | };
230 | Context.prototype.lookup = function lookup(name) {
231 | var cache = this.cache;
232 | var value;
233 | if (cache.hasOwnProperty(name)) {
234 | value = cache[name]
235 | } else {
236 | var context = this,
237 | names, index, lookupHit = false;
238 | while (context) {
239 | if (name.indexOf(".") > 0) {
240 | value = context.view;
241 | names = name.split(".");
242 | index = 0;
243 | while (value != null && index < names.length) {
244 | if (index === names.length - 1) lookupHit = hasProperty(value, names[index]);
245 | value = value[names[index++]]
246 | }
247 | } else {
248 | value = context.view[name];
249 | lookupHit = hasProperty(context.view, name)
250 | } if (lookupHit) break;
251 | context = context.parent
252 | }
253 | cache[name] = value
254 | } if (isFunction(value)) value = value.call(this.view);
255 | return value
256 | };
257 |
258 | function Writer() {
259 | this.cache = {}
260 | }
261 | Writer.prototype.clearCache = function clearCache() {
262 | this.cache = {}
263 | };
264 | Writer.prototype.parse = function parse(template, tags) {
265 | var cache = this.cache;
266 | var tokens = cache[template];
267 | if (tokens == null) tokens = cache[template] = parseTemplate(template, tags);
268 | return tokens
269 | };
270 | Writer.prototype.render = function render(template, view, partials) {
271 | var tokens = this.parse(template);
272 | var context = view instanceof Context ? view : new Context(view);
273 | return this.renderTokens(tokens, context, partials, template)
274 | };
275 | Writer.prototype.renderTokens = function renderTokens(tokens, context, partials, originalTemplate) {
276 | var buffer = "";
277 | var token, symbol, value;
278 | for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
279 | value = undefined;
280 | token = tokens[i];
281 | symbol = token[0];
282 | if (symbol === "#") value = this.renderSection(token, context, partials, originalTemplate);
283 | else if (symbol === "^") value = this.renderInverted(token, context, partials, originalTemplate);
284 | else if (symbol === ">") value = this.renderPartial(token, context, partials, originalTemplate);
285 | else if (symbol === "&") value = this.unescapedValue(token, context);
286 | else if (symbol === "name") value = this.escapedValue(token, context);
287 | else if (symbol === "text") value = this.rawValue(token);
288 | if (value !== undefined) buffer += value
289 | }
290 | return buffer
291 | };
292 | Writer.prototype.renderSection = function renderSection(token, context, partials, originalTemplate) {
293 | var self = this;
294 | var buffer = "";
295 | var value = context.lookup(token[1]);
296 |
297 | function subRender(template) {
298 | return self.render(template, context, partials)
299 | }
300 | if (!value) return;
301 | if (isArray(value)) {
302 | for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
303 | buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate)
304 | }
305 | } else if (typeof value === "object" || typeof value === "string" || typeof value === "number") {
306 | buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate)
307 | } else if (isFunction(value)) {
308 | if (typeof originalTemplate !== "string") throw new Error("Cannot use higher-order sections without the original template");
309 | value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
310 | if (value != null) buffer += value
311 | } else {
312 | buffer += this.renderTokens(token[4], context, partials, originalTemplate)
313 | }
314 | return buffer
315 | };
316 | Writer.prototype.renderInverted = function renderInverted(token, context, partials, originalTemplate) {
317 | var value = context.lookup(token[1]);
318 | if (!value || isArray(value) && value.length === 0) return this.renderTokens(token[4], context, partials, originalTemplate)
319 | };
320 | Writer.prototype.renderPartial = function renderPartial(token, context, partials) {
321 | if (!partials) return;
322 | var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
323 | if (value != null) return this.renderTokens(this.parse(value), context, partials, value)
324 | };
325 | Writer.prototype.unescapedValue = function unescapedValue(token, context) {
326 | var value = context.lookup(token[1]);
327 | if (value != null) return value
328 | };
329 | Writer.prototype.escapedValue = function escapedValue(token, context) {
330 | var value = context.lookup(token[1]);
331 | if (value != null) return mustache.escape(value)
332 | };
333 | Writer.prototype.rawValue = function rawValue(token) {
334 | return token[1]
335 | };
336 | mustache.name = "mustache.js";
337 | mustache.version = "2.1.3";
338 | mustache.tags = ["{{", "}}"];
339 | var defaultWriter = new Writer;
340 | mustache.clearCache = function clearCache() {
341 | return defaultWriter.clearCache()
342 | };
343 | mustache.parse = function parse(template, tags) {
344 | return defaultWriter.parse(template, tags)
345 | };
346 | mustache.render = function render(template, view, partials) {
347 | if (typeof template !== "string") {
348 | throw new TypeError('Invalid template! Template should be a "string" ' + 'but "' + typeStr(template) + '" was given as the first ' + "argument for mustache#render(template, view, partials)")
349 | }
350 | return defaultWriter.render(template, view, partials)
351 | };
352 | mustache.to_html = function to_html(template, view, partials, send) {
353 | var result = mustache.render(template, view, partials);
354 | if (isFunction(send)) {
355 | send(result)
356 | } else {
357 | return result
358 | }
359 | };
360 | mustache.escape = escapeHtml;
361 | mustache.Scanner = Scanner;
362 | mustache.Context = Context;
363 | mustache.Writer = Writer
364 | });
--------------------------------------------------------------------------------
/examples/json/testList.json:
--------------------------------------------------------------------------------
1 | {
2 | "custom": {
3 | "infoList": [
4 | {
5 | "guid": "id0",
6 | "title": "tab1标题0",
7 | "date": "17-04-06 03:20:44",
8 | "author": "type1"
9 | }, {
10 | "guid": "id1",
11 | "title": "tab1标题1",
12 | "date": "17-04-06 03:20:44",
13 | "author": "type1"
14 | }, {
15 | "guid": "id2",
16 | "title": "tab1标题2",
17 | "date": "17-04-06 03:20:44",
18 | "author": "type1"
19 | }, {
20 | "guid": "id3",
21 | "title": "tab1标题3",
22 | "date": "17-04-06 03:20:44",
23 | "author": "type1"
24 | }, {
25 | "guid": "id4",
26 | "title": "tab1标题4",
27 | "date": "17-04-06 03:20:44",
28 | "author": "type4"
29 | }, {
30 | "guid": "id5",
31 | "title": "tab1标题5",
32 | "date": "17-04-06 03:20:44",
33 | "author": "type5"
34 | }
35 | ]
36 | },
37 | "status": {
38 | "code": 200,
39 | "text": "成功",
40 | "url": ""
41 | }
42 | }
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var concat = require('gulp-concat');
3 | var uglify = require('gulp-uglify');
4 | var rename = require('gulp-rename');
5 | var cleanCSS = require('gulp-clean-css');
6 | // 串行执行任务
7 | var gulpSequence = require('gulp-sequence');
8 | // 头部注释
9 | var header = require('gulp-header');
10 | var pkg = require('./package.json');
11 | var banner = ['/**',
12 | ' * <%= pkg.name %> - <%= pkg.description %>',
13 | ' * @version v<%= pkg.version %>',
14 | ' * @author <%= pkg.homepage %>',
15 | ' */',
16 | ''].join('\n');
17 |
18 |
19 | var debugPath = './dist/_debug/';
20 | var releasePath = './dist/';
21 |
22 |
23 | // 下拉刷新核心文件合并
24 | gulp.task('core_concat', function() {
25 | return gulp.src(['./src/core/pulltorefresh.iscroll.probe.js', './src/core/pulltorefresh.js', './src/core/pulltorefresh.core.js'])
26 | .pipe(concat('pulltorefresh.core.js'))
27 | .pipe(gulp.dest(debugPath));
28 | });
29 |
30 |
31 | // 打包skin-defult
32 | gulp.task('pack_skin_default', ['core_concat'], function() {
33 | return gulp.src([debugPath + 'pulltorefresh.core.js', './src/pulltorefresh.skin.default.js'])
34 | .pipe(concat('pulltorefresh.skin.default.js'))
35 | .pipe(gulp.dest(debugPath));
36 | });
37 |
38 | // 打包skin-type1
39 | gulp.task('pack_skin_type1', ['core_concat'], function() {
40 | return gulp.src([debugPath + 'pulltorefresh.core.js', './src/pulltorefresh.skin.type1.js'])
41 | .pipe(concat('pulltorefresh.skin.type1.js'))
42 | .pipe(gulp.dest(debugPath));
43 | });
44 |
45 | // 打包skin-type2
46 | gulp.task('pack_skin_type2', ['core_concat'], function() {
47 | return gulp.src([debugPath + 'pulltorefresh.core.js', './src/pulltorefresh.skin.type2.js'])
48 | .pipe(concat('pulltorefresh.skin.type2.js'))
49 | .pipe(gulp.dest(debugPath));
50 | });
51 |
52 | // 打包skin-type3
53 | gulp.task('pack_skin_type3', ['core_concat'], function() {
54 | return gulp.src([debugPath + 'pulltorefresh.core.js', './src/pulltorefresh.skin.type3.js'])
55 | .pipe(concat('pulltorefresh.skin.type3.js'))
56 | .pipe(gulp.dest(debugPath));
57 | });
58 |
59 | // 打包skin-type4
60 | gulp.task('pack_skin_type4', ['core_concat'], function() {
61 | return gulp.src([debugPath + 'pulltorefresh.core.js', './src/pulltorefresh.skin.type4.js'])
62 | .pipe(concat('pulltorefresh.skin.type4.js'))
63 | .pipe(gulp.dest(debugPath));
64 | });
65 |
66 | // 打包skin-type5
67 | gulp.task('pack_skin_type5', ['core_concat'], function() {
68 | return gulp.src([debugPath + 'pulltorefresh.core.js', './src/pulltorefresh.skin.type5.js'])
69 | .pipe(concat('pulltorefresh.skin.type5.js'))
70 | .pipe(gulp.dest(debugPath));
71 | });
72 |
73 | // 打包skin-native
74 | gulp.task('pack_skin_native', function() {
75 | return gulp.src(['./src/pulltorefresh.skin.native.js'])
76 | .pipe(concat('pulltorefresh.skin.native.js'))
77 | .pipe(gulp.dest(debugPath));
78 | });
79 |
80 | // 打包bizlogic-impl
81 | gulp.task('pack_bizlogic_impl', function() {
82 | return gulp.src(['./src/core/handedata.js', './src/pulltorefresh.bizlogic.impl.js'])
83 | .pipe(concat('pulltorefresh.bizlogic.impl.js'))
84 | .pipe(gulp.dest(debugPath));
85 | });
86 |
87 | // 打包bizlogic-impl
88 | gulp.task('pack_bizlogic_impl2', function() {
89 | return gulp.src(['./src/core/handedata.js', './src/pulltorefresh.bizlogic.impl2.js'])
90 | .pipe(concat('pulltorefresh.bizlogic.impl2.js'))
91 | .pipe(gulp.dest(debugPath));
92 | });
93 |
94 |
95 | // 打包 css以及静态资源
96 | gulp.task('pack_resources', function() {
97 | return gulp.src(['./src/css/**/*'])
98 | .pipe(gulp.dest(debugPath + 'css/'));
99 | });
100 |
101 |
102 | // 压缩发布的源文件
103 | gulp.task('js_uglify', function() {
104 | return gulp.src([debugPath + '**/*.js', '!'+ debugPath + '**/*.min.js'])
105 | .pipe(uglify())
106 | // 压缩时进行异常捕获
107 | .on('error', function(err) {
108 | console.log('line number: %d, message: %s', err.lineNumber, err.message);
109 | this.end();
110 | })
111 | // .pipe(rename({
112 | // suffix: '.min'
113 | // }))
114 | .pipe(header(banner, { pkg : pkg } ))
115 | .pipe(gulp.dest(releasePath));
116 | });
117 |
118 | // 压缩发布 css
119 | gulp.task('clean_css', function() {
120 | return gulp.src([debugPath + '**/*.css', '!'+ debugPath + '**/*.min.css'])
121 | .pipe(cleanCSS())
122 | // .pipe(rename({
123 | // suffix: '.min'
124 | // }))
125 | .pipe(header(banner, { pkg : pkg } ))
126 | .pipe(gulp.dest(releasePath));
127 | });
128 |
129 | // 压缩发布 图片资源,暂时不压缩
130 | gulp.task('resource_uglify', function() {
131 | return gulp.src([debugPath + '**/*', '!'+ debugPath + '**/*.css', '!'+ debugPath + '**/*.js'])
132 | .pipe(gulp.dest(releasePath));
133 | });
134 |
135 | gulp.task('pack_debug', ['pack_skin_default', 'pack_skin_type1', 'pack_skin_type2', 'pack_skin_type3', 'pack_skin_type4', 'pack_skin_type5', 'pack_skin_native', 'pack_bizlogic_impl', 'pack_bizlogic_impl2', 'pack_resources']);
136 |
137 |
138 | gulp.task('pack_release', ['js_uglify', 'clean_css', 'resource_uglify']);
139 |
140 |
141 | gulp.task('default', gulpSequence('pack_debug', 'pack_release'));
142 |
143 | // 看守
144 | gulp.task('watch', function() {
145 |
146 | // 看守所有位在 dist/ 目录下的档案,一旦有更动,便进行重整
147 | // gulp.watch([config.src+'/gulpWatch.json']).on('change', function(file) {
148 | // console.log("改动");
149 | // });
150 | gulp.watch('./src/**/*', ['default']);
151 |
152 | });
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "pulltorefresh-h5-iscroll",
3 | "version": "3.0.0",
4 | "description": "一款基于IScroll5的H5下拉刷新实现,包括多种皮肤的实现",
5 | "author": "dailc",
6 | "license": "MIT",
7 | "devDependencies": {
8 | "gulp": "^3.9.1",
9 | "gulp-clean-css": "^2.0.10",
10 | "gulp-concat": "^2.6.0",
11 | "gulp-rename": "^1.2.2",
12 | "gulp-uglify": "^1.5.1"
13 | },
14 | "dependencies": {
15 | "gulp-header": "^1.8.8",
16 | "gulp-sequence": "^0.4.6"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------
1 | ## 基于IScroll的下拉刷新皮肤系列
2 | **最后更新:20170609**
3 |
4 |
5 | ### API说明
6 | **所有的下拉刷新皮肤对外提供的API均保持一致**
7 |
8 | #### `pulltorefresh.skin.×××`的API
9 | 这些API事每一个下拉刷新对象都有的
10 |
11 | ```
12 | * finished //这是一个属性,用来控制当前上拉加载是否可用
13 | * refresh() //重置状态。譬如上拉加载关闭后需要手动refresh重置finished状态
14 | * pulldownLoading() //主动触发一个下拉刷新的动画(同时会触发下拉回调)
15 | * pullupLoading() //主动触发一个上拉加载的动画(同时会触发上拉回调)
16 | * endPullDownToRefresh() //关闭下拉刷新动画,重置状态
17 | * endPullUpToRefresh(finished) //关闭上拉加载动画,重置状态,如果finished,则不允许在上拉,除非再次refresh()
18 | ```
19 |
20 |
21 | #### `pulltorefresh.core.js`的API
22 | 这个文件的API主要是用来给具体的皮肤类进行继承与实现。
23 |
24 | ```
25 | * _initPullToRefreshTipsHook() //在这里初始化生成下拉刷新与上拉加载的提示
26 | * _pullingHook(deltaY,thresholdHeight) //下拉过程中的钩子函数,方便实现一些渐变动画
27 | * _pulldownLoaingAnimationHook //下拉刷新的动画
28 | * _pulldownLoaingAnimationSuccessHook(done,isSuccess) //下拉刷新的成功动画-动画完毕后可能的成功提示,没有的话请直接执行done
29 | * _pulldownLoaingAnimationEndHook //下拉刷新的动画完成后的回调,可以用来重置状态
30 | * _pullupLoaingAnimationHook(isFinished) //上拉加载的动画
31 | * _pullupLoaingAnimationSuccessHook(isFinished) //上拉加载的成功动画-动画完毕后可能的成功提示,或者重置状态
32 | * _scrollEndHook //滑动完毕后的end回调(这个比较少用到)
33 | * _enablePullUpHook //允许pullup后的回调
34 | * _disablePullUpHook //禁止pullup后的回调
35 | ```
36 |
37 | ### 源码说明
38 |
39 |
40 | #### `pulltorefresh.skin.css`
41 | 是所有自定义下拉刷新皮肤使用的css样式,这里所有的样式一起打包成了一个文件
42 |
43 | #### `pulltorefresh.core.js`
44 | 下拉刷新的核心实现,依赖于`IScroll5`,里面将下拉刷新的核心逻辑都抽取出来了,并规定了一些特定的UI实现API,方便自定义继承实现。
45 |
46 | 这样,可以方便单独去继承这个类实现各色各样不同的皮肤。
47 |
48 | #### `pulltorefresh.skin.×××.js`
49 | 对应的皮肤实现,所有皮肤实现均继承了上述的下拉刷新核心类,因此皮肤类中只关注UI层面的实现。
50 |
51 | * `default`和`type1`皮肤依赖于`mui.css`
52 | * 其它皮肤依赖于`pulltorefresh.skin.css`
53 |
54 | #### `pulltorefresh.skin.native.js`
55 | 这个是一个特殊的皮肤,它重新定义了一个简单的下拉刷新。
56 |
57 | 应用场景是:在混合开发的原生容器内部使用,例如钉钉等环境。在这种环境下,原生已经提供了下拉API了,所以这里面都是基于它的API来实现,同时增加了一个上拉加载。
58 |
59 | 注意,这种皮肤只适用于原生环境,因此在h5环境下会兼容下其它皮肤,参考示例。
60 |
61 | #### `pulltorefresh.bizlogic.impl.js`
62 | 下拉刷新业务层面的封装,上述的皮肤类实现了下拉刷新功能,但是没有对业务场景进行封装的。
63 |
64 | 因此在实际业务是,会有大量重复的代码(如相同的ajax,相同的接口数据处理等等)
65 |
66 | 因此这里有封装了一层,将通用业务写进去了,进一步减少代码。
67 |
68 | 当然了,实际情况下可以去根据不同业务修改这个源文件,重新打包。
69 |
70 | 调用示例:
71 | ```
72 | new PullToRefreshTools.bizlogic({
73 | skin: PullToRefreshTools.skin.defaults,
74 | url: 'http://115.29.151.25:8012/request.php',
75 | template: '#list_item',
76 | dataRequest: function(currPage, callback) {
77 | var result = {
78 | action: 'testPullrefreshListDemoV3',
79 | paras: {
80 | currentpageindex: currPage.toString(),
81 | pagesize: 10,
82 | tabType: 'tab1',
83 | // 搜索值,接口里没有实现,这里可以打印代表搜索值已经获取到
84 | searchValue: ''
85 | }
86 | };
87 | return result;
88 | },
89 | itemClick: function(e) {
90 | console.log("点击:" + this.id);
91 | }
92 | });
93 | ```
94 |
95 | 最终生成的对象开放的API:
96 |
97 | ```
98 | * refresh() //触发一次上拉加载(一般搜索中用到,搜索完毕后会刷新页面)
99 | * pullToRefreshInstance //属性,这个是原始的下拉刷新对象引用(可以使用上述的下拉刷新api)
100 | * 至于生成业务下拉刷新时需要传入的参数,由于与业务耦合,因此不赘述,详情可以参考源码或示例
101 | ```
102 |
103 | ### 如何自定义实现皮肤
104 | 参考源码中的skin系列,只需要继承核心类,然后实现对应的UI函数即可。
--------------------------------------------------------------------------------
/src/core/handedata.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 创建时间: 2017-03-28
4 | * 版本: [1.0, 2017/05/26 ]
5 | * 版权: dailc
6 | * 描述: 数据处理的通用方法封装
7 | */
8 | (function(exports, CommonTools) {
9 | /**
10 | * 通用接口处理
11 | * 通过插拔式增加各种接口的支持
12 | */
13 | (function() {
14 | // 处理数据的函数池
15 | exports.dataProcessFn = [];
16 |
17 | /**
18 | * @description 统一处理返回数据,返回数据必须符合标准才行,否则会返回错误提示
19 | * @param {JSON} response 接口返回的数据
20 | * @param {Object} options 配置信息,包括
21 | * dataPath 手动指定处理数据的路径,遇到一些其它数据格式可以手动指定
22 | * 可以传入数组,传入数组代表回一次找path,直到找到为止或者一直到最后都没找到
23 | * isDebug 是否是调试模式,调试模式会返回一个debugInfo节点包含着原数据
24 | * 其它:无法处理的数据,会返回对应错误信息
25 | * @return {JSON} 返回的数据,包括多个成功数据,错误提示等等
26 | */
27 | exports.dataProcess = function(response, options) {
28 | options = options || {};
29 |
30 | // 永远不要试图修改arguments,请单独备份,否则在严格模式和非严格模式下容易出现错误
31 | var args = [].slice.call(arguments);
32 | var result = {
33 | // code默认为0代表失败,1为成功
34 | code: 0,
35 | // 描述默认为空
36 | message: '',
37 | // 数据默认为空
38 | data: null,
39 | // v7接口中的status字段,放在第一层方便判断
40 | status: 0,
41 | // 一些数据详情,可以协助调试用
42 | debugInfo: {
43 | type: '未知数据格式'
44 | }
45 | };
46 |
47 | if (options.dataPath == null) {
48 | // 不需要处理
49 |
50 | return response;
51 | }
52 |
53 | if (typeof options.dataPath === 'string') {
54 | options.dataPath = [options.dataPath];
55 | }
56 |
57 | // 默认为详情
58 | var isDebug = options.isDebug || false,
59 | paths = options.dataPath,
60 | processFns = exports.dataProcessFn,
61 | len = processFns.length,
62 | num = paths.length,
63 | isFound = false;
64 |
65 | if (!response) {
66 | result.message = '接口返回数据为空!';
67 | return result;
68 | }
69 | // 添加一个result,将返回接口给子函数
70 | args.push(result);
71 | for (var k = 0; !isFound && k < num; k++) {
72 | // 每次动态修改path参数
73 | args[1] = paths[k];
74 |
75 | for (var i = 0; !isFound && i < len; i++) {
76 | var fn = processFns[i];
77 | var returnValue = fn.apply(this, args);
78 |
79 | if (returnValue != null) {
80 | // 找到了或者到了最后一个就退出
81 | if (returnValue.code == 1 || k == num - 1) {
82 | isFound = true;
83 | result = returnValue;
84 | break;
85 | }
86 | }
87 | }
88 | }
89 |
90 | if (!isFound) {
91 | // 没有找到数据需要使用默认
92 | // 如果没有数据处理函数或数据格式不符合任何一个函数的要求
93 | result.message = '没有数据处理函数或者接口数据返回格式不符合要求!';
94 | // 装载数据可以调试
95 | result.debugInfo.data = response;
96 | }
97 |
98 | // 非null代表已经找到格式了,这个是通过约定越好的
99 | if (!isDebug) {
100 | result.debugInfo = undefined;
101 | }
102 | return result;
103 | };
104 | })();
105 | (function() {
106 |
107 | /**
108 | * @description 通过指定路径,来获取对应的数据
109 | * 如果不符合数据要求的,请返回null,这样就会进入下一个函数处理了
110 | * @param {JSON} response 接口返回的数据
111 | * @param {String} path 一个自定义路径,以点分割,用来找数据
112 | * @param {JSON} returnValue 返回数据
113 | * 1:返回列表
114 | * 其它:返回详情
115 | * @return {JSON} 返回的数据,包括多个成功数据,错误提示等等
116 | * */
117 | function handleDataByPathV6(response, path, returnValue) {
118 | if (!(path && response && response.ReturnInfo && response.BusinessInfo)) {
119 | return null;
120 | }
121 | var debugInfo = {
122 | type: 'v6数据格式:' + path
123 | };
124 | var returnInfo = response.ReturnInfo,
125 | businessInfo = response.BusinessInfo,
126 | userArea = response.UserArea;
127 |
128 | if (returnInfo.Code == '1') {
129 | if (businessInfo.Code == '1') {
130 | returnValue.code = 1;
131 |
132 | var data = CommonTools.getNameSpaceObj(response, path);
133 |
134 | if (data) {
135 | returnValue.data = data;
136 | } else {
137 | returnValue.message = returnValue.message || '指定路径下没有找到数据';
138 | returnValue.data = null;
139 | // 3代表业务数据错误
140 | debugInfo.errorType = '3';
141 | }
142 | } else {
143 | // 2代表业务错误
144 | debugInfo.errorType = '2';
145 | returnValue.code = 0;
146 | returnValue.message = businessInfo.Description || '接口请求错误,后台业务逻辑处理出错!';
147 | }
148 | } else {
149 | // v6中的程序错误
150 | // 1代表程序错误
151 | debugInfo.errorType = '1';
152 | returnValue.code = 0;
153 | returnValue.message = returnInfo.Description || '接口请求错误,后台程序处理出错!';
154 | }
155 |
156 | returnValue.debugInfo = debugInfo;
157 | return returnValue;
158 | }
159 |
160 | exports.dataProcessFn.push(handleDataByPathV6);
161 | })();
162 | (function() {
163 |
164 | /**
165 | * @description 通过指定路径,来获取对应的数据
166 | * 如果不符合数据要求的,请返回null,这样就会进入下一个函数处理了
167 | * @param {JSON} response 接口返回的数据
168 | * @param {String} path 一个自定义路径,以点分割,用来找数据
169 | * @param {JSON} returnValue 返回数据
170 | * 1:返回列表
171 | * 其它:返回详情
172 | * @return {JSON} 返回的数据,包括多个成功数据,错误提示等等
173 | * */
174 | function handleDataByPathV7(response, path, returnValue) {
175 | if (!(path && response && response.status && response.custom)) {
176 | return null;
177 | }
178 | var debugInfo = {
179 | type: 'v7数据格式:' + path
180 | };
181 | var status = response.status;
182 |
183 | // 对应状态码
184 | returnValue.status = status.code || 0;
185 | returnValue.message = status.text;
186 |
187 | if (status.code == '200') {
188 | returnValue.code = 1;
189 |
190 | var data = CommonTools.getNameSpaceObj(response, path);
191 |
192 | if (data) {
193 |
194 | returnValue.data = data;
195 | } else {
196 | returnValue.message = returnValue.message || '指定路径下没有找到数据';
197 | returnValue.data = null;
198 | // 3代表业务数据错误
199 | debugInfo.errorType = '3';
200 | }
201 | } else {
202 | // 请求失败的情况暂时使用接口返回的默认提示
203 | returnValue.code = 0;
204 | // 2代表status错误,message默认就已经在节点中
205 | debugInfo.errorType = '2';
206 | returnValue.message = returnValue.message || 'status状态错误';
207 | }
208 |
209 | returnValue.debugInfo = debugInfo;
210 | return returnValue;
211 | }
212 |
213 | exports.dataProcessFn.push(handleDataByPathV7);
214 | })();
215 |
216 | CommonTools.namespace('dataProcess', exports.dataProcess);
217 | })({}, PullToRefreshTools);
--------------------------------------------------------------------------------
/src/core/pulltorefresh.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 创建时间: 2017-03-28
4 | * 版本: [1.0, 2017/05/26 ]
5 | * 版权: dailc
6 | * 描述: 这个工具类都是一些最基本的工具函数
7 | */
8 | "use strict";
9 |
10 | var PullToRefreshTools = window.PullToRefreshTools || (function(exports, undefined) {
11 | /**
12 | * 通用代码
13 | */
14 | (function() {
15 | /**
16 | * @description 产生一个 唯一uuid-guid
17 | * @param {Number} len
18 | * @param {Number} radix 基数
19 | * @return {String} 返回一个随机性的唯一uuid
20 | */
21 | exports.uuid = function(len, radix) {
22 | var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''),
23 | uuid = [],
24 | i;
25 | radix = radix || chars.length;
26 |
27 | if (len) {
28 | for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
29 | } else {
30 | var r;
31 |
32 | uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
33 | uuid[14] = '4';
34 |
35 | for (i = 0; i < 36; i++) {
36 | if (!uuid[i]) {
37 | r = 0 | Math.random() * 16;
38 | uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
39 | }
40 | }
41 | }
42 | return uuid.join('');
43 | };
44 | /**
45 | * 空函数
46 | */
47 | exports.noop = function() {};
48 | /**
49 | * extend(simple)
50 | * @param {type} target
51 | * @param {type} source
52 | * @param {type} deep
53 | * @returns {unresolved}
54 | */
55 | exports.extend = function() { //from jquery2
56 | // from jquery2
57 | var options, name, src, copy, copyIsArray, clone,
58 | target = arguments[0] || {},
59 | i = 1,
60 | length = arguments.length,
61 | deep = false;
62 |
63 | if (typeof target === "boolean") {
64 | deep = target;
65 | target = arguments[i] || {};
66 | i++;
67 | }
68 | if (typeof target !== "object" && !exports.isFunction(target)) {
69 | target = {};
70 | }
71 | if (i === length) {
72 | target = this;
73 | i--;
74 | }
75 | for (; i < length; i++) {
76 | if ((options = arguments[i]) != null) {
77 | for (name in options) {
78 | src = target[name];
79 | copy = options[name];
80 | if (target === copy) {
81 | continue;
82 | }
83 | if (deep && copy && (exports.isPlainObject(copy) || (copyIsArray = exports.isArray(copy)))) {
84 | if (copyIsArray) {
85 | copyIsArray = false;
86 | clone = src && exports.isArray(src) ? src : [];
87 |
88 | } else {
89 | clone = src && exports.isPlainObject(src) ? src : {};
90 | }
91 |
92 | target[name] = exports.extend(deep, clone, copy);
93 | } else if (copy !== undefined) {
94 | target[name] = copy;
95 | }
96 | }
97 | }
98 | }
99 | return target;
100 | };
101 | /**
102 | * isFunction
103 | */
104 | exports.isFunction = function(value) {
105 | return exports.type(value) === "function";
106 | };
107 | /**
108 | * isPlainObject
109 | */
110 | exports.isPlainObject = function(obj) {
111 | return exports.isObject(obj) && !exports.isWindow(obj) && Object.getPrototypeOf(obj) === Object.prototype;
112 | };
113 | exports.isArray = Array.isArray ||
114 | function(object) {
115 | return object instanceof Array;
116 | };
117 | /**
118 | * isWindow(需考虑obj为undefined的情况)
119 | */
120 | exports.isWindow = function(obj) {
121 | return obj != null && obj === obj.window;
122 | };
123 | /**
124 | * isObject
125 | */
126 | exports.isObject = function(obj) {
127 | return exports.type(obj) === "object";
128 | };
129 | exports.type = function(obj) {
130 | return obj == null ? String(obj) : class2type[{}.toString.call(obj)] || "object";
131 | };
132 | /**
133 | * @description each遍历操作
134 | * @param {type} elements
135 | * @param {type} callback
136 | * @returns {global}
137 | */
138 | exports.each = function(elements, callback, hasOwnProperty) {
139 | if (!elements) {
140 | return this;
141 | }
142 | if (typeof elements.length === 'number') {
143 | [].every.call(elements, function(el, idx) {
144 | return callback.call(el, idx, el) !== false;
145 | });
146 | } else {
147 | for (var key in elements) {
148 | if (hasOwnProperty) {
149 | if (elements.hasOwnProperty(key)) {
150 | if (callback.call(elements[key], key, elements[key]) === false) return elements;
151 | }
152 | } else {
153 | if (callback.call(elements[key], key, elements[key]) === false) return elements;
154 | }
155 | }
156 | }
157 | return this;
158 | };
159 | /**
160 | * @description 选择这段代码用到的太多了,因此抽取封装出来
161 | * @param {Object} element dom元素或者selector
162 | */
163 | exports.selector = function(element) {
164 | if (typeof element === 'string') {
165 | element = document.querySelector(element);
166 | }
167 |
168 | return element;
169 | };
170 | var class2type = {};
171 | exports.each(['Boolean', 'Number', 'String', 'Function', 'Array', 'Date', 'RegExp', 'Object', 'Error'], function(i, name) {
172 | class2type["[object " + name + "]"] = name.toLowerCase();
173 | });
174 | (function() {
175 | function detect(ua) {
176 | this.os = {};
177 | this.os.name = 'browser';
178 | var funcs = [
179 | function() { //android
180 | var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
181 | if (android) {
182 | this.os.android = true;
183 | this.os.version = android[2];
184 | this.os.isBadAndroid = !(/Chrome\/\d/.test(window.navigator.appVersion));
185 | this.os.name += '_' + 'Android';
186 | this.os.name += '_' + 'mobile';
187 | }
188 | return this.os.android === true;
189 | },
190 | function() { //ios
191 | var iphone = ua.match(/(iPhone\sOS)\s([\d_]+)/);
192 | if (iphone) { //iphone
193 | this.os.ios = this.os.iphone = true;
194 | this.os.version = iphone[2].replace(/_/g, '.');
195 | this.os.name += '_' + 'iphone';
196 | this.os.name += '_' + 'mobile';
197 | } else {
198 | var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
199 | if (ipad) { //ipad
200 | this.os.ios = this.os.ipad = true;
201 | this.os.version = ipad[2].replace(/_/g, '.');
202 | this.os.name += '_' + 'iOS';
203 | this.os.name += '_' + 'mobile';
204 | }
205 |
206 | }
207 | return this.os.ios === true;
208 | }
209 | ];
210 | [].every.call(funcs, function(func) {
211 | return !func.call(exports);
212 | });
213 | }
214 | detect.call(exports, navigator.userAgent);
215 | })();
216 | /**
217 | * @description 判断os系统 ,判断是否是ejs
218 | * ejs.os
219 | * @param {type}
220 | * @returns {undefined}
221 | */
222 | (function() {
223 | function detect(ua) {
224 | this.os = this.os || {};
225 | //比如 EpointEJS/6.1.1 也可以/(EpointEJS)\/([\d\.]+)/i
226 | var ejs = ua.match(/EpointEJS/i);
227 | if (ejs) {
228 | this.os.ejs = true;
229 | this.os.name += '_' + 'ejs';
230 | }
231 | //阿里的钉钉 DingTalk/3.0.0
232 | var dd = ua.match(/DingTalk/i);
233 | if (dd) {
234 | this.os.dd = true;
235 | this.os.name += '_' + 'dd';
236 | }
237 | }
238 | detect.call(exports, navigator.userAgent);
239 | })();
240 |
241 | })();
242 | /**
243 | * @description 模拟Class的基类,以便模拟Class进行继承等
244 | * 仿照mui写的
245 | */
246 | (function() {
247 | //同时声明多个变量,用,分开要好那么一点点
248 | var initializing = false,
249 | //通过正则检查是否是函数
250 | fnTest = /xyz/.test(function() {
251 | xyz;
252 | }) ? /\b_super\b/ : /.*/;
253 | var Clazz = function() {};
254 | //很灵活的一种写法,直接重写Class的extend,模拟继承
255 | Clazz.extend = function(prop) {
256 | var _super = this.prototype;
257 | initializing = true;
258 | //可以这样理解:这个prototype将this中的方法和属性全部都复制了一遍
259 | var prototype = new this();
260 | initializing = false;
261 | for (var name in prop) {
262 | //这一些列操作逻辑并不简单,得清楚运算符优先级
263 | //逻辑与的优先级是高于三元条件运算符的,得注意下
264 | //只有继承的函数存在_super时才会触发(哪怕注释也一样进入)
265 | //所以梳理后其实一系列的操作就是判断是否父对象也有相同对象
266 | //如果有,则对应函数存在_super这个东西
267 | prototype[name] = typeof prop[name] == "function" &&
268 | typeof _super[name] == "function" && fnTest.test(prop[name]) ?
269 | (function(name, fn) {
270 | return function() {
271 | var tmp = this._super;
272 | this._super = _super[name];
273 | var ret = fn.apply(this, arguments);
274 | this._super = tmp;
275 | return ret;
276 | };
277 | })(name, prop[name]) :
278 | prop[name];
279 | }
280 | /**
281 | * @description Clss的构造,默认会执行init方法
282 | */
283 | function Clazz() {
284 | if (!initializing && this.init) {
285 | this.init.apply(this, arguments);
286 | }
287 | }
288 | Clazz.prototype = prototype;
289 | Clazz.prototype.constructor = Clazz;
290 | //callee 的作用是返回当前执行函数的自身
291 | //这里其实就是this.extend,不过严格模式下禁止使用
292 | //Clazz.extend = arguments.callee;
293 | //替代callee 返回本身
294 | Clazz.extend = this.extend;
295 | return Clazz;
296 | };
297 | exports.Clazz = Clazz;
298 | })();
299 |
300 | /**
301 | * 方便的生成对象下的命名空间
302 | */
303 | (function() {
304 | /**
305 | * @description 设置一个Util对象下的命名空间
306 | * @param {String} namespace
307 | * @param {Object} obj 需要赋值的目标对象
308 | */
309 | exports.namespace = function(namespace, obj) {
310 | var parent = window.PullToRefreshTools;
311 |
312 | if (!namespace) {
313 | return parent;
314 | }
315 |
316 | var namespaceArr = namespace.split('.'),
317 | len = namespaceArr.length;
318 |
319 | for (var i = 0; i < len - 1; i++) {
320 | var tmp = namespaceArr[i];
321 | // 不存在的话要重新创建对象
322 | parent[tmp] = parent[tmp] || {};
323 | // parent要向下一级
324 | parent = parent[tmp];
325 |
326 | }
327 | parent[namespaceArr[len - 1]] = obj;
328 |
329 | return parent[namespaceArr[len - 1]];
330 | };
331 | /**
332 | * @description 获取这个模块下对应命名空间的对象
333 | * 如果不存在,则返回null,这个api只要是供内部获取接口数据时调用
334 | * @param {Object} module
335 | * @param {Array} namespace
336 | */
337 | exports.getNameSpaceObj = function(module, namespace) {
338 | if (!namespace) {
339 | return null;
340 | }
341 | var namespaceArr = namespace.split('.'),
342 | len = namespaceArr.length;
343 | for (var i = 0; i < len; i++) {
344 | module && (module = module[namespaceArr[i]]);
345 | }
346 | return module;
347 | };
348 | })();
349 |
350 | /**
351 | * 兼容require
352 | */
353 | if (typeof module != 'undefined' && module.exports) {
354 | module.exports = exports;
355 | } else if (typeof define == 'function' && (define.amd || define.cmd)) {
356 | define(function() {
357 | return exports;
358 | });
359 | }
360 |
361 | return exports;
362 | })({});
--------------------------------------------------------------------------------
/src/css/images/img_pulltorefresh_skin2_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/src/css/images/img_pulltorefresh_skin2_1.png
--------------------------------------------------------------------------------
/src/css/images/img_pulltorefresh_skin2_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/src/css/images/img_pulltorefresh_skin2_2.png
--------------------------------------------------------------------------------
/src/css/images/img_pulltorefresh_skin2_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/src/css/images/img_pulltorefresh_skin2_3.png
--------------------------------------------------------------------------------
/src/pulltorefresh.skin.default.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 创建时间: 2017/03/28
4 | * 版本: [1.0, 2017/05/26 ]
5 | * 版权: dailc
6 | * 描述: 皮肤类只会实现UI相关的hook函数
7 | * 默认皮肤default,最简单的下拉刷新
8 | * 依赖mui的css
9 | */
10 | (function(exports, CommonTools) {
11 |
12 | // 默认的全局参数-主要用来配置下拉刷新提示的一些css class
13 | var NAMESPACE = 'mui-';
14 | var CLASS_PULL_TOP_POCKET = NAMESPACE + 'pull-top-pocket';
15 | var CLASS_PULL_BOTTOM_POCKET = NAMESPACE + 'pull-bottom-pocket';
16 | var CLASS_PULL = NAMESPACE + 'pull';
17 | var CLASS_PULL_LOADING = NAMESPACE + 'pull-loading';
18 | var CLASS_PULL_CAPTION = NAMESPACE + 'pull-caption';
19 | var CLASS_PULL_CAPTION_DOWN = NAMESPACE + 'pull-caption-down';
20 | var CLASS_PULL_CAPTION_REFRESH = NAMESPACE + 'pull-caption-refresh';
21 | var CLASS_PULL_CAPTION_NOMORE = NAMESPACE + 'pull-caption-nomore';
22 |
23 | var CLASS_ICON = NAMESPACE + 'icon';
24 | var CLASS_SPINNER = NAMESPACE + 'spinner';
25 | var CLASS_ICON_PULLDOWN = NAMESPACE + 'icon-pulldown';
26 | var CLASS_ICON_SUCCESS = NAMESPACE + 'icon-checkmarkempty';
27 | var CLASS_ICON_ERROR = NAMESPACE + 'icon-info';
28 |
29 | var CLASS_BLOCK = NAMESPACE + 'block';
30 | var CLASS_HIDDEN = NAMESPACE + 'hidden';
31 | var CLASS_VISIBILITY = NAMESPACE + 'visibility';
32 |
33 | var CLASS_LOADING_UP = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_PULLDOWN;
34 | var CLASS_LOADING_DOWN = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_PULLDOWN;
35 | var CLASS_LOADING = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_SPINNER;
36 |
37 | var CLASS_LOADING_SUCCESS = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_SUCCESS;
38 |
39 | var CLASS_LOADING_ERROR = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_ERROR;
40 | var pocketHtml = ['', '
', '
{contentrefresh}
', '
'].join('');
41 |
42 |
43 | /**
44 | * 创建一个Class对象
45 | * 只需要关注默认的UI实现即可
46 | * UI只需要实现需要实现的函数
47 | */
48 | var PullToRefresh = CommonTools.core.extend({
49 |
50 | /**
51 | * @description 生成下拉刷新提示,这个需要被具体实现
52 | * 这个默认实现就直接在一个函数里面同时生成下拉和上拉提示了
53 | */
54 | _initPullToRefreshTipsHook: function(enablePullDown, enablePullUp) {
55 | this._initPocket();
56 | if(!enablePullUp) {
57 | this.bottomPocket && this.bottomPocket.classList.add(CLASS_HIDDEN);
58 | }
59 | if(!enablePullDown) {
60 | this.topPocket && this.topPocket.classList.add(CLASS_HIDDEN);
61 | }
62 | },
63 | /**
64 | * @description 初始化下拉刷新
65 | */
66 | _initPulldownRefreshState: function() {
67 | this.pullPocket = this.topPocket;
68 | this.pullPocket.classList.add(CLASS_BLOCK);
69 | this.pullPocket.classList.add(CLASS_VISIBILITY);
70 | this.pullCaption = this.topCaption;
71 | this.pullLoading = this.topLoading;
72 | },
73 | /**
74 | * @description 初始化上拉加载
75 | */
76 | _initPullupRefreshState: function() {
77 | this.pullPocket = this.bottomPocket;
78 | this.pullPocket.classList.add(CLASS_BLOCK);
79 | this.pullPocket.classList.add(CLASS_VISIBILITY);
80 | this.pullCaption = this.bottomCaption;
81 | this.pullLoading = this.bottomLoading;
82 | },
83 | /**
84 | * @description 下拉过程中的钩子函数
85 | * @param {Number} deltaY
86 | * @param {Number} thresholdHeight 对应的高度阈值
87 | */
88 | _pullingHook: function(deltaY, thresholdHeight) {
89 | // 高度阈值
90 | if(deltaY >= thresholdHeight) {
91 | this._setCaption(true, this.options.down.contentover);
92 | } else if(deltaY < thresholdHeight) {
93 | this._setCaption(true, this.options.down.contentdown);
94 | }
95 | },
96 | /**
97 | * @description 下拉刷新的成功动画,每次确保触发一次
98 | */
99 | _pulldownLoaingAnimationHook: function() {
100 | this._setCaption(true, this.options.down.contentrefresh);
101 | },
102 | /**
103 | * @description 下拉刷新的成功动画-动画完毕后可能的成功提示,每次确保触发一次
104 | * 比如在成功里面提示加载了多少条数据,如果不需要可以传null,会直接走到end事件里
105 | * @param {Function} done 这个可以提前结束动画-如果不想要的话
106 | * @param {Boolean} isSuccess 是否请求成功
107 | */
108 | _pulldownLoaingAnimationSuccessHook: function(done, isSuccess) {
109 | if(this.options.down.isSuccessTips) {
110 | this._setCaption(true, isSuccess ? this.options.down.contentrefreshsuccess : this.options.down.contentrefresherror);
111 | } else {
112 | // 否则直接没有成功提示
113 | done();
114 | }
115 |
116 | },
117 | /**
118 | * @description 下拉刷新的动画完成后的回调,可以用来重置状态
119 | */
120 | _pulldownLoaingAnimationEndHook: function() {
121 | this._setCaption(true, this.options.down.contentdown, true);
122 | this.topPocket.classList.remove(CLASS_VISIBILITY);
123 | },
124 | /**
125 | * @description 上拉加载的成功动画,每次确保触发一次
126 | */
127 | _pullupLoaingAnimationHook: function(isFinished) {
128 | if(this.options.up) {
129 | this._setCaption(false, this.options.up.contentrefresh);
130 | }
131 |
132 | },
133 | /**
134 | * @description 上拉加载的成功动画-动画完毕后可能的成功提示,每次确保触发一次
135 | */
136 | _pullupLoaingAnimationSuccessHook: function(isFinished) {
137 | if(this.options.up) {
138 | if(isFinished) {
139 | this._setCaption(false, this.options.up.contentnomore);
140 | } else {
141 | this._setCaption(false, this.options.up.contentdown);
142 | }
143 | //this.bottomPocket.classList.remove(CLASS_VISIBILITY);
144 | }
145 |
146 | },
147 | /**
148 | * @description _disablePullUpHook
149 | */
150 | _disablePullUpHook: function() {
151 | this.bottomPocket.className = 'mui-pull-bottom-pocket' + ' ' + CLASS_HIDDEN;
152 | },
153 | /**
154 | * @description disablePullUpHook
155 | */
156 | _enablePullUpHook: function() {
157 | if(!this.options.up) {
158 | return;
159 | }
160 | this.bottomPocket.classList.remove(CLASS_HIDDEN);
161 | this._setCaption(false, this.options.up.contentdown);
162 | },
163 | /**
164 | * @description 创建上拉提示或下拉提示
165 | * @param {Object} clazz
166 | * @param {Object} options
167 | * @param {Object} iconClass
168 | */
169 | _createPocket: function(clazz, options, iconClass) {
170 | var pocket = document.createElement('div');
171 | pocket.className = clazz;
172 | pocket.innerHTML = pocketHtml.replace('{contentrefresh}', options.contentinit).replace('{icon}', iconClass);
173 | return pocket;
174 | },
175 | /**
176 | * @description 初始化下拉刷新和上拉加载提示
177 | */
178 | _initPocket: function() {
179 | var options = this.options;
180 | if(options.down && options.down.hasOwnProperty('callback')) {
181 | this.topPocket = this.wrapper.querySelector('.' + CLASS_PULL_TOP_POCKET);
182 | if(!this.topPocket) {
183 | this.topPocket = this._createPocket(CLASS_PULL_TOP_POCKET, options.down, CLASS_LOADING_DOWN);
184 | this.wrapper.insertBefore(this.topPocket, this.wrapper.firstChild);
185 | }
186 | this.topLoading = this.topPocket.querySelector('.' + CLASS_PULL_LOADING);
187 | this.topCaption = this.topPocket.querySelector('.' + CLASS_PULL_CAPTION);
188 | }
189 | if(options.up && options.up.hasOwnProperty('callback')) {
190 | this.bottomPocket = this.scrollWrap.querySelector('.' + CLASS_PULL_BOTTOM_POCKET);
191 | if(!this.bottomPocket) {
192 | this.bottomPocket = this._createPocket(CLASS_PULL_BOTTOM_POCKET, options.up, CLASS_LOADING);
193 | this.scrollWrap.appendChild(this.bottomPocket);
194 | }
195 | this.bottomLoading = this.bottomPocket.querySelector('.' + CLASS_PULL_LOADING);
196 | this.bottomCaption = this.bottomPocket.querySelector('.' + CLASS_PULL_CAPTION);
197 | }
198 |
199 | },
200 |
201 | /**
202 | * @description 设置提示的class
203 | * @param {Object} isPulldown
204 | * @param {Object} caption
205 | * @param {Object} title
206 | */
207 | _setCaptionClass: function(isPulldown, caption, title) {
208 | if(!this.options.up) {
209 | return;
210 | }
211 | if(!isPulldown) {
212 |
213 | switch(title) {
214 | case this.options.up.contentdown:
215 | caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_DOWN;
216 | break;
217 | case this.options.up.contentrefresh:
218 | caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_REFRESH
219 | break;
220 | case this.options.up.contentnomore:
221 | caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_NOMORE;
222 | break;
223 | }
224 | }
225 | },
226 | /**
227 | * @description 设置caption
228 | * @param {Object} isPulldown
229 | * @param {Object} title
230 | * @param {Object} reset
231 | */
232 | _setCaption: function(isPulldown, title, reset) {
233 | if(this.loading) {
234 | return;
235 | }
236 | if(isPulldown) {
237 | this._initPulldownRefreshState();
238 | } else {
239 | this._initPullupRefreshState();
240 | }
241 | var options = this.options;
242 | var pocket = this.pullPocket;
243 | var caption = this.pullCaption;
244 | var loading = this.pullLoading;
245 | var isPulldown = this.pulldown;
246 | var self = this;
247 | if(pocket) {
248 | if(reset) {
249 | setTimeout(function() {
250 | caption.innerHTML = self.lastTitle = title;
251 | if(isPulldown) {
252 | loading.className = CLASS_LOADING_DOWN;
253 | } else {
254 | self._setCaptionClass(false, caption, title);
255 | loading.className = CLASS_LOADING;
256 | }
257 | loading.style.webkitAnimation = "";
258 | loading.style.webkitTransition = "";
259 | loading.style.webkitTransform = "";
260 | }, 100);
261 | } else {
262 | if(title !== this.lastTitle) {
263 | caption.innerHTML = title;
264 | if(isPulldown) {
265 | if(title === options.down.contentrefresh) {
266 | loading.className = CLASS_LOADING;
267 | loading.style.webkitAnimation = "spinner-spin 1s step-end infinite";
268 | } else if(title === options.down.contentover) {
269 | loading.className = CLASS_LOADING_UP;
270 | loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
271 | loading.style.webkitTransform = "rotate(180deg)";
272 | } else if(title === options.down.contentdown) {
273 | loading.className = CLASS_LOADING_DOWN;
274 | loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
275 | loading.style.webkitTransform = "rotate(0deg)";
276 | } else if(title === options.down.contentrefreshsuccess) {
277 | //隐藏loading先
278 | loading.className = CLASS_LOADING_SUCCESS;
279 | loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
280 | loading.style.webkitTransform = "scale(1.2,1.2)";
281 | loading.style.webkitAnimation = "none";
282 | //优先显示tips
283 | caption.innerHTML = self.successTips || title;
284 | } else if(title === options.down.contentrefresherror) {
285 | loading.className = CLASS_LOADING_ERROR;
286 | loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
287 | loading.style.webkitTransform = "scale(1.2,1.2)";
288 | loading.style.webkitAnimation = "none";
289 | }
290 | } else {
291 | if(options.up) {
292 | if(title === options.up.contentrefresh) {
293 | loading.className = CLASS_LOADING + ' ' + CLASS_VISIBILITY;
294 | } else {
295 | loading.className = CLASS_LOADING + ' ' + CLASS_HIDDEN;
296 | }
297 | self._setCaptionClass(false, caption, title);
298 | }
299 |
300 | }
301 | this.lastTitle = title;
302 | }
303 | }
304 |
305 | }
306 | },
307 |
308 | });
309 |
310 | /**
311 | * @description 初始化下拉刷新组件,init是兼容工厂的调用方式
312 | * @param {JSON} options 传入的参数
313 | * @return 返回的是一个下拉刷新对象
314 | */
315 | PullToRefresh.init = function(options) {
316 | return new PullToRefresh(options);
317 | };
318 |
319 |
320 | CommonTools.namespace('skin.defaults', PullToRefresh);
321 |
322 | })({}, PullToRefreshTools);
--------------------------------------------------------------------------------
/src/pulltorefresh.skin.native.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 创建时间: 2017/03/28
4 | * 版本: [1.0, 2017/05/26 ]
5 | * 版权: dailc
6 | * 描述: 这个皮肤是ejs或钉钉下的下拉刷新,使用了他们自带提供的原生下拉刷新,以及自定义生成上拉加载
7 | * 注意:分别在ejs下或者钉钉下依赖对应的库文件
8 | */
9 | (function(exports, CommonTools) {
10 |
11 | var isSupportTouch = "ontouchend" in document ? true : false;
12 | //默认的下拉刷新每一个页面只支持一个,所以是单例模式
13 | var instance;
14 | //这里的isPullDown是指从上往下拉
15 | //pullup是指从下往上拉
16 | var isTouch = false,
17 | isPullDown = false;
18 | //定义一个global
19 | var global = {};
20 | /**
21 | * 默认的设置参数
22 | */
23 | var defaultSetting = {
24 | //下拉有关
25 | down: {
26 | callback: CommonTools.noop
27 | },
28 | //上拉有关
29 | up: {
30 | //是否自动上拉加载-初始化是是否自动
31 | auto: false,
32 | //是否隐藏那个加载更多动画,达到默认加载效果
33 | show: true,
34 | contentrefresh: '正在加载...',
35 | callback: CommonTools.noop
36 | },
37 | //注意,传给Mui时可以传 #id形式或者是 原生dom对象
38 | element: '#pullrefresh'
39 | };
40 | var pulluploadingTips = '{{contentrefresh}}
';
41 | /**
42 | * @description 兼容ejs情况下的下拉刷新
43 | * 去除多余dom
44 | * @param {HTMLElement} elem 对应的dom
45 | */
46 | function compatibleNative(elem) {
47 | //计划改变,ejs下拉刷新不使用scroll,否则不好计算什么时候可以滑动,而是直接去除这个dom
48 | // mui(elem).scroll({
49 | // deceleration: 0.0005 //flick 减速系数,系数越大,滚动速度越慢,滚动距离越小,默认值0.0006
50 | // });
51 | if (typeof elem === 'string') {
52 | elem = document.querySelector(elem);
53 | }
54 | if (CommonTools.os.ejs || CommonTools.os.dd) {
55 | //去除dom,ejs下拉刷新不需要scroll
56 | var pullRefreshDom = elem;
57 | pullRefreshDom.classList.remove('mui-scroll-wrapper');
58 | var scrollDom = pullRefreshDom.querySelector('.mui-scroll');
59 | if (scrollDom) {
60 | //pullRefreshDom.innerHTML = scrollDom.innerHTML;
61 | scrollDom.classList.remove('mui-scroll');
62 | }
63 | } else {
64 |
65 | }
66 |
67 | }
68 |
69 | /**
70 | * @description 将string字符串转为html对象,默认创一个div填充
71 | * @param {String} strHtml 目标字符串
72 | * @return {HTMLElement} 返回处理好后的html对象,如果字符串非法,返回null
73 | */
74 | function pareseStringToHtml(strHtml) {
75 | if (strHtml == null || typeof(strHtml) != "string") {
76 | return null;
77 | }
78 | //创一个灵活的div
79 | var i, a = document.createElement("div");
80 | var b = document.createDocumentFragment();
81 | a.innerHTML = strHtml;
82 | while (i = a.firstChild) b.appendChild(i);
83 | return b;
84 | }
85 | /**
86 | * @description 浏览器视口的高度
87 | * @return {Number} 返回具体高度
88 | */
89 | function getWinHeight() {
90 | var windowHeight = 0;
91 | if (document.compatMode == "CSS1Compat") {
92 | windowHeight = document.documentElement.clientHeight;
93 | } else {
94 | windowHeight = document.body.clientHeight;
95 | }
96 | return windowHeight;
97 | }
98 | /**
99 | * @description 获取滚动条在Y轴上的滚动距离
100 | * @return {Number} 返回具体距离
101 | */
102 | function getScrollTop() {
103 | var scrollTop = 0,
104 | bodyScrollTop = 0,
105 | documentScrollTop = 0;
106 | if (document.body) {
107 | bodyScrollTop = document.body.scrollTop || 0;
108 | }
109 | if (document.documentElement) {
110 | documentScrollTop = document.documentElement.scrollTop || 0;
111 | }
112 | scrollTop = (bodyScrollTop > documentScrollTop) ? bodyScrollTop : documentScrollTop;
113 | return scrollTop;
114 | }
115 | /**
116 | * @description 获取文档的总高度
117 | * @return {Number} 返回具体高度
118 | */
119 | function getScrollHeight() {
120 | var scrollHeight = 0,
121 | bodyScrollHeight = 0,
122 | documentScrollHeight = 0;
123 | if (document.body) {
124 | bodyScrollHeight = document.body.scrollHeight;
125 | }
126 |
127 | if (document.documentElement) {
128 | documentScrollHeight = document.documentElement.scrollHeight;
129 | }
130 | scrollHeight = (bodyScrollHeight - documentScrollHeight > 0) ? bodyScrollHeight : documentScrollHeight;
131 | return scrollHeight;
132 | }
133 | /**
134 | * @constructor 构造函数
135 | * @description 定义下拉刷新构造函数
136 | * @param {HTMLElement} elem
137 | * @param {JSON} options
138 | */
139 | function PullRefresh(options) {
140 | options = CommonTools.extend(true, {}, defaultSetting, options);
141 |
142 | var $this = this;
143 | var elem = options.container;
144 | $this.loadingUp = false;
145 | $this.finished = false;
146 | $this.options = options;
147 | if (typeof elem === 'string') {
148 | elem = document.querySelector(elem);
149 | }
150 | $this.elem = elem;
151 |
152 | //增加class
153 | $this.elem.classList.add('pulltorefresh-native-type');
154 | setPullDownFunc();
155 |
156 | if ($this.options.down) {
157 | if (CommonTools.os.dd) {
158 | //钉钉的下拉刷新
159 | //开启下拉刷新
160 | dd.ui.pullToRefresh.enable({
161 | onSuccess: function() {
162 | //alert('下拉刷新成功,立刻收起');
163 | $this.options.down.callback && $this.options.down.callback();
164 | },
165 | onFail: function() {
166 | //alert('下拉刷新失败');
167 | dd.ui.pullToRefresh.stop();
168 | }
169 | });
170 | } else {
171 | //ejs的下拉刷新
172 | //开启下拉刷新
173 | if (ejs.nativeUI) {
174 | ejs.nativeUI.pullToRefresh.enable(function() {
175 | $this.options.down.callback && $this.options.down.callback();
176 | });
177 | } else {
178 | ejs.ui.pullToRefresh.enable({
179 | success: function() {
180 | $this.options.down.callback && $this.options.down.callback();
181 | },
182 | error: function() {
183 | //alert('下拉刷新失败');
184 | ejs.ui.pullToRefresh.stop();
185 | }
186 | });
187 | }
188 |
189 | }
190 | }
191 |
192 | //兼容原生环境下的处理
193 | compatibleNative($this.elem || '#pullrefresh');
194 | }
195 | /**
196 | * @description 主动上拉加载更多
197 | */
198 | PullRefresh.prototype.pullupLoading = function() {
199 | if (instance.options.up) {
200 | //加载更多
201 | loadMoreAnimation(true);
202 | //触发上拉回调
203 | instance.options.up.callback && instance.options.up.callback();
204 | }
205 | };
206 | PullRefresh.prototype.endPullUpToRefresh = function(isNoMore) {
207 | if (isNoMore) {
208 | this.finished = true;
209 | }
210 | if (instance.options.up) {
211 | //去除加载更多动画
212 | loadMoreAnimation(false);
213 | }
214 | };
215 | PullRefresh.prototype.endPullDownToRefresh = function() {
216 | //关闭下拉刷新
217 | if (CommonTools.os.dd) {
218 | dd.ui.pullToRefresh.stop();
219 | } else if (CommonTools.os.ejs) {
220 | if (ejs.nativeUI) {
221 | ejs.nativeUI.pullToRefresh.stop();
222 | } else {
223 | ejs.ui.pullToRefresh.stop();
224 | }
225 | }
226 |
227 | };
228 | PullRefresh.prototype.refresh = function(refresh) {
229 | this.finished = false;
230 | };
231 | /**
232 | * @description 设置下拉刷新相关
233 | */
234 | function setPullDownFunc() {
235 | var x = 0,
236 | y = 0,
237 | scrollTop = 0;
238 | var b = document.body;
239 | //监听touch时间,模拟下拉
240 | var touchStartEvt = isSupportTouch ? 'touchstart' : 'mousedown';
241 | b.addEventListener(touchStartEvt, function(evt) {
242 | //console.log('touchstart');
243 | var touch;
244 | if (isSupportTouch) {
245 | touch = evt.touches[0]; //获取第一个触点
246 | } else {
247 | touch = evt;
248 | }
249 | x = Number(touch.pageX); //页面触点X坐标
250 | y = Number(touch.pageY); //页面触点Y坐标
251 | scrollTop = b.scrollTop;
252 | isTouch = true;
253 | //console.log('x = ' + x);
254 | //console.log('y = ' + y);
255 | //console.log('scrollTop = ' + scrollTop);
256 | });
257 | var touchEndEvt = isSupportTouch ? 'touchend' : 'mouseup';
258 | b.addEventListener(touchEndEvt, function(evt) {
259 | //console.log('touchend');
260 | isTouch = false;
261 | isPullDown = false;
262 | });
263 | var touchMoveEvt = isSupportTouch ? 'touchmove' : 'mousemove';
264 | b.addEventListener(touchMoveEvt, function(evt) {
265 | //console.log('touchmove');
266 | var touch;
267 | if (isSupportTouch) {
268 | touch = evt.touches[0]; //获取第一个触点
269 | } else {
270 | touch = evt;
271 | }
272 | var mx = Number(touch.pageX); //页面触点X坐标
273 | var my = Number(touch.pageY); //页面触点Y坐标
274 |
275 | //console.log("isTouch = " + isTouch)
276 | //console.log("y-my = " + (y-my))
277 | //console.log("b.scrollTop = " + b.scrollTop);
278 | if (isTouch) {
279 | if (my - y > 30) {
280 | if (b.scrollTop == 0) {
281 | if (!isPullDown) {
282 | console.log("PullDown");
283 | isPullDown = true;
284 | }
285 | }
286 | }
287 | //alert('scrollTop:'+scrollTop+',b.scrollTop:'+b.scrollTop+',y:'+y+',my:'+my);
288 | if (y - my > 100) {
289 |
290 | if (scrollTop == b.scrollTop) {
291 | if (!instance.loadingUp) {
292 | //console.log('my = ' + my);
293 | //console.log('y = ' + y);
294 | //console.log('scrollTop = ' + scrollTop);
295 | //console.log('b.scrollTop = ' + b.scrollTop);
296 | //console.log("pullup,finish:"+instance.finished);
297 | if (!instance.finished) {
298 | if (instance.options.up) {
299 | //加载更多
300 | loadMoreAnimation(true);
301 | //触发上拉回调
302 | instance.options.up.callback && instance.options.up.callback();
303 | }
304 | }
305 |
306 | }
307 | }
308 | }
309 |
310 | }
311 | });
312 |
313 | //ios下的补救措施
314 | var scrollFunc = function() {
315 | var y = getScrollTop();
316 | var slider = document.getElementById('sliderSegmentedControl');
317 |
318 | if ((y + getWinHeight()) === getScrollHeight()) {
319 | if (!instance.loadingUp) {
320 | if (!instance.finished) {
321 | if (instance.options.up) {
322 | //加载更多
323 | loadMoreAnimation(true);
324 | //触发上拉回调
325 | instance.options.up.callback && instance.options.up.callback();
326 | }
327 | }
328 | }
329 |
330 | }
331 | };
332 | document.onscroll = scrollFunc;
333 | }
334 | /**
335 | * @description 控制加载更多
336 | * @param {Boolean} more
337 | */
338 | function loadMoreAnimation(more) {
339 |
340 | var dom = instance.elem;
341 | if (!dom) {
342 | return;
343 | }
344 |
345 | if (more) {
346 | if (!instance.loadingUp) {
347 | //显示loading
348 | var content = instance.options.up.contentrefresh || '正在加载...';
349 | pulluploadingTips = pulluploadingTips.replace('{{contentrefresh}}', content);
350 | dom.appendChild(pareseStringToHtml(pulluploadingTips));
351 | instance.loadingUp = true;
352 | }
353 | } else {
354 | if (instance.loadingUp) {
355 | //隐藏loading
356 | var loadingDom = dom.querySelector('.mui-pull-bottom-tips');
357 | loadingDom && loadingDom.parentNode.removeChild(loadingDom);
358 | instance.loadingUp = false;
359 | }
360 | }
361 | }
362 |
363 | function initPullToRefresh(options) {
364 | if(instance) {
365 | return instance;
366 | }
367 | instance = new PullRefresh(options);
368 |
369 | if (options.up && options.up.auto) {
370 | // 如果设置了auto,则自动上拉一次
371 | instance.pullupLoading();
372 | }
373 |
374 | return instance;
375 | }
376 |
377 | CommonTools.namespace('skin.natives', initPullToRefresh);
378 |
379 | })({}, PullToRefreshTools);
--------------------------------------------------------------------------------
/src/pulltorefresh.skin.type1.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 创建时间: 2017/03/28
4 | * 版本: [1.0, 2017/05/26 ]
5 | * 版权: dailc
6 | * 描述: 皮肤类只会实现UI相关的hook函数
7 | * 默认皮肤,皮肤 type1 为了简化代码已经后续方便就没有再复用default了
8 | * 依赖mui的css
9 | */
10 | (function(exports, CommonTools) {
11 |
12 | // 默认的全局参数-主要用来配置下拉刷新提示的一些css class
13 | var NAMESPACE = 'mui-';
14 | var CLASS_PULL_TOP_POCKET = NAMESPACE + 'pull-top-pocket';
15 | var CLASS_PULL_BOTTOM_POCKET = NAMESPACE + 'pull-bottom-pocket';
16 | var CLASS_PULL = NAMESPACE + 'pull';
17 | var CLASS_PULL_LOADING = NAMESPACE + 'pull-loading';
18 | var CLASS_PULL_CAPTION = NAMESPACE + 'pull-caption';
19 | var CLASS_PULL_CAPTION_DOWN = NAMESPACE + 'pull-caption-down';
20 | var CLASS_PULL_CAPTION_REFRESH = NAMESPACE + 'pull-caption-refresh';
21 | var CLASS_PULL_CAPTION_NOMORE = NAMESPACE + 'pull-caption-nomore';
22 |
23 | var CLASS_ICON = NAMESPACE + 'icon';
24 | var CLASS_SPINNER = NAMESPACE + 'spinner';
25 | var CLASS_ICON_PULLDOWN = NAMESPACE + 'icon-pulldown';
26 | var CLASS_ICON_SUCCESS = NAMESPACE + 'icon-checkmarkempty';
27 | var CLASS_ICON_ERROR = NAMESPACE + 'icon-info';
28 |
29 | var CLASS_BLOCK = NAMESPACE + 'block';
30 | var CLASS_HIDDEN = NAMESPACE + 'hidden';
31 | var CLASS_VISIBILITY = NAMESPACE + 'visibility';
32 |
33 | var CLASS_LOADING_UP = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_PULLDOWN;
34 | var CLASS_LOADING_DOWN = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_PULLDOWN;
35 | var CLASS_LOADING = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_SPINNER;
36 |
37 | var CLASS_LOADING_SUCCESS = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_SUCCESS;
38 | var CLASS_LOADING_ERROR = CLASS_PULL_LOADING + ' ' + CLASS_ICON + ' ' + CLASS_ICON_ERROR;
39 | var pocketHtml = ['', '
', '
{contentrefresh}
', '
'].join('');
40 |
41 |
42 | var PullToRefresh = CommonTools.core.extend({
43 |
44 | /**
45 | * @description 生成下拉刷新提示,这个需要被具体实现
46 | * 这个默认实现就直接在一个函数里面同时生成下拉和上拉提示了
47 | */
48 | _initPullToRefreshTipsHook: function(enablePullDown, enablePullUp) {
49 | this._initPocket();
50 | if(!enablePullUp) {
51 | this.bottomPocket && this.bottomPocket.classList.add(CLASS_HIDDEN);
52 | }
53 | if(!enablePullDown) {
54 | this.topPocket && this.topPocket.classList.add(CLASS_HIDDEN);
55 | }
56 | },
57 | /**
58 | * @description 初始化下拉刷新
59 | */
60 | _initPulldownRefreshState: function() {
61 | this.pullPocket = this.topPocket;
62 | this.pullPocket.classList.add(CLASS_BLOCK);
63 | this.pullPocket.classList.add(CLASS_VISIBILITY);
64 | this.pullCaption = this.topCaption;
65 | this.pullLoading = this.topLoading;
66 |
67 | },
68 | /**
69 | * @description 初始化上拉加载
70 | */
71 | _initPullupRefreshState: function() {
72 | this.pullPocket = this.bottomPocket;
73 | this.pullPocket.classList.add(CLASS_BLOCK);
74 | this.pullPocket.classList.add(CLASS_VISIBILITY);
75 | this.pullCaption = this.bottomCaption;
76 | this.pullLoading = this.bottomLoading;
77 | },
78 | /**
79 | * @description 下拉过程中的钩子函数
80 | * @param {Number} deltaY
81 | * @param {Number} thresholdHeight 对应的高度阈值
82 | */
83 | _pullingHook: function(deltaY, thresholdHeight) {
84 | // 高度阈值
85 | if(deltaY >= thresholdHeight) {
86 | this._setCaption(true, this.options.down.contentover);
87 | } else if(deltaY < thresholdHeight) {
88 | this._setCaption(true, this.options.down.contentdown);
89 | }
90 | },
91 | /**
92 | * @description 下拉刷新的成功动画,每次确保触发一次
93 | */
94 | _pulldownLoaingAnimationHook: function() {
95 | this._setCaption(true, this.options.down.contentrefresh);
96 | },
97 | /**
98 | * @description 下拉刷新的成功动画-动画完毕后可能的成功提示,每次确保触发一次
99 | * 比如在成功里面提示加载了多少条数据,如果不需要可以传null,会直接走到end事件里
100 | * @param {Function} done 这个可以提前结束动画-如果不想要的话
101 | * @param {Boolean} isSuccess 是否请求成功
102 | */
103 | _pulldownLoaingAnimationSuccessHook: function(done, isSuccess) {
104 | if(this.options.down.isSuccessTips) {
105 | this._setCaption(true, isSuccess ? this.options.down.contentrefreshsuccess : this.options.down.contentrefresherror);
106 | } else {
107 | // 否则直接没有成功提示
108 | done();
109 | }
110 |
111 | },
112 | /**
113 | * @description 下拉刷新的动画完成后的回调,可以用来重置状态
114 | */
115 | _pulldownLoaingAnimationEndHook: function() {
116 | this._setCaption(true, this.options.down.contentdown, true);
117 | this.topPocket.classList.remove(CLASS_VISIBILITY);
118 | },
119 | /**
120 | * @description 上拉加载的成功动画,每次确保触发一次
121 | */
122 | _pullupLoaingAnimationHook: function(isFinished) {
123 | this._setCaption(false, this.options.up.contentrefresh);
124 | },
125 | /**
126 | * @description 上拉加载的成功动画-动画完毕后可能的成功提示,每次确保触发一次
127 | */
128 | _pullupLoaingAnimationSuccessHook: function(isFinished) {
129 | if(isFinished) {
130 | this._setCaption(false, this.options.up.contentnomore);
131 | } else {
132 | this._setCaption(false, this.options.up.contentdown);
133 | }
134 | // this.bottomPocket.classList.remove(CLASS_VISIBILITY);
135 | },
136 | /**
137 | * @description _disablePullUpHook
138 | */
139 | _disablePullUpHook: function() {
140 | this.bottomPocket.className = 'mui-pull-bottom-pocket' + ' ' + CLASS_HIDDEN;
141 | },
142 | /**
143 | * @description disablePullUpHook
144 | */
145 | _enablePullUpHook: function() {
146 | this.bottomPocket.classList.remove(CLASS_HIDDEN);
147 | this._setCaption(false, this.options.up.contentdown);
148 | },
149 | /**
150 | * @description 创建上拉提示或下拉提示
151 | * @param {Object} clazz
152 | * @param {Object} options
153 | * @param {Object} iconClass
154 | */
155 | _createPocket: function(clazz, options, iconClass) {
156 | var pocket = document.createElement('div');
157 | pocket.className = clazz;
158 | pocket.innerHTML = pocketHtml.replace('{contentrefresh}', options.contentdown).replace('{icon}', iconClass);
159 | return pocket;
160 | },
161 | /**
162 | * @description 初始化下拉刷新和上拉加载提示
163 | */
164 | _initPocket: function() {
165 | var options = this.options;
166 | if(options.down && options.down.hasOwnProperty('callback')) {
167 | this.topPocket = this.wrapper.querySelector('.' + CLASS_PULL_TOP_POCKET);
168 | if(!this.topPocket) {
169 | this.topPocket = this._createPocket(CLASS_PULL_TOP_POCKET, options.down, CLASS_LOADING_DOWN);
170 | // this.wrapper.insertBefore(this.topPocket, this.wrapper.firstChild);
171 | this.scrollWrap.insertBefore(this.topPocket, this.scrollWrap.firstChild);
172 | }
173 | this.topLoading = this.topPocket.querySelector('.' + CLASS_PULL_LOADING);
174 | this.topCaption = this.topPocket.querySelector('.' + CLASS_PULL_CAPTION);
175 | // 这里为了方便,就不再单独引入样式文件了,而是直接通过style改写mui的样式
176 | // 将absulute改写为 relative visibility改为visible;
177 | this.topPocket.style.position = 'relative';
178 |
179 | }
180 | if(options.up && options.up.hasOwnProperty('callback')) {
181 | this.bottomPocket = this.scrollWrap.querySelector('.' + CLASS_PULL_BOTTOM_POCKET);
182 | if(!this.bottomPocket) {
183 | this.bottomPocket = this._createPocket(CLASS_PULL_BOTTOM_POCKET, options.up, CLASS_LOADING);
184 | this.scrollWrap.appendChild(this.bottomPocket);
185 | }
186 | this.bottomLoading = this.bottomPocket.querySelector('.' + CLASS_PULL_LOADING);
187 | this.bottomCaption = this.bottomPocket.querySelector('.' + CLASS_PULL_CAPTION);
188 | }
189 |
190 | // 需要滑动到offset位置
191 | // 这个如果不设置,下拉的提示就会位置不正确
192 | // 需要设一个定时,否则可能计算失误,这里在返回到offset前就先隐藏了
193 | var self = this;
194 | setTimeout(function() {
195 | // 暂时写死一个,用offset有时会有失误
196 | // self.topPocket.offsetHeight||0
197 | self.topPocket && self._setOffsetY(50, function() {
198 | self.topPocket.style.visibility = 'visible';
199 | self.bottomPocket && (self.bottomPocket.style.visibility = 'visible');
200 | });
201 | }, 0);
202 | },
203 |
204 | /**
205 | * @description 设置提示的class
206 | * @param {Object} isPulldown
207 | * @param {Object} caption
208 | * @param {Object} title
209 | */
210 | _setCaptionClass: function(isPulldown, caption, title) {
211 | if(!this.options.up) {
212 | return;
213 | }
214 | if(!isPulldown) {
215 |
216 | switch(title) {
217 | case this.options.up.contentdown:
218 | caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_DOWN;
219 | break;
220 | case this.options.up.contentrefresh:
221 | caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_REFRESH
222 | break;
223 | case this.options.up.contentnomore:
224 | caption.className = CLASS_PULL_CAPTION + ' ' + CLASS_PULL_CAPTION_NOMORE;
225 | break;
226 | }
227 | }
228 | },
229 | /**
230 | * @description 设置caption
231 | * @param {Object} isPulldown
232 | * @param {Object} title
233 | * @param {Object} reset
234 | */
235 | _setCaption: function(isPulldown, title, reset) {
236 | if(this.loading) {
237 | return;
238 | }
239 | if(isPulldown) {
240 | this._initPulldownRefreshState();
241 | } else {
242 | this._initPullupRefreshState();
243 | }
244 | var options = this.options;
245 | var pocket = this.pullPocket;
246 | var caption = this.pullCaption;
247 | var loading = this.pullLoading;
248 | var isPulldown = this.pulldown;
249 | var self = this;
250 | if(pocket) {
251 | if(reset) {
252 | setTimeout(function() {
253 | caption.innerHTML = self.lastTitle = title;
254 | if(isPulldown) {
255 | loading.className = CLASS_LOADING_DOWN;
256 | } else {
257 | self._setCaptionClass(false, caption, title);
258 | loading.className = CLASS_LOADING;
259 | }
260 | loading.style.webkitAnimation = "";
261 | loading.style.webkitTransition = "";
262 | loading.style.webkitTransform = "";
263 | }, 100);
264 | } else {
265 | if(title !== this.lastTitle) {
266 | caption.innerHTML = title;
267 | if(isPulldown) {
268 | if(title === options.down.contentrefresh) {
269 | loading.className = CLASS_LOADING;
270 | loading.style.webkitAnimation = "spinner-spin 1s step-end infinite";
271 | } else if(title === options.down.contentover) {
272 | loading.className = CLASS_LOADING_UP;
273 | loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
274 | loading.style.webkitTransform = "rotate(180deg)";
275 | } else if(title === options.down.contentdown) {
276 | loading.className = CLASS_LOADING_DOWN;
277 | loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
278 | loading.style.webkitTransform = "rotate(0deg)";
279 | } else if(title === options.down.contentrefreshsuccess) {
280 | // 隐藏loading先
281 | loading.className = CLASS_LOADING_SUCCESS;
282 | loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
283 | loading.style.webkitTransform = "scale(1.2,1.2)";
284 | loading.style.webkitAnimation = "none";
285 | // 优先显示tips
286 | caption.innerHTML = self.successTips || title;
287 | } else if(title === options.down.contentrefresherror) {
288 | loading.className = CLASS_LOADING_ERROR;
289 | loading.style.webkitTransition = "-webkit-transform 0.3s ease-in";
290 | loading.style.webkitTransform = "scale(1.2,1.2)";
291 | loading.style.webkitAnimation = "none";
292 | }
293 | } else {
294 | if(options.up) {
295 | if(title === options.up.contentrefresh) {
296 | loading.className = CLASS_LOADING + ' ' + CLASS_VISIBILITY;
297 | } else {
298 | loading.className = CLASS_LOADING + ' ' + CLASS_HIDDEN;
299 | }
300 | self._setCaptionClass(false, caption, title);
301 | }
302 |
303 | }
304 | this.lastTitle = title;
305 | }
306 | }
307 |
308 | }
309 | },
310 |
311 | });
312 |
313 | /**
314 | * @description 初始化下拉刷新组件
315 | * @param {JSON} options 传入的参数
316 | * @return 返回的是一个下拉刷新对象
317 | */
318 | PullToRefresh.init = function(options) {
319 | return new PullToRefresh(options);
320 | };
321 |
322 | CommonTools.namespace('skin.type1', PullToRefresh);
323 |
324 | })({}, PullToRefreshTools);
--------------------------------------------------------------------------------
/src/pulltorefresh.skin.type2.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 创建时间: 2017/03/28
4 | * 版本: [1.0, 2017/05/26 ]
5 | * 版权: dailc
6 | * 描述: 皮肤类只会实现UI相关的hook函数
7 | * 皮肤 type2 ,不再基于mui的css,而是有自己的资源引用
8 | * 依赖 pulltorefresh.skin.css
9 | */
10 | (function(exports, CommonTools) {
11 |
12 | /**
13 | * 全局参数
14 | */
15 | var CLASS_HIDDEN = 'hidden';
16 |
17 | var PullToRefresh = CommonTools.core.extend({
18 |
19 | /**
20 | * @description 生成下拉刷新提示,这个需要被具体实现
21 | * 这个默认实现就直接在一个函数里面同时生成下拉和上拉提示了
22 | */
23 | _initPullToRefreshTipsHook: function(enablePullDown, enablePullUp) {
24 | this._initPocket();
25 | this._checkHidden(enablePullDown, enablePullUp);
26 | },
27 |
28 | _checkHidden: function(enablePullDown, enablePullUp) {
29 | if(!enablePullUp) {
30 | this.bottomPocket && this.bottomPocket.classList.add(CLASS_HIDDEN);
31 | }
32 | if(!enablePullDown) {
33 | this.topPocket && this.topPocket.classList.add(CLASS_HIDDEN);
34 | }
35 | },
36 |
37 | /**
38 | * @description 下拉过程中的钩子函数
39 | * @param {Number} deltaY
40 | * @param {Number} thresholdHeight 对应的高度阈值
41 | */
42 | _pullingHook: function(deltaY, thresholdHeight) {
43 | // 高度阈值
44 | if(deltaY >= thresholdHeight) {
45 | this._setCaption(true, this.options.down.contentover);
46 | } else if(deltaY < thresholdHeight) {
47 | this._setCaption(true, this.options.down.contentdown);
48 | }
49 | },
50 | /**
51 | * @description 下拉刷新的成功动画,每次确保触发一次
52 | */
53 | _pulldownLoaingAnimationHook: function() {
54 | this._setCaption(true, this.options.down.contentrefresh);
55 | },
56 | /**
57 | * @description 下拉刷新的成功动画-动画完毕后可能的成功提示,每次确保触发一次
58 | * 比如在成功里面提示加载了多少条数据,如果不需要可以传null,会直接走到end事件里
59 | * @param {Function} done 这个可以提前结束动画-如果不想要的话
60 | * @param {Boolean} isSuccess 是否请求成功
61 | */
62 | _pulldownLoaingAnimationSuccessHook: function(done, isSuccess) {
63 | if(this.options.down.isSuccessTips) {
64 | this._setCaption(true, isSuccess ? this.options.down.contentrefreshsuccess : this.options.down.contentrefresherror);
65 | } else {
66 | // 否则直接没有成功提示
67 | done();
68 | }
69 |
70 | },
71 | /**
72 | * @description 下拉刷新的动画完成后的回调,可以用来重置状态
73 | */
74 | _pulldownLoaingAnimationEndHook: function() {
75 | this._setCaption(true, this.options.down.contentdown, true);
76 |
77 | },
78 | /**
79 | * @description 上拉加载的成功动画,每次确保触发一次
80 | */
81 | _pullupLoaingAnimationHook: function(isFinished) {
82 | this._setCaption(false, this.options.up.contentrefresh);
83 | },
84 | /**
85 | * @description 上拉加载的成功动画-动画完毕后可能的成功提示,每次确保触发一次
86 | */
87 | _pullupLoaingAnimationSuccessHook: function(isFinished) {
88 | if(isFinished) {
89 | this._setCaption(false, this.options.up.contentnomore);
90 | } else {
91 | this._setCaption(false, this.options.up.contentdown);
92 | }
93 | // this.bottomPocket.classList.remove(CLASS_VISIBILITY);
94 | },
95 | /**
96 | * @description _disablePullUpHook
97 | */
98 | _disablePullUpHook: function() {
99 | this.bottomPocket.className = 'pull-bottom-pocket' + ' ' + CLASS_HIDDEN;
100 | },
101 | /**
102 | * @description disablePullUpHook
103 | */
104 | _enablePullUpHook: function() {
105 | this.bottomPocket.classList.remove(CLASS_HIDDEN);
106 | this._setCaption(false, this.options.up.contentdown);
107 | },
108 | /**
109 | * @description 创建下拉提示
110 | */
111 | _createTopPocket: function() {
112 | var pocket = document.createElement('div');
113 | pocket.style.visibility = 'hidden';
114 | pocket.className = 'pull-top-pocket';
115 | pocket.innerHTML = '' + this.options.down.contentdown + '
';
116 | return pocket;
117 | },
118 | /**
119 | * @description 创建上拉提示
120 | */
121 | _createBottomPocket: function() {
122 | var pocket = document.createElement('div');
123 | pocket.style.visibility = 'hidden';
124 | pocket.className = 'pull-bottom-pocket';
125 | pocket.innerHTML = '' + this.options.up.contentdown + '
';
126 | return pocket;
127 | },
128 | /**
129 | * @description 初始化下拉刷新和上拉加载提示
130 | */
131 | _initPocket: function() {
132 | // 先改变wrap的皮肤
133 | this.wrapper.classList.add('pulltorefresh-type2');
134 | var options = this.options;
135 | if(options.down && options.down.hasOwnProperty('callback')) {
136 | if(!this.topPocket) {
137 | this.topPocket = this._createTopPocket();
138 |
139 | this.scrollWrap.insertBefore(this.topPocket, this.scrollWrap.firstChild);
140 | }
141 | }
142 | if(options.up && options.up.hasOwnProperty('callback')) {
143 | if(!this.bottomPocket) {
144 | this.bottomPocket = this._createBottomPocket();
145 | this.scrollWrap.appendChild(this.bottomPocket);
146 | }
147 | }
148 | // 需要滑动到offset位置
149 | // 这个如果不设置,下拉的提示就会位置不正确
150 | // 需要设一个定时,否则可能计算失误,这里在返回到offset前就先隐藏了
151 | var self = this;
152 | setTimeout(function() {
153 | // 暂时写死一个,用offset有时会有失误
154 | // self.topPocket.offsetHeight||0
155 | self.topPocket && self._setOffsetY(74, function() {
156 | self.topPocket.style.visibility = 'visible';
157 | self.bottomPocket && (self.bottomPocket.style.visibility = 'visible');
158 | });
159 | }, 0);
160 | },
161 |
162 | /**
163 | * @description 设置caption
164 | * @param {Object} isPulldown
165 | * @param {Object} title
166 | * @param {Object} reset
167 | */
168 | _setCaption: function(isPulldown, title, reset) {
169 | if(this.loading) {
170 | return;
171 | }
172 | var pocket;
173 | if(isPulldown) {
174 | pocket = this.topPocket;
175 |
176 | } else {
177 | pocket = this.bottomPocket;
178 | }
179 | var label = pocket.querySelector('.pull-caption');
180 | var options = this.options;
181 | var self = this;
182 | if(pocket) {
183 | if(reset) {
184 | setTimeout(function() {
185 | pocket.className = 'pull-top-pocket ';
186 | label.innerHTML = options.down.contentdown;
187 | }, 100);
188 | } else {
189 | if(title !== this.lastTitle) {
190 | label.innerHTML = title;
191 | if(isPulldown) {
192 | if(title === options.down.contentrefresh) {
193 | pocket.className = 'pull-top-pocket loading';
194 |
195 | } else if(title === options.down.contentover) {
196 | pocket.className = 'pull-top-pocket flip';
197 |
198 | } else if(title === options.down.contentdown) {
199 | pocket.className = 'pull-top-pocket ';
200 | } else if(title === options.down.contentrefreshsuccess) {
201 | // 优先显示tips
202 | label.innerHTML = self.successTips || title;
203 | pocket.className = 'pull-top-pocket success';
204 | } else if(title === options.down.contentrefresherror) {
205 | pocket.className = 'pull-top-pocket error';
206 | }
207 | } else {
208 | if(options.up) {
209 | if(title === options.up.contentrefresh) {
210 | pocket.classList.remove('nomore');
211 | pocket.classList.add('loading');
212 | } else {
213 | pocket.classList.remove('loading');
214 |
215 | if(title === options.up.contentnomore) {
216 | pocket.classList.add('nomore');
217 | } else {
218 | pocket.classList.remove('nomore');
219 | }
220 |
221 | }
222 |
223 | }
224 |
225 | }
226 | this.lastTitle = title;
227 | }
228 | }
229 |
230 | }
231 | },
232 |
233 | });
234 |
235 | /**
236 | * @description 初始化下拉刷新组件
237 | * @param {JSON} options 传入的参数
238 | * @return 返回的是一个下拉刷新对象
239 | */
240 | PullToRefresh.init = function(options) {
241 | return new PullToRefresh(options);
242 | };
243 |
244 |
245 | CommonTools.namespace('skin.type2', PullToRefresh);
246 |
247 | })({}, PullToRefreshTools);
--------------------------------------------------------------------------------
/src/pulltorefresh.skin.type5.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 作者: dailc
3 | * 创建时间: 2017/08/14
4 | * 版本: [1.0, 2017/08/14 ]
5 | * 版权: dailc
6 | * 描述: 皮肤类只会实现UI相关的hook函数
7 | * 皮肤 type5
8 | * 仿微信小程序效果
9 | *
10 | */
11 | (function(CommonTools) {
12 |
13 | /**
14 | * 全局参数
15 | */
16 | var CLASS_HIDDEN = 'hidden';
17 |
18 | var PullToRefresh = CommonTools.core.extend({
19 |
20 | /**
21 | * @description 生成下拉刷新提示,这个需要被具体实现
22 | * 这个默认实现就直接在一个函数里面同时生成下拉和上拉提示了
23 | */
24 | _initPullToRefreshTipsHook: function(enablePullDown, enablePullUp) {
25 | this._initPocket();
26 | this._checkHidden(enablePullDown, enablePullUp);
27 | },
28 |
29 | _checkHidden: function(enablePullDown, enablePullUp) {
30 | if (!enablePullUp) {
31 | this.bottomPocket && this.bottomPocket.classList.add(CLASS_HIDDEN);
32 | }
33 | if (!enablePullDown) {
34 | this.topPocket && this.topPocket.classList.add(CLASS_HIDDEN);
35 | }
36 | },
37 |
38 | /**
39 | * @description 下拉过程中的钩子函数
40 | * @param {Number} deltaY
41 | * @param {Number} thresholdHeight 对应的高度阈值
42 | */
43 | _pullingHook: function(deltaY, thresholdHeight) {
44 | if ((this.options.down && this.options.down.cssAnimation)) {
45 | // 高度阈值,暂时不做其他事情
46 | if (deltaY <= thresholdHeight) {
47 | this.topLoading.style.webkitTransform = 'translateY(' + (-50 + deltaY / thresholdHeight * 50) + 'px)';
48 | this.topLoading.style.transform = 'translateY(' + (-50 + deltaY / thresholdHeight * 50) + 'px)';
49 | } else {
50 | this.topLoading.style.webkitTransform = 'translateY(0)';
51 | this.topLoading.style.transform = 'translateY(0)';
52 | }
53 | }
54 |
55 | },
56 | /**
57 | * @description 下拉刷新的成功动画,每次确保触发一次
58 | */
59 | _pulldownLoaingAnimationHook: function() {
60 | // 添加loading class
61 | this.topPocket.classList.add('loading');
62 | },
63 | /**
64 | * @description 下拉刷新的成功动画-动画完毕后可能的成功提示,每次确保触发一次
65 | * 比如在成功里面提示加载了多少条数据,如果不需要可以传null,会直接走到end事件里
66 | * @param {Function} done 这个可以提前结束动画-如果不想要的话
67 | * @param {Boolean} isSuccess 是否请求成功
68 | */
69 | _pulldownLoaingAnimationSuccessHook: function(done, isSuccess) {
70 | // 此皮肤没有成功提示
71 | done();
72 | },
73 | /**
74 | * @description 下拉刷新的动画完成后的回调,可以用来重置状态
75 | */
76 | _pulldownLoaingAnimationEndHook: function() {
77 | // 移除loading class
78 | this.topPocket.classList.remove('loading');
79 | if (this.options.down && this.options.down.cssAnimation) {
80 | this.topLoading.style.webkitTransform = 'translateY(-50px)';
81 | this.topLoading.style.transform = 'translateY(-50px)';
82 | }
83 |
84 | },
85 | /**
86 | * @description 上拉加载的成功动画,每次确保触发一次
87 | */
88 | _pullupLoaingAnimationHook: function(isFinished) {
89 | this._setCaption(false, this.options.up.contentrefresh);
90 | },
91 | /**
92 | * @description 上拉加载的成功动画-动画完毕后可能的成功提示,每次确保触发一次
93 | */
94 | _pullupLoaingAnimationSuccessHook: function(isFinished) {
95 | if (isFinished) {
96 | this._setCaption(false, this.options.up.contentnomore);
97 | } else {
98 | this._setCaption(false, this.options.up.contentdown);
99 | }
100 | // this.bottomPocket.classList.remove(CLASS_VISIBILITY);
101 | },
102 | /**
103 | * @description _disablePullUpHook
104 | */
105 | _disablePullUpHook: function() {
106 | this.bottomPocket.className = 'pull-bottom-pocket' + ' ' + CLASS_HIDDEN;
107 | },
108 | /**
109 | * @description disablePullUpHook
110 | */
111 | _enablePullUpHook: function() {
112 | this.bottomPocket.classList.remove(CLASS_HIDDEN);
113 | this._setCaption(false, this.options.up.contentdown);
114 | },
115 | /**
116 | * @description 创建下拉提示
117 | */
118 | _createTopPocket: function() {
119 | var pocket = document.createElement('div');
120 | //pocket.style.visibility = 'hidden';
121 | pocket.className = 'pull-top-pocket';
122 | pocket.innerHTML = '';
123 | return pocket;
124 | },
125 | /**
126 | * @description 创建上拉提示
127 | */
128 | _createBottomPocket: function() {
129 | var pocket = document.createElement('div');
130 | //pocket.style.visibility = 'hidden';
131 | pocket.className = 'pull-bottom-pocket';
132 | pocket.innerHTML = '' + this.options.up.contentdown + '
';
133 | return pocket;
134 | },
135 | /**
136 | * @description 初始化下拉刷新和上拉加载提示
137 | */
138 | _initPocket: function() {
139 | // 改变配置
140 | this.options.down.cssAnimation = true;
141 | // 先改变wrap的皮肤
142 | this.wrapper.classList.add('pulltorefresh-type5');
143 | var options = this.options;
144 | if (options.down && options.down.hasOwnProperty('callback')) {
145 | if (!this.topPocket) {
146 | this.topPocket = this._createTopPocket();
147 |
148 | // 插到wrap中
149 | this.wrapper.insertBefore(this.topPocket, this.wrapper.firstChild);
150 | }
151 |
152 | this.topLoading = this.topPocket.querySelector('.pull-block');
153 |
154 | if (this.options.down && this.options.down.cssAnimation) {
155 | // 单独渲染图层,优化动画
156 | this.topPocket.style.webkitTransform = 'translateZ(0)';
157 | this.topPocket.style.transform = 'translateZ(0)';
158 | this.topLoading.style.webkitTransform = 'translateY(-50px)';
159 | this.topLoading.style.transform = 'translateY(-50px)';
160 | }
161 |
162 | }
163 | if (options.up && options.up.hasOwnProperty('callback')) {
164 | if (!this.bottomPocket) {
165 | this.bottomPocket = this._createBottomPocket();
166 | this.scrollWrap.appendChild(this.bottomPocket);
167 | }
168 | }
169 | },
170 |
171 | /**
172 | * @description 设置caption
173 | * @param {Object} isPulldown
174 | * @param {Object} title
175 | * @param {Object} reset
176 | */
177 | _setCaption: function(isPulldown, title, reset) {
178 | if (this.loading) {
179 | return;
180 | }
181 | var pocket;
182 | if (isPulldown) {
183 | // 本皮肤上拉没有文字提示
184 | return;
185 |
186 | } else {
187 | pocket = this.bottomPocket;
188 | }
189 | var label = pocket.querySelector('.pull-caption');
190 | var options = this.options;
191 | var self = this;
192 | if (pocket) {
193 | if (title !== this.lastTitle) {
194 | label.innerHTML = title;
195 | if (options.up) {
196 | if (title === options.up.contentrefresh) {
197 | pocket.classList.remove('nomore');
198 | pocket.classList.add('loading');
199 | } else {
200 | pocket.classList.remove('loading');
201 |
202 | if (title === options.up.contentnomore) {
203 | pocket.classList.add('nomore');
204 | } else {
205 | pocket.classList.remove('nomore');
206 | }
207 |
208 | }
209 |
210 | }
211 | this.lastTitle = title;
212 | }
213 | }
214 | },
215 |
216 | });
217 |
218 | CommonTools.namespace('skin.type5', PullToRefresh);
219 |
220 | })(PullToRefreshTools);
--------------------------------------------------------------------------------
/staticresource/img/effect1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/staticresource/img/effect1.gif
--------------------------------------------------------------------------------
/staticresource/img/effect2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/staticresource/img/effect2.gif
--------------------------------------------------------------------------------
/staticresource/img/effect3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/staticresource/img/effect3.gif
--------------------------------------------------------------------------------
/staticresource/img/effect4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/staticresource/img/effect4.gif
--------------------------------------------------------------------------------
/staticresource/img/effect5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/staticresource/img/effect5.gif
--------------------------------------------------------------------------------
/staticresource/img/effect6.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dailc/pulltorefresh-h5-iscroll/f221a5e60e6f6c1c955e99f3ea59c1f373ff08ae/staticresource/img/effect6.gif
--------------------------------------------------------------------------------