JS实现图片懒加载效果


前言

懒加载时一种也页面效果,可以提高页面加载速率,并降低服务器的贷款和资源损耗。


一、图片实现懒加载步骤

  1. 先清空图片的 src 属性值,以使浏览器不加载图片
  2. 然后再在需要加载图片时,为图片添加上 src 属性

二、案例练习(三国女将)

1. html 代码

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>三国女将</title>
    <link rel="stylesheet" href="./css/三国女将.css">
    <script type="text/javascript" src="./js/transformCSS.js"></script>
    <script type="text/javascript" src="./js/tweenAnimation.js"></script>
    <script type="text/javascript" src="./js/touchscroll.js"></script>
</head>
<body>
<div id="app">
    <header>三国女将</header>
    <main id="main">
        <div id="content">
            <ul id="imgList">
            </ul>
            <div class="pull-up-update">上拉加载更多……</div>
        </div>
    </main>
    <div id="big-image-page">
        <header>大图预览
            <span class="close">&times;</span>
        </header>
        <section id="show-area">
            <img id="big-image" src="" alt="">
        </section>
    </div>
</div>
<script type="text/javascript" src="./js/三国女将.js"></script>
</body>
</html>

2. css 代码

/*清除默认样式*/
* {
  padding: 0;
  margin: 0;
}
ul {
  list-style: noen;
}
/*全局样式控制*/
html,
body {
  width: 100%;
  height: 100%;
}
#app {
  width: 100%;
  height: 100%;
  overflow: hidden;
}
/*设置样式*/
/*头部*/
header {
  position: relative;
  z-index: 10;
  height: 10vh;
  background-color: #000000;
  color: white;
  font-family: 苹方;
  font-size: 20px;
  text-align: center;
  line-height: 10vh;
}
header .close {
  background-color: #00CC00;
  position: absolute;
  right: 10px;
  top: 25px;
  display: block;
  width: 20px;
  height: 20px;
  line-height: 20px;
  text-align: center;
  font-size: 28px;
}
/*主体*/
main {
  height: 90vh;
}
main #content {
  position: relative;
}
main #content ul {
  overflow: hidden;
}
main #content ul li {
  float: left;
  width: 46vw;
  height: 46vw;
  margin: 2vw;
  border-radius: 4vw;
  overflow: hidden;
  background-image: url("../img/loadingImg.gif");
  background-repeat: no-repeat;
  background-position: center center;
}
main #content ul li img {
  width: 100%;
  height: 100%;
}
main #content .pull-up-update {
  position: absolute;
  width: 100%;
  height: 20vh;
  bottom: -20vh;
  font-size: 24px;
  line-height: 20vh;
  text-align: center;
  background-color: #acd3e3;
}
#big-image-page {
  transform: scale(0);
  z-index: 10;
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background-color: white;
}
#big-image-page #show-area {
  position: relative;
  width: 100%;
  height: 90vh;
}
#big-image-page #show-area img {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
  margin: auto;
}
/*# sourceMappingURL=三国女将.css.map */

3. js 代码

  1. 三国女将
