写在前面:本人水平有限,有什么分析不到位的还请各路大神指出,谢谢。
这次要写的东西是类似于<今日头条>的效果,下拉加载上啦加载,这次做的效果是简单的模拟,没有多少内容,下面是今日头条的移动端截图:
1. 先说一个题外话,拿到这个效果后,先分析了下,由于新闻分类很多,每个类目下都得有很多新闻,并且加载的时候得用ajax,所以得分清在哪个栏目下触发的加载,然后挑出相应的接口数据,插入到那个页面。
先分析一下:这个效果类似选项卡,但是简单的选项卡是把选项卡子内容全部写在文档内部(页面加载的时候会把所有的资源都加在进来),通过display:none/block;来控制显示,通过js处理可以达到下拉上拉加载的效果。但是这个新闻类页面图片资源比较多,在移动端加载大量资源会费时,费流量(不止自己的流量,服务器也需要流量),所以我们把这个项目下面的内容拆分为每个单页面。今日头条项目中每个类型在切换的时候都会先清空之前的内容,在重新插入,这个拆分单页面在类型切换,页面刷新时无疑会造成数据丢失,他们(每日头条开发者)的做法是吧数据写在了缓存里面(最下面有图,朋友们也可以自己去打开看看)。
开始写插件,插件结构如下:
; (function($,window,document,undefined){//传值,多传的忽略 'use strict'//使用严格模式 //定义插件名称 var plugingName='slideDownRefresh', defaults={ //默认 配置项 如果使用者不写自己加上 'width':'300px' } // 属性: function Plugin(element,options){ //element 为节点,options是执行的快慢,宽高呀配置项 //console.log(element);//测试是否正确 this.element = element; // this.options = options;//得检测下看看 使用者是否佳丽参数 this.options = $.extend({},defaults,options);//如果options没有就用defaults,如果options有就把defaults的给替换 // console.log(this.options); } //方法: Plugin.prototype={ init:function(){ }, eventHandle:function(){ } } // 把插件绑定到Zepto上: $.fn[plugingName]=function(options){ return this.each(function(){//遍历匹配的元素,此处的this表示为jquery对象,而不是dom对象 // 因为 应该有多个地方用到这个插件 //zepto 的data与jquery的data有区别日后再说 if( !$(this).data('plugin_' + plugingName)) { return $(this).data('plugin_'+plugingName,new Plugin(this,options)) } }) } })(Zepto,window,document);
接下来补充插件的事件等:
; (function($,window,document,undefined){//传值,多传的忽略 'use strict'//使用严格模式 //定义插件名称 var plugingName = 'slideDownRefresh', defaults = { //默认 配置项 如果使用者不写自己加上 'width':'300px' } // 属性: function Plugin(element,options){ //element 为节点,options是执行的快慢,宽高呀配置项 //console.log(element);//测试是否正确 this.element = element; // this.options = options;//得检测下看看 使用者是否佳丽参数 this.options = $.extend({},defaults,options);//如果options没有就用defaults,如果options有就把defaults的给替换 // console.log(this.options); // 执行以下,初始化调用一下 this.init(); this.eventHandle(); } //方法: Plugin.prototype = { init: function(){ this.$refresh = $(this.element).find('.refresh');//找到标签 this.$rotate = $(this.element).find('img');//找到旋转标签 this._start = 0;//旋转的初始值 this._end = 0;//旋转的结束值 }, // 事件主要为移动端touch事件,下面会写到,不懂得可以取查阅资料 eventHandle: function(){ this.touchStart(this.element); }, touchStart: function(ele){ var _self=this;//把this存起来,不用来回反复取(节约性能); $(ele).on('touchstart', function(e){ var touch = e.targetTouches[0];//只允许一个手指触碰 _self._start = touch.pageY;//获取点上去时的纵坐标 _self.touchMove(_self.element);//调用移动方法 }) }, touchMove: function(ele){ var _self=this;//把this存起来,不用来回反复取(节约性能); $(ele).on('touchmove', function(e){ var touch = e.targetTouches[0];//只允许一个手指触碰 _self._end = _self._start - touch.pageY;//获取移动的纵坐标距离 _sliding.call(_self,_self._end); //这里之所以不用_sliding.()调用是因为,这样传的this为touchmove的this,而我们要的this为:_self _self.touchEnd(_self.element); }); // 写个私有方法 function _sliding(dist){ // dist为距离 _self.$refresh.css('transform', 'translate3d(0,'+ -dist + 'px, 0)');//拿到结点 写动画 _self.$rotate.css('transform','rotate('+ (-dist * 4) + 'deg)');//让load转起来这里的4只是随便写的,可以任意写,怎么好看怎么写 } }, touchEnd: function(ele){ var _self=this;//把this存起来,不用来回反复取(节约性能); $(ele).on('touchend', function(e){ if(_self._end < -160){ // 这个数字可以随便设置 成功时 _slided.call(_self); setTimeout(function(){ _reset.call(_self); },3000); }else{ //距离不够 _noslide.call(_self); } // 事件全部执行完以后,把事件全部移除 $(this).unbind('touchmove'); $(this).unbind('touchend'); }); function _slided(){// 下拉,然后松开,然后执行 _self.$refresh.addClass('refreshing'); _self.$rotate.addClass('index'); }; // 下滑距离不够时,复原 但是不算新 function _noslide(){ _self.$refresh.addClass('refreshing'); _self.$rotate.addClass('index'); _self.$refresh.css('transform', 'translate3d(0,0,0)'); _self.$rotate.css('transform', 'rotate(0deg)'); // 移除加的class setTimeout(function(){ _self.$refresh.removeClass('refreshing'); _self.$rotate.removeClass('index'); },500); }; // 刷新完成,回到原来状态 function _reset(){ _self.$refresh.css('transform', 'translate3d(0,0,0)'); _self.$rotate.css('transform', 'rotate(0deg)'); setTimeout(function(){ _self.$refresh.removeClass('refreshing'); _self.$rotate.removeClass('index'); // window.location.reload(); //刷新页面,或者执行ajax 调取数据 // 调用数据 $.ajax({ url:, data:url, success:function(data){ var list=defaults.redenr(data); $("...").append(list); } }) },500); } } } // 把插件绑定到Zepto上: $.fn[plugingName] = function(options){ return this.each(function(){//遍历匹配的元素,此处的this表示为jquery对象,而不是dom对象 // 因为 应该有多个地方用到这个插件 //zepto 的data与jquery的data有区别日后再说 if( !$(this).data('plugin_' + plugingName)){ return $(this).data('plugin_' + plugingName, new Plugin(this,options)) } }) } })(Zepto,window,document);
调用代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>基于Zepto移动端下拉刷新(加载),上拉加载插件开发</title> <meta name="viewport" content="width=device-width, initial-scale=1.0,minimum-scale=1.0, maximum-scale=1.0,user-scalable=no"> <style> *{ padding:0; margin:0; } a{ text-decoration: none; } li{ list-style: none; } header{ 100%; height: 40px; line-height: 40px; position: fixed; top:0; left: 0; background: #fff; z-index: 100; } header li{ display: inline-block; 24%; } header li a{ text-align: center; 100%; display: block; color:#000; height: 40px; } .refresh{ 100%; position: absolute; text-align: center; } .refresh img{ 40px; } .warp{ 100%; clear: both; } .refreshing{ transition: all .5s ease-in-out; -webkit-transition: all .5s ease-in-out; } .refresh img.index{ -webkit-animation:today 3s infinite; animation:today 3s infinite; } @keyframes today{ 0%{ transform:rotate(0deg); } 100%{ transform:rotate(-2000deg); } } @-webkit-keyframes today{ 0%{ -webkit-transform:rotate(0deg); } 100%{ -webkit-transform:rotate(-2000deg); } } </style> </head> <body> <div class="warp"> <header> <ul> <li><a href="#tuijian" class="tuijian">推荐</a></li> <li><a href="#junshi" class="junshi">军事</a></li> <li><a href="#jingji" class="jingji">经济</a></li> <li><a href="#shehui" class="shehui">社会</a></li> </ul> </header> <div class="refresh"> <img src="img/re.png" alt=""> </div> <section id="content"> <li>测试内容</li> <li>测试内容</li> </section> </div> </body> <script src="http://apps.bdimg.com/libs/zepto/1.1.4/zepto.js"> </script> <script src="js/myDemo.js"></script> <script> $('.warp').slideDownRefresh({ 'width':'800px', 'url':,//这个url 为要添加新数据的url redenr:function(data){ //在这里拼接页面 var list=null; return list; } }); </script> </html>
总结:这个插件只是写了下拉,上啦加载的可以在 touchEnd 函数中判断是上滑还是下滑来判断加载。 本插件在单页中没什么问题,要是放在 今日头条这样的项目中就得补充插件内容了。
分析今日头条:今日头条的每个新闻项目的切换 相应的url也会变化,项目来回切换的时候 各种新闻数据还是不变的,即便F5刷新 各个新闻数据还是不变的。于是我找了下缓存还有发现了新闻的缓存。
所以本插件还得添加一个功能:把拿来的数据添加到缓存中。 类似的还有《微信热文》也是这个原理实现的。
欢迎大家指出问题,项目下载地址https://github.com/WangMaoling/refresh