基于Zepto移动端下拉加载(刷新),上拉加载插件开发

写在前面:本人水平有限,有什么分析不到位的还请各路大神指出,谢谢。

这次要写的东西是类似于<今日头条>的效果,下拉加载上啦加载,这次做的效果是简单的模拟,没有多少内容,下面是今日头条的移动端截图:

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

原文地址:https://www.cnblogs.com/wangmaoling/p/6524759.html