(function(){
    /*阻止浏览器默认行为 , 如果通过 documentElement 阻止默认行为需要关闭被动模式*/
    var app = document.getElementById("app");
    app.addEventListener("touchstart",function(e){
        e.preventDefault();
    });

    //获取元素
    var main = document.getElementById("main");
    var content = main.querySelector("#content");
    var imgList = content.querySelector("#imgList");
    var pullUpUpdate = content.querySelector(".pull-up-update");
    var bigImagePage =document.getElementById("big-image-page");
    var close = bigImagePage.querySelector("header .close");
    var bigImage = bigImagePage.querySelector("#show-area #big-image");
    //每次 / 每页呈现的图片数量
    var num = 16;
    //当前显示的页码
    var page =1;
    //滑动状态标识
    var isMoving = false;

    /*
    * 初始化图片数据仓库
    *      100 张图片
    * */
    var imgData = ["./img/1.jpg"];
    for(var i=0;i<100;i++){
        // imgData[i]='https://picsum.photos/id/'+i+'/400/300';
        imgData[i]="./img/"+(i%18+1)+".jpg";
    }
    //声明函数创建 li 标签 , 根据页码呈现图片
    function creatLi(){
        /*
        * 第 1 页     0   16
        *    2       16  32
        *    3       32  48
        *    N    (N-1)*16  N*16
        * */
        var start = (page-1)*num;
        var end = page * num;
        for(var i=start;i<end;i++){
            var li = document.createElement("li");
            //为 li 添加自定义属性 data-src , 用于保存当前 li 里的 img 的图片路径
            li.dataset.src = imgData[i];
            /*//为 li 添加自定义属性 data-isloaded , 标识当前 li 为未加载状态
            li.dataset.isloaded = 0;*/
            //为 li 添加自定义属性 loaded ,用于标识当前 li 为未加载状态
            li.setAttribute("loaded",0);
            var img = document.createElement("img");
            li.appendChild(img);
            imgList.appendChild(li);
        }
        //页码自增
        page++;
        //图片懒加载
        lazyload();
    }
    creatLi();

    /*主体滚动*/
    var touchscroll = new Touchscroll('main','#content',{
        width:4,
        //移动时的回调函数
        move:function(){
            /*
            * 问题: 惯性移动时不加载图片
            * 解决: 在 tweenAnimation 的定时器中增加回调函数参数用来加载图片
            * */
            //惯性移动时也加载图片
            lazyload();
            /*
            * 上拉时底部元素缩放
            * 超出临界点时 , 缩放比例 = (content当前的 translateY 值 - content 的最小 translateY 值) / 底部元素的高度
            * */
            //获取当前的 translateY
            var translateY = transformCSS(content,'translateY');
            //计算最小的 translateY
            var minTranslateY = main.offsetHeight - content.offsetHeight;
            //判断是否到达临界点
            if(translateY < minTranslateY){
                //计算底部元素的缩放比例
                pullUpUpdate.scale = Math.min(Math.abs(translateY-minTranslateY)/pullUpUpdate.offsetHeight,1);
                //已经滑出边界 , 设置底部元素的显示比例
                transformCSS(pullUpUpdate,'scale',pullUpUpdate.scale);
            }
        },
        //结束时的回调函数
        end:function(){
            /*
            * 上拉加载更多图片
            *       底部元素全部出来时松手加载更多图片
            * */
            //判断底部元素是否显示完全
            if(pullUpUpdate.scale >= 1){
                creatLi();
                //更新滚动条高度
                touchscroll.init();
                //获取滚动条
                var scrollBar = document.querySelector(".scroll-bar");
                //关闭定时器
                if(scrollBar.timer && scrollBar.timer['translateY']){
                    clearInterval(scrollBar.timer['translateY']);
                }
                if(content.timer && content.timer['translateY']){
                    clearInterval(content.timer['translateY']);
                }
                //修改滚动条位置
                var scrollBarTranslateY = -main.offsetHeight * transformCSS(content,'translateY') / content.offsetHeight;
                transformCSS(scrollBar,'translateY',scrollBarTranslateY);
                /*
                * 滚动条位置问题 滑动状态问题
                * 原因: 在 touchscroll.js 中 , 修改滚动条位置调用了 tweenAnimation.js 中的定时器
                *       在定时器中会执行 move 回调函数
                *       由于定时器的延时 , 在 end 回调函数执行完毕 , 但定时器的回调函数还在执行
                *       导致定时器将滚动条位置改回错误的 traslateY , 也会将滑动状态标识 改回 true
                * 滚动条问题解决: 先关闭定时器再修改滚动条位置 , 为保持内容与滚动条位置一致 , 也需要关闭内容的定时器
                * 滑动状态问题解决: 单独为 main 绑定事件
                * */
            }
            //重设底部元素的缩放比例为 0
            pullUpUpdate.scale = 0;
        }
    });

    /*
    * 绑定touchmove 事件 , 检测图片是否进入可视区
    * 进入可视区后判断图片是否已经加载
    * 如果图片未加载 , 则加载图片
    * */
    main.addEventListener("touchmove",function(){
        //屏幕滑动时加载图片
        lazyload();
        //修改滑动状态标识为 true
        isMoving = true;
    });
    main.addEventListener("touchend",function(){
        //修改滑动状态标识为 false
        isMoving = false;
    })

    /*
    * 大图显示
    * 问题: 新增元素没有事件
    * 解决: 事件委托 或重新为新创建元素绑定事件
    * */
    /*//获取所有 li
    var lis = document.querySelectorAll("#imgList li");
    lis.forEach(function(li){
        li.addEventListener("touchend",function(e){
            //判断滑动状态 , 如果当前正在滑动 , 直接 return 返回
            if(isMoving) return;
            //设置大图的 src
            bigImage.src = this.dataset.src;
            //修改大图页面的 scale 为 1
            transformCSS(bigImagePage,'scale',1);
            //为大图页面添加过渡
            bigImagePage.style.transition = 'transform 0.5s';
            //获取触点位置
            var x = e.changedTouches[0].clientX;
            var y = e.changedTouches[0].clientY;
            //设置过渡的起始位置 transform-origin
            bigImagePage.style.transformOrigin = x+'px '+y+'px';
        });
    });*/
    //绑定事件委托
    imgList.addEventListener("touchend",function(e){
        //判断事件源 nodeName === 'IMG'
        if(e.target.nodeName === 'IMG'){
            //执行事件响应函数
            //判断滑动状态 , 如果当前正在滑动 , 直接 return 返回
            if(isMoving) return;
            //设置大图的 src
            bigImage.src = e.target.src;
            //修改大图页面的 scale 为 1
            transformCSS(bigImagePage,'scale',1);
            //为大图页面添加过渡
            bigImagePage.style.transition = 'transform 0.5s';
            //获取触点位置
            var x = e.changedTouches[0].clientX;
            var y = e.changedTouches[0].clientY;
            //设置过渡的起始位置 transform-origin
            bigImagePage.style.transformOrigin = x+'px '+y+'px';
        }
    });
    close.addEventListener("touchstart",function(e){
       //修改大图页面的 scale 为 0
        transformCSS(bigImagePage,'scale',0);
    });


    //创建函数实现图片懒加载功能
    function lazyload(){
        //获取所有 li
        var lis = document.querySelectorAll("#imgList li");
        lis.forEach(function(li){
            /*
            * 图片懒加载
            *       检测图片位置 , 滚动高度 + 视口高度 == 图片相对于父元素的 offsetTop 时 , 说明已经到达临界状态
            * */
            //获取当前 li 到定位父元素的偏移量
            var oT = li.offsetTop;
            //main 的高度
            var h = main.offsetHeight;
            //content 的滚动高度
            var translateY = -transformCSS(content,'translateY');
            //判断 li 是否进入可视区
            if(oT <= h+translateY){
                //判断当前 li 是否已经加载 , 如果已经加载就直接 return 返回
                /*if(li.dataset.isloaded == 1) return;*/
                if(li.getAttribute("loaded") == 1) return;
                //说明 li 已经进入可视区 , 此时才加载图片
                //获取当前 li 里面的 img
                var img = li.querySelector("img");
                /*浮入效果*/
                img.style.opacity = 0;
                img.style.transition = "opacity 0.8s";
                //延时加载图片
                setTimeout(function(){
                    //设置 img 的 src 属性 , 等于当前 li 的 data-src 属性值
                    img.src = li.dataset.src;
                    //图片加载完毕后修改透明度
                    img.onload = function(){
                        this.style.opacity = 1;
                    };
                    //图片加载失败 , 图片数据仓库中没有该图片
                    img.onerror = function(){
                        this.style.opacity = 1;
                        console.error("图片数据仓库中没有该图片!");
                        this.src = './img/noimage.png';
                    }
                },1000);

                //修改加载状态为已加载
                /*li.dataset.isloaded = 1;*/
                li.setAttribute("loaded",1);
            }
        });
    }
})();
  1. transformCSS
