`
sslaowan
  • 浏览: 373775 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

DCloud下拉刷新上拉加载

 
阅读更多

补充一些文档里没有的。

    官方案例里,就是pullrefresh_main.html和pullrefresh_sub.html这两个文件。

 

    在pullrefresh_main.html中:

Js代码  收藏代码
  1. if(mui.os.ios){  
  2.             contentWebview.evalJS("mui('#pullrefresh').pullRefresh().scrollTo(0,0,100)");  
  3.         }else{  
  4.             contentWebview.evalJS('mui.scrollTo(0, 100)');  
  5.         }  

    其中mui('#pullrefresh')获得了子页面中id为pullrefresh的div的对象,这段代码的目的是让让滚动条在顶部。如官方文档所言,Android是用Webview实现,iOS是用H5(div)实现。下面这个代码是针对Android使用HTML5+实现的。在iOS中,用div模拟scroll,因此scrollTo方法属于pullRefresh这个方法返回的js对象。而对于Android而言,使用的是H5+扩展,scrollTo直接就是Webkit方法。

  注:下面的诸多方法都有5+和H5两种不同实现,但是逻辑是基本一致的,方法名也一样,只是前者是利用Webview的各种方法调用,后者是针对H5.

 在pushfresh_sub.html中调用了pullRefresh().pullupLoading()的,目的是为了初始化(首次加载)表格

 

Js代码  收藏代码
  1. if (mui.os.plus) {  
  2.             mui.plusReady(function() {  
  3.                 setTimeout(function() {  
  4.                     mui('#pullrefresh').pullRefresh().pullupLoading();  
  5.                 }, 1000);  
  6.   
  7.             });  
  8.         } else {  
  9.             mui.ready(function() {  
  10.                 mui('#pullrefresh').pullRefresh().pullupLoading();  
  11.             });  
  12.         }  

   接下来我们分析代码是如何实现上述目的的。

  首先我们来分析mui('#pullrefresh').pullRefresh()是怎么回事?

  在mui.js中包含pullRefresh代码主要作用是初始化PullRefresh对象,但是针对iOS和Android是不同的,前者是js对象,后者是H5+对象。

  H5版本的pullRefresh方法如下:

  Js代码  收藏代码

  1. $.fn.pullRefresh = function(options) {  
  2.     if (this.length === 1) {  
  3.         var self = this[0];  
  4.         var pullRefreshApi = null;  
  5.         options = options || {};  
  6.         var id = self.getAttribute('data-pullrefresh');  
  7.         if (!id) {  
  8.             id = ++$.uuid;  
  9.             $.data[id] =  pullRefreshApi = new PullRefresh(self, options);  
  10.             self.setAttribute('data-pullrefresh', id);  
  11.         } else {  
  12.             pullRefreshApi = $.data[id];  
  13.         }  
  14.         if (options.up && options.up.auto) { //如果设置了auto,则自动上拉一次,在官方例子中,没有设置auto,因此在sub.html中主动调用了一次
  15.             pullRefreshApi.pullupLoading();
  16.         }  
  17.           
  18.         return pullRefreshApi;  
  19.     }  
  20. };  

     注意:后面的PlusPullRefresh是绑定在Webview整个dom的扩展,然后$.fn.pullRefresh对于全局有效(jquery的语法规则),因此 $container.pullrefresh就是调用的$.fn.pullRefresh  

其中核心是:

  1、返回了PullRefresh或PlusPullRefresh对象

  2、如果up设置了auto属性为true,则自动调用up对应的上拉加载函数加载一起数据。

 

然后我们来看看pullRefresh如何调用的pullupLoading

 

   我们可以看到,实际调用pullupLoading是通过pullRefreshApi的,而后者其实是pullupRefresh中创建的PullupRefresh对象的引用,该对象有个pullupLoading()方法,其将在mui.init中声明的options作为参数传到内部,new PullRefresh(self, options);。 

 

 

  
Js代码  收藏代码
  1. function($, window, document, undefined) {  
  2.   
  3.     var CLASS_VISIBILITY = 'mui-visibility';  
  4.     var CLASS_HIDDEN = 'mui-hidden';  
  5.   
  6.     var PullRefresh = $.Scroll.extend($.extend({  
  7.         handleEvent: function(e) {  
  8.             this._super(e);  
  9.   
  10.   
  11.     ........  
  12.   
  13.     pullupLoading:  function(callback, x, time) {  
  14.             x = x || 0;  
  15.             this.scrollTo(x, this.maxScrollY, time, this.options.bounceEasing);  
  16.             if (this.loading) {  
  17.                 return;  
  18.             }  
  19.             this._initPullupRefresh();  
  20.             this._setCaption(this.options.up.contentrefresh);  
  21.             this.indicators.map(function(indicator) {  
  22.                 indicator.fade(0);  
  23.             });  
  24.             this.loading = true;  
  25.             callback = callback || this.options.up.callback;  
  26.             callback && callback.call(this);  
  27.         }, 

 

  从callback= callback || this.options.up.callback;可以看出pullupLoading方法中调用了up.callback,callback.call(this)换言之,mui('#pullrefresh').pullRefresh().pullupLoading();等于是调用了 pullupRefresh //上拉加载具体业务实现 方法。

  那为什么this.options.up.callback对应的就是pullupFresh呢?

 

  那么pullupLoading是如何调用up对应pullupRefresh自定义方法的?  

   简而言之,是因为在初始化时,将pullupRefresh方法赋值给了up的callback方法。如下代码所示。

Js代码  收藏代码
  1. mui.init({  
  2.             pullRefresh: {  
  3.                 container: '#pullrefresh',  
  4.                 down: {  
  5.                     callback: pulldownRefresh //下拉刷新具体业务实现  
  6.                 },  
  7.                 up: {  
  8.                     contentrefresh: '正在加载...',  
  9.                     callback: pullupRefresh //上拉加载具体业务实现  
  10.                 }  
  11.             }  
  12.         });  

  

  那么这个mui.init调用的pullRefresh具体代码是如何进行参数传递的呢?

  

Js代码  收藏代码
  1. **  
  2.  * mui.init pulldownRefresh  
  3.  * @param {type} $  
  4.  * @returns {undefined}  
  5.  */  
  6. (function($) {  
  7.     $.registerInit({  
  8.         name: 'pullrefresh',  
  9.         index: 1000,  
  10.         handle: function() {  
  11.             <span style="color: #ff0000;">var options = $.options;</span>  
  12.             var pullRefreshOptions = options.pullRefresh || {};  
  13.             var hasPulldown = pullRefreshOptions.down && pullRefreshOptions.down.hasOwnProperty('callback');  
  14.             var hasPullup = pullRefreshOptions.up && pullRefreshOptions.up.hasOwnProperty('callback');  
  15.             if (hasPulldown || hasPullup) {  
  16.                 var container = pullRefreshOptions.container;  
  17.                 if (container) {  
  18.                     var $container = $(container);  
  19.                     if ($container.length === 1) {  
  20.                           if ($.os.plus && $.os.android) //android 5+ 
  21.                             $.plusReady(function() {  
  22.                                 var webview = plus.webview.currentWebview();  
  23.                                 if (hasPullup) {  
  24.                                     //当前页面初始化pullup  
  25.                                     var upOptions = {};  
  26.                                     upOptions.up = pullRefreshOptions.up; 
  27.                                     upOptions.webviewId = webview.id || webview.getURL();  
  28.                                     $container.pullRefresh(upOptions); 
  29.                                 }  
  30.                                 if (hasPulldown) {  
  31.                                     var parent = webview.parent();  
  32.                                     var id = webview.id || webview.getURL();  
  33.                                     if (parent) {  
  34.                                         if (!hasPullup) { //如果没有上拉加载,需要手动初始化一个默认的pullRefresh,以便当前页面容器可以调用endPulldownToRefresh等方法  
  35.                                             $container.pullRefresh({  
  36.                                                 webviewId: id  
  37.                                             });  
  38.                                         }  
  39.                                         var downOptions = {  
  40.                                             webviewId: id  
  41.                                         };  
  42.                                         downOptions.down = $.extend({}, pullRefreshOptions.down);  
  43.                                         downOptions.down.callback = '_CALLBACK';  
  44.                                         //父页面初始化pulldown  
  45.                                         parent.evalJS("mui&&mui(document.querySelector('.mui-content')).pullRefresh('" + JSON.stringify(downOptions) + "')");  
  46.                                     }  
  47.                                 }  
  48.                             });  
  49.                         } else {  
  50.                              $container.pullRefresh(pullRefreshOptions); 
  51.                         }  
  52.                     }  
  53.                 }  
  54.             }  
  55.         }  
  56.     });  
  57. })(mui);  
  58. /**  

其中$container是从mui.init中的pullRefresh初始化的参数中来的:  

 Js代码  收藏代码

  1. var container = pullRefreshOptions.container;  

 

   就是containers等于id为pullreresh的那个div。

  这段代码的核心是:

 1、 通过调用$container.pullRefresh(pullRefreshOptions);, 将sub.html中配置的container,up,down这些options都传给了PullRefresh对象。

 2、也是通过上述代码,初始化了PullRefresh对象。

 

 总结:

 1、在mui.init中通过调用pullRefresh将container,up,down等参数传入初始化了PullRefresh对象(针对iOS使用H5),或PlusPullRefresh对象(针对Android使用HTML5+)

 2、在mui('#pullrefresh').pullRefresh().pullupLoading();中完成了表格初始化加载。调用了up对应的pullupRefresh方法。

 3、当下拉刷新时,调用down对应的方法pulldownRefresh;当上拉加载时,调用up调用的方法pullupRefresh;

 4、在pullupRefresh和pullupRefresh中利用ajax实现远程数据加载。

 5、在mui.init中初始化pullRefresh时,可以通过参数来设置显示的话术,不写的话默认也有话术,见源代码。

Js代码  收藏代码
  1. up:{contentrefresh:"正在加载...",//可选,正在加载状态时,上拉加载控件上显示的标题内容  
  2.      contentnomore:'没有更多数据了',//可选,请求完毕若没有更多数据时显示的提醒内容;  

 

 

==================================================================================================================

 

	var count = 0;
			/**
			 * 上拉加载具体业务实现
			 */
			function pullupRefresh() {
				setTimeout(function() {
					mui('#pullrefresh').pullRefresh().endPullupToRefresh((++count > 2)); //参数为true代表没有更多数据了。
					var table = document.body.querySelector('.mui-table-view');
					var cells = document.body.querySelectorAll('.mui-table-view-cell');
					for (var i = cells.length, len = i + 20; i < len; i++) {
						var li = document.createElement('li');
						li.className = 'mui-table-view-cell';
						li.innerHTML = '<a class="mui-navigate-right">Item ' + (i + 1) + '</a>';
						table.appendChild(li);
					}
				}, 1500);
			}
 

 

下面分析一下上拉加载的代码,同时它也是表格初始化的代码。

mui('#pullrefresh').pullRefresh().endPullupToRefresh((++count > 2)); //参数为true代表没有更多数据了。

这句代码用于显示没有更多数据这句话,并结束上拉。由于官方案例主要用于模拟,因此它的终止条件是上拉2次,但是初始化表格还算一次,因此count最终等于3而终止上拉。

如果是真实项目,应该是先用Ajax从远程或storage从本地加载数据,应该从Server返回一个属性标识是否后续还有数据。

同时还需要考虑首次加载和上拉加载的参数传递。

假设列表是按照item的id排序(假设id是自增序列),首次加载从max(item_id)返回20条数据,这样上拉加载时就告知server当前列表底部最后一条数据的id,然后server返回比该id更小的20条数据。当下拉刷新时,向服务器请求id大于列表顶端的item。

rest api:上拉加载 1、/list/load  加载最新的20条,select * from list orderby id limit 20

                              2、/list/load?startId={列表底部item的id}   select * from list where id<{列表底部item的id}  limit 20

                              如果返回的结果小于20,那说明已经到底儿了,返回给客户端告知isEnd:ture

               下拉刷新 :/list/load?endId={列表顶部item的id}     select * from list where id>{列表顶部item的id}  orderby id limit 20  

                             如果新的数据大于20,也不可能一次都拉过来,上述sql返回离现在最近的20条,余下的可以采用循环拉取方式,比如发现select回来加了limi限制的数据和select count(*) from list where id>{列表顶部item的id} 相比更少,可以再次发起请求拉取,/list/load?endId={本次下拉刷新操作前列表顶部item的id}  & startId={上次取回的数据最小的id},  select * from list where id>{本次下拉刷新操作前列表顶部item的id} and id<{上次取回的数据最小的id} orderby id limit 2,然后拿回来的数据再次与select count(*) from list where id>{本次下拉刷新操作前列表顶部item的id} and id<{上次取回的数据最小的id}比如果还是小,那么告知客户端继续拉取。

                            另一种方式是将之前的数据清掉,保证可以触发上拉加载事件(不知道MUI是否支持)

                            其实如果量不大,就一次性都拉过来也可以,也就是去掉limit 20的限制。

            返回的结果集json:

           var result={"list":[

             {"item_id":1,"item_content":"Hello cat"}, {"item_id":2,"item_content":"Hello dog"}

          ],"isEnd":true}

            

 

 

 

分享到:
评论
1 楼 qinghechaoge 2016-01-13  
感谢分享,受教了

相关推荐

Global site tag (gtag.js) - Google Analytics