//将 transformCSS 封装为全局函数
(function(w){
    function transformCSS(ele,prop,val){
        /*
        * 设置: transformCSS(ele,'translateX',100)
        * 读取: transformCSS(ele,'translateX') 只能读取通过本方法设置的 transform 样式
        * 参数: ele 元素对象
        *       prop 变形样式 字符串
        *       val 样式值
        * */
        //判断当前对象是否已有样式仓库
        if(ele.store === undefined){
            //没有样式仓库 , 创建初始化样式仓库对象,用于保存样式
            ele.store={};
        }
        //设置样式 , arguments 中封装了实参
        if(arguments.length == 3){
            //将参数保存到样式仓库中
            ele.store[prop] = val;
            //创建局部变量用于表示 transform 样式值
            var str = '';
            //遍历仓库对象的属性
            for(var i in ele.store){
                //根据属性保存样式值
                switch (i) {
                    //平移
                    case 'translateX':
                    case 'translateY':
                    case 'translateZ':
                       str += i + '(' + ele.store[i] + 'px) ';
                        break;
                    //旋转
                    case 'rotate':
                    case 'rotateX':
                    case 'rotateY':
                    case 'rotateZ':
                        str += i + '(' + ele.store[i] + 'deg) ';
                        break;
                    //缩放
                    case 'scale':
                    case 'scaleX':
                    case 'scaleY':
                    case 'scaleZ':
                        str += i + '(' + ele.store[i] + ') ';
                        break;
                }
            }
            //为元素设置样式
            ele.style.transform = str;
        }
        //读取样式
        if(arguments.length == 2){
            //判断当前对象的样式仓库中是否含有该样式
            if(ele.store[prop]){
                //含有该样式 , 则返回样式仓库中的样式
                //注意: 只能读取通过本方法设置的 transform 样式
                return ele.store[prop];
            }
            //当前样式仓库中没有该样式 , 返回默认值
            /*
            * 根据样式名返回不同值:
            *       translate / rotate    0
            *       scale                 1
            * */
            //判断是否以 scale 开头
            var start = prop.substr(0,5);
            if(start === 'scale'){
                //是 scale
                return 1;
            }else{
                //是 rotate 或translate
                return 0;
            }
        }
    }
    w.transformCSS=transformCSS;
})(window);
//匿名函数自调用 , 用以暴露闭包中的局部变量
  1. tweenAnimation
/*
* 功能: 实现元素动画过渡 backEaseout easeOut Linear
* 函数名: tweenAnimation
* 参数: ele   元素对象
*      style    样式 字符串
*      init     起始状态
*      end      结束状态
*      time     过渡时间
*      jiange       动画间隔时间
*      type     动画类型 字符串
*      callback     回调函数 , 在定时器中执行
* 使用示例: tweenAnimation(ele,'width',200,1000,5000,10,'backEaseOut')
*
*       function backEaseOut(t,b,c,d,s){
            if (s == undefined) s = 1.70158;
            return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
        }
*       function easeOut(t,b,c,d){
            return -c * ((t=t/d-1)*t*t*t - 1) + b;
        }
*       function Linear(t,b,c,d){ return c*t/d + b; }
*
* 如: 2s 内元素的 top 值从 200 过渡到 9000 , 每次动画时间间隔为 10 , easeOut
*       tweenAnimation(ele,'top',200,9000,2000,10,'easeOut')
* 依赖: transformCSS.js
* */
function tweenAnimation(ele,style,init,end,time,jiange,type,callback){
    //定义 tween 对象 , 保存计算过渡的函数
    var tween = {
        backEaseOut: function (t,b,c,d,s){
            if (s == undefined) s = 1.70158;
            return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
        },
        easeOut: function (t,b,c,d){
            return -c * ((t=t/d-1)*t*t*t - 1) + b;
        },
        Linear: function (t,b,c,d){
            return c*t/d + b;
        }
    }

    //type 参数初始化 , 默认为 Linear
    var type = type === undefined ? 'Linear' : type;

    // tween 函数参数初始化 t b c d
    var t = 0;  //开始时间
    var b = init;   //起始样式
    var c = end-init;    //样式变化量
    var d = time;   //动画过渡总时间

    /*
    * 定时器冲突问题:
    *       setIntervar() 函数的返回结果是一个作为当前定时器标识的数字
    *       当多次调用定时器时 , 会覆盖之前创建的定时器的标识
    *       导致前面的定时器无法被清除
    * 解决: 将所有定时器标识保存到对象的定时器样式样式仓库中 , 通过样式名来标识当前定时器
    * */
    //为对象添加 timer 属性 , 是一个对象 , 表示定时器样式仓库 , 用于保存元素的所有定时器标识
    if(ele.timer === undefined){
        //如果当前元素没有定时器样式仓库 , 则添加样式仓库属性 timer 并初始化
        ele.timer = {};
    }
    //设置定时器 , 通过样式标识对应定时器
    ele.timer[style] = setInterval(function(){
        //4. 当时间 t 达到结束时间 time 时,关闭定时器
        /*
        * 注意:  第四步应该写到最前面
        *       应该在 t 自增之前判断是否已经到达结束时间 , 然后根据判断结果决定是否执行后面的代码
        * */
        if(t >= d){
            clearInterval(ele.timer[style]);
            return;
        }
        //1. 时间自增
        t += jiange;
        //2. 每一个间隔时间后 , 调用 tween 对象中的 [type]方法 , 计算出时间 t 时的新的样式值
        var v = tween[type](t,b,c,d);
        //3. 为元素对象设置新的样式
        switch (style){
            //判断样式并设置
            case 'width':
            case 'height':
            case 'left':
            case 'top':
                ele.style[style] = v +'px';
                break;
            case 'translateX':
            case 'translateY':
            case 'translateZ':
            case 'scale':
            case 'scaleX':
            case 'scaleY':
            case 'scaleZ':
            case 'rotate':
            case 'rotateX':
            case 'rotateY':
                transformCSS(ele,style,v);
                break;
            case 'opcity':
                ele.style[style] = v;
        }
        //执行回调函数
        if(callback && typeof callback === 'function'){
            callback();
        }
    },jiange);
}
  1. touchscroll
/*
* 构造函数: Touchscroll
* 功能: 实现竖向触摸滑动
* 参数:  container       //包裹元素 选择器字符串
*       content         //滚动元素 选择器字符串
*       options{
*           backgroundColor          //滚动条的背景颜色 , 默认为 rgba(0,0,0,0.6)
*           width                    //滚动条的宽度 , 默认为 6px
*           move                     //函数 , 在滑动时执行
*       }
* 使用示例: new Touchscroll("#container",".wrapper",{
*               width: 4,
*               backgroundColor: 'rgb(228,228,228)'
*          });
*   <div id="container">
*        <div class="wrapper"></div>
*   </div>
* 缺点: 需要手动设置包裹元素的 position: relative  height  overflow: hidden
* 依赖: transformCSS.js
*       tweenAnimation.js
*
* */
function Touchscroll(container,content,options){
    //获取元素
    var app = document.querySelector(container);
    var main = app.querySelector(content);

    //move 时的回调函数
    var moveCallback = options && options.move ? options.move : null;


    /*创建滚动条*/
    var scrollBar = document.createElement("div");
    //将滚动条添加到容器中
    app.appendChild(scrollBar);
    /*
    * 滚动条初始化
    *       为滚动条添加 scroll-bar 类
    *       设置滚动条样式
    *           .scroll-bar{
                    position: absolute;
                    right: 0;
                    top: 0;
                    width: 6px;
                    border-radius: 3px;
                    background-color: rgba(0,0,0,0.6);
                }
    *       将滚动条添加到 包裹元素 中
    * */
    this.init = function(){
        //添加 scroll-bar 类
        scrollBar.className = "scroll-bar";
        //设置滚动条样式
        //定位
        scrollBar.style.position = "absolute";
        scrollBar.style.right = 0;
        scrollBar.style.top = 0;
        //宽度
        var scrollBarWidth = options && options.width ? options.width : 6;
        scrollBar.style.width = scrollBarWidth +'px';
        //圆角
        scrollBar.style.borderRadius = "3px";
        //背景颜色
        var bg = options && options.backgroundColor ? options.backgroundColor : "rgba(0,0,0,0.6)";
        scrollBar.style.backgroundColor = bg;
        //设置滚动条的高度
        //计算滚动条应该设置的高度 滚动条的高度 / app高度 = app高度 / content高度
        var h = (app.offsetHeight * app.offsetHeight) / main.offsetHeight;
        scrollBar.style.height = h +'px';
        //给外层包裹元素增加 相对定位
        app.style.position = 'relative';

    };
    this.init();
    app.init = this.init;
    //文档加载完毕 , 初始化滚动条
    window.addEventListener('load', function(){
        app.init();
    });


    app.addEventListener("touchstart",function(e){
        //获取触摸开始时的时间
        this.touchstartTime = Date.now();
        //获取开始时的触点位置
        this.touchY = e.changedTouches[0].clientY;
        //获取触摸开始时 content 的 translateY 的值
        this.contentT = transformCSS(main,'translateY');
        //即点即停
        if(main.timer && main.timer['translateY']){
            clearInterval(main.timer['translateY']);
        }
        //导航条即点即停
        if(scrollBar.timer && scrollBar.timer['translateY']){
            clearInterval(scrollBar.timer['translateY']);
        }
    });
    app.addEventListener("touchmove",function(e){
        //取消过渡效果
        main.style.transition = "none";
        //获取移动时的触点位置
        this.touchY2 = e.changedTouches[0].clientY;
        //计算 content 应该设置的 translateY 的值
        var t = this.contentT + (this.touchY2 - this.touchY);
        /*橡皮筋效果*/
        //定义缩减系数
        var K = 0.5;
        //边界控制
        if(t >= 0 || t <= app.offsetHeight - main.offsetHeight){
            t = this.contentT + (this.touchY2 - this.touchY) * K;
        }
        //设置 content 的 translateY 的值
        transformCSS(main,'translateY',t);
        /*
        * 滚动条移动
        *       滚动条移动距离 / app 的高度 = content移动距离 / content的高度
        *       注意应该要对 content 移动距离取反
        * */
        //计算 scrollBar 应该移动的距离
        var y = -app.offsetHeight * t / main.offsetHeight;
        //设置 scrollBar 的 translateY 的值
        transformCSS(scrollBar,'translateY',y);
        //执行 move 回调函数
        if(options && typeof options.move === 'function'){
            options.move();
        }
    });
    app.addEventListener("touchend",function(e){
        //获取触摸结束时的时间
        this.touchendTime = Date.now();
        //获取结束时的触点位置
        this.touchY3 = e.changedTouches[0].clientY;
        //计算 content 没有惯性移动时应该设置的 translateY 的值
        var t = this.contentT + (this.touchY3 - this.touchY);

        /*惯性滑动*/
        //定义时间系数
        var T = 100;
        //获取滑动速度
        var v = (this.touchY3 - this.touchY)/(this.touchendTime - this.touchstartTime);
        //计算惯性移动的距离
        var s = v * T;
        //新的 translateY 值
        t += s;
        /*导航条跟随惯性移动*/
        //计算加上惯性移动滚动条移动的距离
        var y = -app.offsetHeight * t / main.offsetHeight;

        /*回弹效果*/
        // 声明变量 , 用于保存变形效果 , 默认为 easeOut
        var type = 'easeOut';
        if(t >= 0){
            t = 0;
            type = 'backEaseOut';
        }else if(t <= app.offsetHeight - main.offsetHeight){
            t = app.offsetHeight - main.offsetHeight;
            type = 'backEaseOut';
        }
        /*导航条跟随回弹*/
        if(y <= 0){
            y = 0;
            type = 'backEaseOut';
        }else if(y >= app.offsetHeight - scrollBar.offsetHeight ){
            y = app.offsetHeight - scrollBar.offsetHeight;
            type = 'backEaseOut';
        }

        /*
        * 即点即停效果
        *       直接使用 transition 的缺点: 无法即点即停,惯性移动时,触摸元素并滑动会取消过渡效果导致元素直接跳到最终位置
        *       可以使用 tweenAnimation() 函数执行过渡 , 然后在 touchstart 事件中清除定时器以实现即点即停效果
        * 注意:
        *       一定要及时清除定时器 , 不然每触发一次 touchend 事件就会开启一个定时器
        * */
        //获取 content 当前的 translateY 值
        var currentContentY = transformCSS(main,'translateY');
        //移动 content
        tweenAnimation(main,'translateY',currentContentY,t,500,10,type,moveCallback);
        //获取 scrollBar 当前的 translateY 值
        var currentScrollY = transformCSS(scrollBar,'translateY');
        //移动 scrollBar
        tweenAnimation(scrollBar,'translateY',currentScrollY,y,500,10,type);

        //执行 end 回调函数
        if(options && typeof options.end === 'function'){
            options.end();
        }

    });

}

执行结果

三国女将练习

大图预览

(完)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值