TWEEN动画、JQUERY、ES6 — 1、定时器和TWEEN动画

1、定时器的基础知识(设置、清除、返回值分析)

JS中的定时器一共有两种:

1、window.setTimeout([function],[interval]):设置一个定时器,当到达指定时间后执行对应的方法(执行一次定时器就结束了)

2、window.setInterval([function],[interval]):设置一个定时器,当到达指定时间后执行对应的方法(以后每间隔这么长时间都要从新的执行定时器中的方法,直到定时器清除为止,执行很多次)

var count = 0;
setTimeout(function () {
    console.log(++count);//=>1
}, 1000);//=>1000MS=1S

var count = 0;
setInterval(function () {
    console.log(++count);
}, 1000);
复制代码

定时器的返回值:当我们设置定时器(不管是setTimeout还是setInterval),都会有一个返回值,返回值是一个数字,代表当前是在浏览器中设置的第几个定时器(返回的是定时器序号)

1、setTimeout和setInterval虽然是处理不同需求的定时器,但是都是浏览器的定时器,所以设置的时候,返回的序号是依次排列的

2、setInterval设置完成定时器会有一个返回值,不管执行多少次,这个代表序号的返回值不变(设置定时器就有返回值,执行多少次是定时器的处理)

var timer1 = setTimeout(function () {

}, 1000);
console.log(timer1);//=>1

var timer2 = setInterval(function () {

}, 1000);
console.log(timer2);//=>2
复制代码

定时器的清除

clearTimeout([定时器的排队序号])

clearInterval([定时器的排队序号])

定时器需要手动清除

var t1 = setTimeout(function () {

    //=>当方法执行完成后,定时器没用了,我们清除定时器即可
    // clearTimeout(t1);//=>t1存储的就是当前定时器的编号
    // clearInterval(t1);//=>使用它也可以清除掉

    clearTimeout(t1);//=>在浏览器内部把定时器清除掉了(相当于银行业务员在系统中清除我们的排队号)
    t1 = null;//=>我们手动把之前存储序号的变量赋值为null(相当于我们把排队号那个纸条撕毁扔掉)
}, 1000);
复制代码

2、实现简单渐现的动画(融合到图片懒加载案例中)

css/index.less

@import "reset";

.newsBox {
  margin: 0 10px;

  li {
    border-bottom: 1px solid #E4E4E4;
    &:nth-last-child(1) {
      border-bottom: none;
    }

    a {
      position: relative;
      display: block;
      padding: 10px 0;

      .imgBox {
        position: absolute;
        left: 0;
        top: 10px;
        width: 84px;
        height: 56px;
        background: url("../img/default.gif") no-repeat center center #EEE;
        background-size: 25px;

        img {
          display: none;
          opacity: 0;
          filter: alpha(opacity=0);

          width: 100%;
          height: 100%;
        }
      }

      .con {
        margin-left: 94px;

        p {
          height: 40px;
          line-height: 20px;
          font-size: 14px;
          color: #555;
          overflow: hidden;
        }

        span {
          display: block;
          line-height: 20px;
          font-size: 12px;
          color: #999;
          text-indent: 15px;
          background: url("../img/comment.png") no-repeat left center;
          background-size: 13px 15px;
        }

      }
    }
  }
}
复制代码

css/reset.less

body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, dl, dt, dd, ul, ol, li, button, input, textarea, th, td {
  margin: 0;
  padding: 0
}

body {
  font-size: 12px;
  font-style: normal;
  font-family: "\5FAE\8F6F\96C5\9ED1", Helvetica, sans-serif
}

small {
  font-size: 12px
}

h1 {
  font-size: 18px
}

h2 {
  font-size: 16px
}

h3 {
  font-size: 14px
}

h4, h5, h6 {
  font-size: 100%
}

ul, ol {
  list-style: none
}

a {
  text-decoration: none;
  background-color: transparent
}

a:hover, a:active {
  outline-width: 0;
  text-decoration: none
}

table {
  border-collapse: collapse;
  border-spacing: 0
}

hr {
  border: 0;
  height: 1px
}

img {
  border-style: none
}

img:not([src]) {
  display: none
}

svg:not(:root) {
  overflow: hidden
}

html {
  -webkit-touch-callout: none;
  -webkit-text-size-adjust: 100%
}

input, textarea, button, a {
  -webkit-tap-highlight-color: rgba(0, 0, 0, 0)
}

article, aside, details, figcaption, figure, footer, header, main, menu, nav, section, summary {
  display: block
}

audio, canvas, progress, video {
  display: inline-block
}

audio:not([controls]), video:not([controls]) {
  display: none;
  height: 0
}

progress {
  vertical-align: baseline
}

mark {
  background-color: #ff0;
  color: #000
}

sub, sup {
  position: relative;
  font-size: 75%;
  line-height: 0;
  vertical-align: baseline
}

sub {
  bottom: -0.25em
}

sup {
  top: -0.5em
}

button, input, select, textarea {
  font-size: 100%;
  outline: 0
}

button, input {
  overflow: visible
}

button, select {
  text-transform: none
}

textarea {
  overflow: auto
}

button, html [type="button"], [type="reset"], [type="submit"] {
  -webkit-appearance: button
}

button::-moz-focus-inner, [type="button"]::-moz-focus-inner, [type="reset"]::-moz-focus-inner, [type="submit"]::-moz-focus-inner {
  border-style: none;
  padding: 0
}

button:-moz-focusring, [type="button"]:-moz-focusring, [type="reset"]:-moz-focusring, [type="submit"]:-moz-focusring {
  outline: 1px dotted ButtonText
}

[type="checkbox"], [type="radio"] {
  box-sizing: border-box;
  padding: 0
}

[type="number"]::-webkit-inner-spin-button, [type="number"]::-webkit-outer-spin-button {
  height: auto
}

[type="search"] {
  -webkit-appearance: textfield;
  outline-offset: -2px
}

[type="search"]::-webkit-search-cancel-button, [type="search"]::-webkit-search-decoration {
  -webkit-appearance: none
}

::-webkit-input-placeholder {
  color: inherit;
  opacity: .54
}

::-webkit-file-upload-button {
  -webkit-appearance: button;
  font: inherit
}

.clearfix:after {
  display: block;
  height: 0;
  content: "";
  clear: both
}
复制代码

css/reset.min.css

body,h1,h2,h3,h4,h5,h6,hr,p,blockquote,dl,dt,dd,ul,ol,li,button,input,textarea,th,td{margin:0;padding:0}body{font-size:12px;font-style:normal;font-family:"\5FAE\8F6F\96C5\9ED1",Helvetica,sans-serif}small{font-size:12px}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}h4,h5,h6{font-size:100%}ul,ol{list-style:none}a{text-decoration:none;background-color:transparent}a:hover,a:active{outline-width:0;text-decoration:none}table{border-collapse:collapse;border-spacing:0}hr{border:0;height:1px}img{border-style:none}img:not([src]){display:none}svg:not(:root){overflow:hidden}html{-webkit-touch-callout:none;-webkit-text-size-adjust:100%}input,textarea,button,a{-webkit-tap-highlight-color:rgba(0,0,0,0)}article,aside,details,figcaption,figure,footer,header,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]),video:not([controls]){display:none;height:0}progress{vertical-align:baseline}mark{background-color:#ff0;color:#000}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}button,input,select,textarea{font-size:100%;outline:0}button,input{overflow:visible}button,select{text-transform:none}textarea{overflow:auto}button,html [type="button"],[type="reset"],[type="submit"]{-webkit-appearance:button}button::-moz-focus-inner,[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring,[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring{outline:1px dotted ButtonText}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-cancel-button,[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-input-placeholder{color:inherit;opacity:.54}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}.clearfix:after{display:block;height:0;content:"";clear:both}
复制代码

js/index.js

var newsRender = (function () {
    var _newsData = null,
        _newsBox = document.getElementById('newsBox');

    //=>queryData:使用AJAX获取到需要绑定的数据
    function queryData() {
        var xhr = new XMLHttpRequest();
        xhr.open('get', 'json/news.json', false);
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status === 200) {
                _newsData = utils.toJSON(xhr.responseText);
            }
        };
        xhr.send(null);
    }

    //=>bindHTML:根据获取的数据把HTML绑定在页面中
    function bindHTML() {
        if (!_newsData) return;
        var str = ``;
        for (var i = 0; i < _newsData.length; i++) {
            var item = _newsData[i];
            str += `<li><a href="${item.link}">
                <div class="imgBox">
                    <img src="" data-img="${item.figure}" alt="">
                </div>
                <div class="con">
                    <p class="title">${item.title}</p>
                    <span>${item.comment}</span>
                </div>
            </a></li>`;
        }
        _newsBox.innerHTML = str;
    }

    //=>computed:计算出哪些图片需要延迟加载,我们让其延迟加载
    function computed() {
        var imgList = _newsBox.getElementsByTagName('img');
        for (var i = 0; i < imgList.length; i++) {
            var curImg = imgList[i],
                curBox = curImg.parentNode;
            if (curImg.isLoad) continue;//=>如果当前图片已经处理过了,我们不需要再重复处理,直接进行下一轮的循环,验证下一张图片是否需要加载即可

            //=>获取“图片所在盒子底边框距离BODY的距离 A” 和 “浏览器底边框距离BODY的距离 B”
            var A = utils.offset(curBox)['top'] + curBox.offsetHeight;
            var B = utils.winBox('clientHeight') + utils.winBox('scrollTop');
            if (A <= B) {
                //=>当前这张图片符合延迟加载的条件,我们开始加载
                lazyImg(curImg);
            }
        }
    }

    //=>lazyImg:给某一张图片进行延迟加载
    function lazyImg(curImg) {
        curImg.isLoad = true;//=>避免重复处理(isLoad:是自定义属性)
        var tempImg = new Image;
        tempImg.onload = function () {
            curImg.src = tempImg.src;
            curImg.style.display = 'block';
            imgFade(curImg);
            tempImg = null;
        };
        tempImg.src = curImg.getAttribute('data-img');
    }

    //=>imgFade:让当前图片渐现出来
    function imgFade(curImg) {
        var n = 0;
        var timer = setInterval(function () {
            if (n > 1) {
                clearInterval(timer);
                timer = null;
                return;
            }
            n += 0.05;
            utils.css(curImg, 'opacity', n);
        }, 17);//=>17MS是执行定时器动画相对比较理想的间隔时间
    }

    return {
        init: function () {
            //=>模块的入口:在入口中协调控制先做什么再做什么
            queryData();
            bindHTML();

            setTimeout(computed, 500);//=>当页面中数据都加载完成,过500MS在执行图片的延迟加载操作 <=> window.onload=computed 这个事件就是页面整体都加载完成才会触发
            window.onscroll = computed;//=>当滚动到具体的区域的时候,我们把当前符合条件的图片做延迟加载
        }
    }
})();
newsRender.init();
复制代码

js/less-2.5.3.min.js

......
复制代码

js/utils.js

var utils = (function () {
    //=>toArray:converts the class array to an array
    var toArray = function (classAry) {
        var ary = [];
        try {
            ary = Array.prototype.slice.call(classAry);
        } catch (e) {
            for (var i = 0; i < classAry.length; i++) {
                ary[ary.length] = classAry[i];
            }
        }
        return ary;
    };

    //=>toJSON:converts a JSON formatted string to a JSON object
    var toJSON = function (str) {
        return 'JSON' in window ? JSON.parse(str) : eval('(' + str + ')');
    };

    //=>getCss:gets a value of a style attribute of the current element
    var getCss = function (curEle, attr) {
        var value = null,
            reg = null;
        if (window.getComputedStyle) {
            value = window.getComputedStyle(curEle, null)[attr];
        } else {
            if (attr === 'opacity') {
                value = curEle.currentStyle['filter'];
                reg = /^alpha\(opacity=(.+)\)$/i;
                value = reg.test(value) ? reg.exec(value)[1] / 100 : 1;
            } else {
                value = curEle.currentStyle[attr];
            }
        }
        reg = /^-?\d+(\.\d+)?(px|pt|rem|em)?$/i;
        reg.test(value) ? value = parseFloat(value) : null;
        return value;
    };

    //=>setCss:sets a value for a style property of the current element
    var setCss = function (curEle, attr, value) {
        if (attr === 'opacity') {
            curEle['style']['opacity'] = value;
            curEle['style']['filter'] = 'alpha(opacity=' + value * 100 + ')';
            return;
        }
        !isNaN(value) && !/^(zIndex|zoom|lineHeight|fontWeight)$/i.test(attr) ? value += 'px' : null;
        curEle['style'][attr] = value;
    };

    //=>setGroupCss:setting style attribute values to current elements in batches
    var setGroupCss = function (curEle, options) {
        if (Object.prototype.toString.call(options) !== '[object Object]') return;
        for (var attr in options) {
            if (options.hasOwnProperty(attr)) {
                setCss(curEle, attr, options[attr]);
            }
        }
    };

    //=>css:integrated method of setting styles, obtaining styles and setting styles in batches
    var css = function () {
        var len = arguments.length,
            type = Object.prototype.toString.call(arguments[1]),
            fn = getCss;
        len >= 3 ? fn = setCss : (len === 2 && type === '[object Object]' ? fn = setGroupCss : null);
        return fn.apply(this, arguments);
    };

    //=>offset:gets the offset of the current element distance BODY, including left offset and top offset
    var offset = function (curEle) {
        var l = curEle.offsetLeft,
            t = curEle.offsetTop,
            p = curEle.offsetParent;
        while (p.tagName !== 'BODY') {
            if (!/MSIE 8/i.test(navigator.userAgent)) {
                l += p.clientLeft;
                t += p.clientTop;
            }
            l += p.offsetLeft;
            t += p.offsetTop;
            p = p.offsetParent;
        }
        return {top: t, left: l};
    };

    //=>winBox:the operation has the JS box model property about the browser and handles the compatibility
    var winBox = function (attr, value) {
        if (typeof value !== 'undefined') {
            document.documentElement[attr] = value;
            document.body[attr] = value;
            return;
        }
        return document.documentElement[attr] || document.body[attr];
    };

    return {
        toArray: toArray,
        toJSON: toJSON,
        css: css,
        offset: offset,
        winBox: winBox
    }
})();
复制代码

json/mocData.js

var ary = [
    {
        "id": 1,
        "title": "勤政日历·省委书记|6地书记学习中央统一领导的规定",
        "figure": "img/1.jpg",
        "comment": 100,
        "link": "http://news.sina.cn/mrdx/swsj.d.html?cre=tianyi&mod=wnews&loc=0&r=-1&doct=0&rfunc=67&tj=none&tr=73&vt=4&pos=3"
    },
    {
        "id": 2,
        "title": "章莹颖家人计划明日回国 案件是否延期审判未定",
        "figure": "img/2.jpg",
        "comment": 97,
        "link": "http://news.sina.cn/sh/2017-11-11/detail-ifynshev5246310.d.html?cre=tianyi&mod=wnews&loc=1&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
    },
    {
        "id": 3,
        "title": "上海浦东一家超市发生坍塌多人被埋 致1人遇难",
        "figure": "img/3.jpg",
        "comment": 70,
        "link": "http://news.sina.cn/gn/2017-11-11/detail-ifynshev5276174.d.html?cre=tianyi&mod=wnews&loc=2&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
    },
    {
        "id": 4,
        "title": "山西官方回应幼童校园被袭事件:施暴者已被刑拘",
        "figure": "img/4.jpg",
        "comment": 591,
        "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7262878.d.html?cre=tianyi&mod=wnews&loc=3&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
    },
    {
        "id": 5,
        "title": "中国留学生加拿大失联 警方:或接恐吓电话躲起来",
        "figure": "img/5.jpg",
        "comment": 83,
        "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7271765.d.html?cre=tianyi&mod=wnews&loc=4&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
    },
    {
        "id": 6,
        "title": "复旦版“中国医院排行榜”公布 这些医院排名靠前",
        "figure": "img/6.jpg",
        "comment": 380,
        "link": "http://news.sina.cn/2017-11-11/detail-ifynrsrf3816830.d.html?cre=tianyi&mod=wnews&loc=5&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
    },
    {
        "id": 7,
        "title": "赵薇股神人设崩塌 是演技太好还是我们入戏太深?",
        "figure": "img/7.jpg",
        "comment": 546,
        "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7310451.d.html?cre=tianyi&mod=wnews&loc=6&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
    },
    {
        "id": 8,
        "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
        "figure": "img/8.jpg",
        "comment": 100,
        "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
    },
    {
        "id": 9,
        "title": "法国男子撞伤3名中国留学生 检方按谋杀案调查",
        "figure": "img/9.jpg",
        "comment": 100,
        "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynrsrf3768828.d.html?cre=tianyi&mod=wnews&loc=8&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
    }
];
var data = [];
for (var i = 1; i <= 1000; i++) {
    var ran = Math.round(Math.random() * 8),
        res = ary[ran];
    data.push({
        id: i,
        title: res.title,
        figure: res.figure,
        comment: res.comment,
        link: res.link
    });
}
var fs = require('fs');
fs.writeFileSync('./news.json', JSON.stringify(data), 'utf-8');
复制代码

json/news.json

[
  {
    "id": 1,
    "title": "章莹颖家人计划明日回国 案件是否延期审判未定",
    "figure": "img/2.jpg",
    "comment": 97,
    "link": "http://news.sina.cn/sh/2017-11-11/detail-ifynshev5246310.d.html?cre=tianyi&mod=wnews&loc=1&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 2,
    "title": "复旦版“中国医院排行榜”公布 这些医院排名靠前",
    "figure": "img/6.jpg",
    "comment": 380,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynrsrf3816830.d.html?cre=tianyi&mod=wnews&loc=5&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 3,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 4,
    "title": "复旦版“中国医院排行榜”公布 这些医院排名靠前",
    "figure": "img/6.jpg",
    "comment": 380,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynrsrf3816830.d.html?cre=tianyi&mod=wnews&loc=5&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 5,
    "title": "勤政日历·省委书记|6地书记学习中央统一领导的规定",
    "figure": "img/1.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/mrdx/swsj.d.html?cre=tianyi&mod=wnews&loc=0&r=-1&doct=0&rfunc=67&tj=none&tr=73&vt=4&pos=3"
  },
  {
    "id": 6,
    "title": "山西官方回应幼童校园被袭事件:施暴者已被刑拘",
    "figure": "img/4.jpg",
    "comment": 591,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7262878.d.html?cre=tianyi&mod=wnews&loc=3&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 7,
    "title": "上海浦东一家超市发生坍塌多人被埋 致1人遇难",
    "figure": "img/3.jpg",
    "comment": 70,
    "link": "http://news.sina.cn/gn/2017-11-11/detail-ifynshev5276174.d.html?cre=tianyi&mod=wnews&loc=2&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 8,
    "title": "中国留学生加拿大失联 警方:或接恐吓电话躲起来",
    "figure": "img/5.jpg",
    "comment": 83,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7271765.d.html?cre=tianyi&mod=wnews&loc=4&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 9,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 10,
    "title": "赵薇股神人设崩塌 是演技太好还是我们入戏太深?",
    "figure": "img/7.jpg",
    "comment": 546,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7310451.d.html?cre=tianyi&mod=wnews&loc=6&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 11,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 12,
    "title": "山西官方回应幼童校园被袭事件:施暴者已被刑拘",
    "figure": "img/4.jpg",
    "comment": 591,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7262878.d.html?cre=tianyi&mod=wnews&loc=3&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 13,
    "title": "山西官方回应幼童校园被袭事件:施暴者已被刑拘",
    "figure": "img/4.jpg",
    "comment": 591,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7262878.d.html?cre=tianyi&mod=wnews&loc=3&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 14,
    "title": "赵薇股神人设崩塌 是演技太好还是我们入戏太深?",
    "figure": "img/7.jpg",
    "comment": 546,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7310451.d.html?cre=tianyi&mod=wnews&loc=6&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 15,
    "title": "法国男子撞伤3名中国留学生 检方按谋杀案调查",
    "figure": "img/9.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynrsrf3768828.d.html?cre=tianyi&mod=wnews&loc=8&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 16,
    "title": "复旦版“中国医院排行榜”公布 这些医院排名靠前",
    "figure": "img/6.jpg",
    "comment": 380,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynrsrf3816830.d.html?cre=tianyi&mod=wnews&loc=5&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 17,
    "title": "章莹颖家人计划明日回国 案件是否延期审判未定",
    "figure": "img/2.jpg",
    "comment": 97,
    "link": "http://news.sina.cn/sh/2017-11-11/detail-ifynshev5246310.d.html?cre=tianyi&mod=wnews&loc=1&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 18,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 19,
    "title": "山西官方回应幼童校园被袭事件:施暴者已被刑拘",
    "figure": "img/4.jpg",
    "comment": 591,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7262878.d.html?cre=tianyi&mod=wnews&loc=3&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 20,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 21,
    "title": "中国留学生加拿大失联 警方:或接恐吓电话躲起来",
    "figure": "img/5.jpg",
    "comment": 83,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7271765.d.html?cre=tianyi&mod=wnews&loc=4&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 22,
    "title": "上海浦东一家超市发生坍塌多人被埋 致1人遇难",
    "figure": "img/3.jpg",
    "comment": 70,
    "link": "http://news.sina.cn/gn/2017-11-11/detail-ifynshev5276174.d.html?cre=tianyi&mod=wnews&loc=2&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 23,
    "title": "中国留学生加拿大失联 警方:或接恐吓电话躲起来",
    "figure": "img/5.jpg",
    "comment": 83,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7271765.d.html?cre=tianyi&mod=wnews&loc=4&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 24,
    "title": "章莹颖家人计划明日回国 案件是否延期审判未定",
    "figure": "img/2.jpg",
    "comment": 97,
    "link": "http://news.sina.cn/sh/2017-11-11/detail-ifynshev5246310.d.html?cre=tianyi&mod=wnews&loc=1&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 25,
    "title": "上海浦东一家超市发生坍塌多人被埋 致1人遇难",
    "figure": "img/3.jpg",
    "comment": 70,
    "link": "http://news.sina.cn/gn/2017-11-11/detail-ifynshev5276174.d.html?cre=tianyi&mod=wnews&loc=2&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 26,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 27,
    "title": "上海浦东一家超市发生坍塌多人被埋 致1人遇难",
    "figure": "img/3.jpg",
    "comment": 70,
    "link": "http://news.sina.cn/gn/2017-11-11/detail-ifynshev5276174.d.html?cre=tianyi&mod=wnews&loc=2&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 28,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 29,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 30,
    "title": "上海浦东一家超市发生坍塌多人被埋 致1人遇难",
    "figure": "img/3.jpg",
    "comment": 70,
    "link": "http://news.sina.cn/gn/2017-11-11/detail-ifynshev5276174.d.html?cre=tianyi&mod=wnews&loc=2&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 31,
    "title": "特朗普和普京批准联合声明:将共同打击IS直至消灭",
    "figure": "img/8.jpg",
    "comment": 100,
    "link": "http://news.sina.cn/gj/2017-11-11/detail-ifynshev5289601.d.html?cre=tianyi&mod=wnews&loc=7&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 32,
    "title": "中国留学生加拿大失联 警方:或接恐吓电话躲起来",
    "figure": "img/5.jpg",
    "comment": 83,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7271765.d.html?cre=tianyi&mod=wnews&loc=4&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 33,
    "title": "复旦版“中国医院排行榜”公布 这些医院排名靠前",
    "figure": "img/6.jpg",
    "comment": 380,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynrsrf3816830.d.html?cre=tianyi&mod=wnews&loc=5&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 34,
    "title": "上海浦东一家超市发生坍塌多人被埋 致1人遇难",
    "figure": "img/3.jpg",
    "comment": 70,
    "link": "http://news.sina.cn/gn/2017-11-11/detail-ifynshev5276174.d.html?cre=tianyi&mod=wnews&loc=2&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 35,
    "title": "复旦版“中国医院排行榜”公布 这些医院排名靠前",
    "figure": "img/6.jpg",
    "comment": 380,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynrsrf3816830.d.html?cre=tianyi&mod=wnews&loc=5&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 36,
    "title": "山西官方回应幼童校园被袭事件:施暴者已被刑拘",
    "figure": "img/4.jpg",
    "comment": 591,
    "link": "http://news.sina.cn/2017-11-11/detail-ifynsait7262878.d.html?cre=tianyi&mod=wnews&loc=3&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  },
  {
    "id": 37,
    "title": "章莹颖家人计划明日回国 案件是否延期审判未定",
    "figure": "img/2.jpg",
    "comment": 97,
    "link": "http://news.sina.cn/sh/2017-11-11/detail-ifynshev5246310.d.html?cre=tianyi&mod=wnews&loc=1&r=25&doct=0&rfunc=67&tj=none&tr=25&vt=4&pos=3"
  }
]
复制代码

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <!--meta:vp [TAB]-->
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <title></title>

    <link rel="stylesheet/less" href="css/index.less">
    <script src="js/less-2.5.3.min.js"></script>
</head>
<body>
<ul class="newsBox" id="newsBox">
    <li><a href="#">
        <div class="imgBox">
            <img src="img/1.jpg" alt="">
        </div>
        <div class="con">
            <p class="title">广西又曝两起虐童案 园长:家长敢曝光会被弄死</p>
            <span>1923</span>
        </div>
    </a></li>
</ul>

<!--IMPORT JS-->
<script src="js/utils.js"></script>
<script src="js/index.js"></script>
</body>
</html>
复制代码

在index.js中增加:让当前图片渐现出来的方法

 //=>imgFade:让当前图片渐现出来
    function imgFade(curImg) {
        var n = 0;
        var timer = setInterval(function () {
            if (n > 1) {
                clearInterval(timer);
                timer = null;
                return;
            }
            n += 0.05;
            utils.css(curImg, 'opacity', n);
        }, 17);//=>17MS是执行定时器动画相对比较理想的间隔时间
    }
复制代码

3、JS中的同步和异步编程

JS中的同步编程和异步编程

JS是单线程的(一次只能执行一个任务,当前任务没有完成,下面的任务是不进行处理的)

同步编程(sync:synchronize):任务是按照顺序一件件的完成的,当前任务没有完成,下面的任务不进行处理

异步编程(async):当前任务在等待执行的时候,我们不去执行,继续完成下面的任务,当下面的任务完成后,而是也到达等待的时间了,才去完成当前的任务

  • 定时器都是异步编程的

  • 所有的事件绑定也是异步编程的

  • AJAX中有异步编程

  • 有些人把回调函数当做异步编程(理解起来比较牵强)

其余的都是同步编程

同步编程以及如何验证当前任务消耗的时间或者性能

var startTime = new Date();
for (var i = 0; i < 100000000; i++) {
    if (i === 999999) {
        console.log('no');//=>1 'no'
    }
}
console.log(new Date() - startTime);
console.log('ok');//=>2 'ok'
复制代码

在真实项目中我们要避免出现死循环:因为循环是同步编程,当前循环无法结束证明任务没完成,后续的任务操作都执行不了了

while (1 === 1) {

}
console.log('ok');
复制代码

定时器有两件任务:创建定时器和过多长时间执行方法。创建定时器是同步,但是多长时间之后执行方法(等待任务)是异步。

//=>第一件任务:创建一个变量
var n = 0;
//=>第二件任务:创建一个定时器 (定时器里面还有个等待任务:1000MS执行方法是一个等待执行的任务)
setTimeout(function () {
    n++;
    console.log(n);//=>再输出 1
}, 1000);
//=>第三个任务:输出0
console.log(n);//=>先输出 0
复制代码

同步异步编程的核心原理

JS中有两个任务队列(存放任务列表的空间就是任务队列)

1、主任务队列:同步执行任务(从上到下依次执行)

2、等待任务队列:异步执行任务

// 王洋饭店
//   高梅(单线程理解为只能招聘一个服务员)
//
// 10:00:00 徐锐:拍黄瓜 (5MIN)
// 10:00:01 赵淼:水煮鱼 (30MIN)
// 10:00:02 金广:醋溜白菜 (10MIN)
// 10:00:03 元帅:白开水 (1MIN)
// ...
// 11:00:00 高梅忙完了,开始端菜,谁的先到时间先给谁端

setTimeout(function () {
    console.log(1);
}, 50);

setTimeout(function () {
    console.log(2);
}, 10);

setTimeout(function () {
    console.log(3);
}, 30);

for (var i = 0; i < 100000000; i++) {
    //=>需要600MS~700MS
}
console.log(4);

=>输出
123
...
123
4
2
3
1
复制代码

代码执行图

js中有两个任务队列:主任务队列(同步)和等待任务队列(异步)

js是单线程的(同步),浏览器是多线程的,浏览器只给js分了一个线程,所以所有要执行的方法都要放在主任务队列中去执行,主任务队列执行是一个同步编程的过程,只能从上到下依次执行,而js所谓的异步编程只是把某些事情先临时存放在等待任务队列当中,浏览器开始计时,当主任务队列都完成之后,到等待任务队列中,找到已经到达时间的任务,把等待任务队列中的任务拿到主任务队列中执行,当前这个任务完成后,在等待中去找其他的任务。

4、同步异步编程应用1

for (var i = 1; i <= 5; i++) {
    setTimeout(function () {
        console.log(i);
    }, (5 - i) * 10);
}
// =>[主任务队列]
// i=1 创建一个定时器
// i=2 创建一个定时器
// i=3 创建一个定时器
// i=4 创建一个定时器
// i=5 创建一个定时器
// i=6 循环结束,此时主任务队列中的方法都已经执行完成了,到等待任务队列中找先到时间的方法,拿到主任务队列中执行
// 执行它 function () {console.log(i);},i不是自己私有的,找全局下的i(此时的i已经是6了)

// =>[等待任务队列]
// 40MS后执行某方法
// 30MS后执行某方法
// 20MS后执行某方法
// 10MS后执行某方法
// 0MS后执行某方法

//输出5次,5次都是输出6

//--------------------------------------------------------------------------

for (var i = 0; i <oList.length; i++) {
    oList[i].onclick=function () {
        alert(i);
    }
}
// 所有事件绑定也是异步编程,第一次循环给oList[i]绑定一个方法,但是并没有执行,
// 异步编程放在等待任务队列中去,点击这个事件的时候才会执行(浏览器在等待任务队列中
// 除了有计时器功能外,还有监听是否触发点击事件,点击了才会把等待任务队列中的事件拿到
// 主任务中去执行)。当点击执行这个事件时,主任务中循环已经完成,i永远是最后的结果i,
// 所以最后输出的结果永远都是最后的结果i

// 结论:所有事件绑定都是异步的,当我们触发执行的时候,同步变成的循环早已结束,i就是最后循环的值

// 解决方案 把var换成let或者闭包
for (var i = 1; i <= 5; i++) {
    ~function (i) {
        setTimeout(function () {
            console.log(i);
        }, (5 - i) * 10);
    }(i);
}
复制代码

5、同步异步编程应用2

同步编程和异步编程在真正项目中会存在一个实际的应用:比如当我们打开类似京东页面,当页面在加载中时,点击页面不会任何反应,只有这个加载完成(圆圈没有了的时候),点击页面才会有对应的操作。原因就是在加载过程中,主任务队列中任务还没有完成,所以放在等待任务队列中的所有事件绑定都不会执行,只有等主任务队列完成后才去执行。

项目中会这样去实现:我们把一个页面按功能分成很多个板块,把每一块板块内容都分别用page1,page2包起来,把除第一屏page1外的板块内容都放到定时器里面,来实现异步操作,使页面加载速度更快,让首页能更快的加载出来并操作。(让主任务队列中的任务少一点,等待任务队列中的任务多一点)。

这样做还有一个好处:假设某个区域数据太多,加载出来会花很长时间,但是也不会影响其他区域加载出来(用异步操作,这个区域没加载出来,其他区域到达时间也会去加载出来)

var page1 = (function () {
    return {
        init: function () {

        }
    }
})();
page1.init();

var page2 = (function () {
    return {
        init: function () {

        }
    }
})();
setTimeout(page2.init, 0);
复制代码

例子1

setTimeout(function () {
    console.log('ok');
}, 0);//=>定时器等待时间设置为0也不是立马执行,浏览器都有一个最小的反应时间(谷歌:5~7MS IE:10~13MS ...),写0也需要等到几毫秒
console.log('no');

//-----------------------------------------------------------------------
setTimeout(function () {
    console.log(1);
}, 100);
while (1 == 1) {

}
// 主任务队列死循环永远完成不了,所以永远执行不到等待任务队列中的定时器输出不到1
复制代码

例子2

setTimeout(function () {
    console.log(1);
}, 1000);

setTimeout(function () {
    console.log(2);
    while (1 == 1) {

    }
}, 500);

setTimeout(function () {
    console.log(3);
}, 100);

for (var i = 0; i < 1000000000; i++) {

}
console.log(4);
// 输出2后,主任务队列中的while死循环执行不到输出1,所以输出结果是:4,3,2
复制代码

6、js中固定步长和固定时间的均速运动动画

html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="css/reset.min.css">
    <style>
        .box {
            position: absolute;
            top: 0;
            left: 0;
            width: 100px;
            height: 100px;
            background: red;

            opacity: 1;
            filter: alpha(opacity=100);
        }
    </style>
</head>
<body>
<div class="box" id="box"></div>

<script src="js/utils.js"></script>
<script src="js/2-1.js"></script>
</body>
</html>
复制代码

2-1.js 步长固定(每一步走多少固定了),但是多长时间运动完成不固定

//=>JS中的动画:
//1、步长固定(每一步走多少固定了),但是多长时间运动完成不固定
var oBox = document.getElementById('box'),
    target = utils.winBox('clientWidth') - oBox.offsetWidth;//目标长度
//=>动画:每间隔一定时间都在自己原有的LEFT基础上累加步长50PX即可,一直到达目标值结束
var timer = setInterval(function () {
    var curL = utils.css(oBox, 'left');//获取当前的LEFT值
    curL += 50;
    utils.css(oBox, 'left', curL);

    if (curL >= target) {
        utils.css(oBox, 'left', target);
        clearInterval(timer);
    }
}, 17);
复制代码

2-2.js 固定时间的匀速动画

//=>JS中动画:固定时间的匀速动画
//1、target:目标值
//2、begin:起始值
//3、change:总距离  target-begin
//4、duration:总时间
//5、time:已经运动的时间

// time/duration =>已经走了百分之多少的距离
// time/duration*change =>已经运动的距离
// time/duration*change+begin =>当前元素的位置

//=>匀速公式:计算出当前元素应该运动到的位置
function linear(t, b, c, d) {
    return t / d * c + b;
}
var oBox = document.getElementById('box');
var time = 0,
    duration = 1000,
    begin = utils.css(oBox, 'left'),
    target = utils.winBox('clientWidth') - oBox.offsetWidth,
    change = target - begin;
var timer = setInterval(function () {
    time += 17;
    if (time >= duration) {
        utils.css(oBox, 'left', target);
        clearInterval(timer);
        return;
    }
    var curL = linear(time, begin, change, duration);
    utils.css(oBox, 'left', curL);
}, 17);
复制代码

7、使用setTimeout模拟setInterval的效果

html

// 同6
复制代码

js

//=>使用setTimeout模拟setInterval的效果(递归)
//固定步长来模拟
var oBox = document.getElementById('box'),
    target = utils.winBox('clientWidth') - oBox.offsetWidth,//目标距离
    step = 50;//步长

// var timer = null;
function move() {
    //=>每一次开始之前,都把上一次创建的,那个没用的定时器清除掉(内存优化)
    clearTimeout(oBox.timer);

    //=>每一次走一步
    var curL = utils.css(oBox, 'left');//当前位置
    if (curL + step >= target) {
        utils.css(oBox, 'left', target);
        return;
    }
    curL += step;
    utils.css(oBox, 'left', curL);

    // var timer = setTimeout(move, 17); // 私有变量timer,下次执行得不到这个timer,如果把这个
    // // timer放在全局下(var timer = null),全局变量会增加,所以最好把这个定时器放在自定义属性 oBox.timer上;
    oBox.timer = setTimeout(move, 17);//递归
    
}
move();
复制代码

8、多方向固定时间匀速运动的动画

//=>多方向匀速固定时间动画
var oBox = document.getElementById('box');

var time = 0, // 已经走的时间
    duration = 1000;
var begin = { // 两个方向的起始值 一个变量存两个值用对象方式
    left: utils.css(oBox, 'left'),
    top: utils.css(oBox, 'top')
};
var target = { // 两个方向的目标值
    left: utils.winBox('clientWidth') - oBox.offsetWidth,
    top: utils.winBox('clientHeight') - oBox.offsetHeight
};

var change = {};//两个方向的距离值
for (var key in target) {
    if (target.hasOwnProperty(key)) {
        change[key] = target[key] - begin[key];
    }
}
// console.log(change)

// // 也可以直接这样去写
// var change = {
//     left:target['left']-begin['left'],
//     top:target['top']-begin['top']
// };

oBox.timer = setInterval(function () {
    time += 17;//当前走了多长时间
    //=>边界
    if (time >= duration) {
        utils.css(oBox, target);
        clearInterval(oBox.timer);
        return;
    }
    var curPos = {};//当前元素位置
    for (var key in change) {
        if (change.hasOwnProperty(key)) {
            curPos[key] = linear(time, begin[key], change[key], duration);
        }
    }
    //curPos={top:xxx,left:xxx} 每一个方向当前的位置
    utils.css(oBox, curPos);//批量设置oBox的样式
}, 17);

//匀速运动的公式
function linear(t, b, c, d) {
    return t / d * c + b;
}
复制代码

加了个透明度

//=>多方向匀速固定时间动画
var oBox = document.getElementById('box');
var time = 0,
    duration = 1000;
var begin = {
    left: utils.css(oBox, 'left'),
    top: utils.css(oBox, 'top'),
    opacity: utils.css(oBox, 'opacity')//加一个透明度
};
var target = {
    left: utils.winBox('clientWidth') - oBox.offsetWidth,
    top: utils.winBox('clientHeight') - oBox.offsetHeight,
    opacity: 0.1//目标值  从1变到0.1
};
var change = {};
for (var key in target) {
    if (target.hasOwnProperty(key)) {
        change[key] = target[key] - begin[key];
    }
}

oBox.timer = setInterval(function () {
    time += 17;
    //=>边界
    if (time >= duration) {
        utils.css(oBox, target);
        clearInterval(oBox.timer);
        return;
    }
    var curPos = {};
    for (var key in change) {
        if (change.hasOwnProperty(key)) {
            curPos[key] = linear(time, begin[key], change[key], duration);
        }
    }
    //curPos={top:xxx,left:xxx} 每一个方向当前的位置
    utils.css(oBox, curPos);
}, 17);


function linear(t, b, c, d) {
    return t / d * c + b;
}
复制代码

多方向匀速运动原理:把每一个方向的固定时间的匀速运动最终汇总到一起,用一个对象存储多个方向

9、封装简易的动画库(支持匀速定时多方向运动)

html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="css/reset.min.css">
    <style>
        .box {
            position: absolute;
            top: 0;
            left: 0;
            width: 100px;
            height: 100px;
            background: red;

            opacity: 1;
            filter: alpha(opacity=100);
        }
    </style>
</head>
<body>
<div class="box" id="box"></div>

<script src="js/utils.js"></script> //这里需要用到utiles里面的utils.winBox('clientWidth'),所以还是需要引入
<script src="js/animate.js"></script>
<script src="js/2-6.js"></script>
</body>
</html>
复制代码

animate.js

//=>支持多方向匀速运动(固定时间)
~function () {
    //=>4、把UTILS中的CSS单独提取出来:这样以后我们的ANIMATE动画库不需要依赖UTILS也可以独立运行
    var utils = (function () {
        var isCompatible = 'getElementsByClassName' in document;

        function getCss(curEle, attr) {
            var value = null, reg = null;
            if (isCompatible) {
                value = window.getComputedStyle(curEle, null)[attr];
            } else {
                if (attr === 'opacity') {
                    value = curEle.currentStyle['filter'];
                    reg = /^alpha\(opacity=(.+)\)$/i;
                    return reg.test(value) ? reg.exec(value)[1] / 100 : 1;
                }
                value = curEle.currentStyle[attr];
            }
            reg = /^-?\d+(.\d+)?(pt|px|rem|em)?$/i;
            return reg.test(value) ? parseFloat(value) : value;
        }

        function setCss(curEle, attr, value) {
            if (attr === 'opacity') {
                curEle.style.opacity = value;

                curEle.style.filter = 'alpha(opacity=' + value * 100 + ')';
                return;
            }
            !isNaN(value) && !/(fontWeight|lineHeight|zoom|zIndex)/i.test(attr) ? value += 'px' : null;
            curEle.style[attr] = value;
        }

        function setGroupCss(curEle, options) {
            if (Object.prototype.toString.call(options) !== '[object Object]') return;
            for (var attr in options) {
                if (options.hasOwnProperty(attr)) {
                    setCss(curEle, attr, options[attr])
                }
            }
        }

        function css() {
            var len = arguments.length,
                type = Object.prototype.toString.call(arguments[1]),
                fn = getCss;
            len >= 3 ? fn = setCss : (len === 2 && type === '[object Object]' ? fn = setGroupCss : null)
            return fn.apply(this, arguments);
        }

        return {
            css: css
        }
    })();

    /*
     * curEle:当前需要运动的元素
     * target:运动的目标位置 {xxx:xxx,...}
     * duration:运动的总时间
     */

    // 1、匀速运动公式 
    function linear(t, b, c, d) {
        return t / d * c + b;
    }

    //2、实现运动的方法
    function animate(curEle, target, duration) {
        var t = 0,
            d = duration || 1000,
            b = {},//起始值
            c = {};//总距离
        //=>传递的目标中有哪些方向,我们需要分别获取当前这些方向的起始值和总距离
        for (var key in target) {
            if (target.hasOwnProperty(key)) {
                b[key] = utils.css(curEle, key); //获取当前位置(起始值) 3、需要用到utils的css 提取utils的css方法
                c[key] = target[key] - b[key];//总距离
            }
        }

        //=>开始设置定时器,让元素运动即可
        clearInterval(curEle.animateTimer);//=>在设置新动画之前把之前正在运行的动画清除掉,防止当前元素相同的动画共存
        curEle.animateTimer = setInterval(function () {
            t += 17;
            if (t >= d) {
                utils.css(curEle, target);
                clearInterval(curEle.animateTimer);
                return;
            }
            var cur = {};
            for (var key in target) {
                if (target.hasOwnProperty(key)) {
                    cur[key] = linear(t, b[key], c[key], d);
                }
            }
            utils.css(curEle, cur);//批量设置curEle样式
        }, 17);
    }

    window.animate = animate;//暴露animate
}();
复制代码

2-6.js

// var oBox = document.getElementById('box'),
//     target = { //获取目标值
//         left: utils.winBox('clientWidth') - oBox.offsetWidth,
//         top: utils.winBox('clientHeight') - oBox.offsetHeight,
//         opacity: 0.1
//     };
// animate(oBox, target);
// animate(oBox, target, 500);

//-------------------------------------------------------
//目标值可以直接写

// var oBox = document.getElementById('box');
// animate(oBox, {
//     top: 300,
//     left:700,
//     width:200,
//     height:200
// }, 1000);

// animate(oBox, {
//     top: 100,
//     left:100,
//     width:50,
//     height:50
// }, 500);
//-------------------------------------------------------

var oBox = document.getElementById('box');
animate(oBox, {
    top: -300
}, 1000);

animate(oBox, {
    top: 300
}, 1000);

// 给当前元素设置两个动画时会冲突,所以 clearInterval(curEle.animateTimer);
//=>在设置新动画之前把之前正在运行的动画清除掉,防止当前元素相同的动画共存
复制代码

utils.js

var utils = (function () {
    var isCompatible = 'getElementsByClassName' in document,
        isSupportJSON = 'JSON' in window;

    //=>toArray & toJSON
    var toArray = function (classAry) {
        var ary = [];
        if (isCompatible) {
            ary = Array.prototype.slice.call(classAry);
        } else {
            for (var i = 0; i < classAry.length; i++) {
                ary[ary.length] = classAry[i];
            }
        }
        return ary;
    };

    var toJSON = function (str) {
        return isSupportJSON ? JSON.parse(str) : eval('(' + str + ')');
    };

    //=>offset & winBox
    var offset = function (curEle) {
        var l = curEle.offsetLeft,
            t = curEle.offsetTop,
            p = curEle.offsetParent;
        while (p.tagName !== 'BODY') {
            if (isCompatible === false && isSupportJSON === true) {
                l += p.clientLeft;
                t += p.clientTop;
            }
            l += p.offsetLeft;
            t += p.offsetTop;
            p = p.offsetParent;
        }
        return {left: l, top: t};
    };

    var winBox = function (attr, value) {
        if (typeof value !== 'undefined') {
            document.documentElement[attr] = value;
            document.body[attr] = value;
            return;
        }
        return document.documentElement[attr] || document.body[attr];
    };

    //=>children
    function children(ele, attr) {
        var ary = [];
        isCompatible ? ary = toArray(ele.children) : ary = toArray(ele.childNodes);
        for (var k = 0; k < ary.length; k++) {
            var obj = ary[k];
            if (obj.nodeType === 1) {
                if (attr && attr.toLowerCase() !== obj.tagName.toLowerCase()) {
                    ary.splice(k, 1);
                    k--;
                }
            } else {
                ary.splice(k, 1);
                k--;
            }
        }
        return ary;
    }

    //=>getElementsByClassName
    function getElementsByClassName(classStr, context) {
        if (arguments.length === 0) return [];
        context = context || document;
        if (isCompatible) {
            return toArray(context.getElementsByClassName(classStr));
        }
        var eleList = toArray(context.getElementsByTagName("*"));
        var classList = classStr.replace(/^ +| +$/g, "").split(/ +/);
        for (var i = 0; i < classList.length; i++) {
            var cur = classList[i];
            var reg = new RegExp("(^| +)" + cur + "( +|$)");
            for (var j = 0; j < eleList.length; j++) {
                if (!reg.test(eleList[j].className)) {
                    eleList.splice(j, 1);
                    j--;
                }
            }
        }
        return eleList;
    }

    //=>css
    function getCss(curEle, attr) {
        var value = null, reg = null;
        if (isCompatible) {
            value = window.getComputedStyle(curEle, null)[attr];
        } else {
            if (attr === 'opacity') {
                value = curEle.currentStyle['filter'];
                reg = /^alpha\(opacity=(.+)\)$/i;
                return reg.test(value) ? reg.exec(value)[1] / 100 : 1;
            }
            value = curEle.currentStyle[attr];
        }
        reg = /^-?\d+(.\d+)?(pt|px|rem|em)?$/i;
        return reg.test(value) ? parseFloat(value) : value;
    }

    function setCss(curEle, attr, value) {
        if (attr === 'opacity') {
            curEle.style.opacity = value;

            curEle.style.filter = 'alpha(opacity=' + value * 100 + ')';
            return;
        }
        !isNaN(value) && !/(fontWeight|lineHeight|zoom|zIndex)/i.test(attr) ? value += 'px' : null;
        curEle.style[attr] = value;
    }

    function setGroupCss(curEle, options) {
        if (Object.prototype.toString.call(options) !== '[object Object]') return;
        for (var attr in options) {
            if (options.hasOwnProperty(attr)) {
                setCss(curEle, attr, options[attr])
            }
        }

    }

    function css() {
        var len = arguments.length,
            type = Object.prototype.toString.call(arguments[1]),
            fn = getCss;

        len >= 3 ? fn = setCss : (len === 2 && type === '[object Object]' ? fn = setGroupCss : null)
        return fn.apply(this, arguments);

    }

    return {
        toArray: toArray,
        toJSON: toJSON,
        offset: offset,
        winBox: winBox,
        children: children,
        getElementsByClassName: getElementsByClassName,
        css: css
    }
})();
复制代码

10、使用动画库实现DIALOG弹出层 

html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="css/reset.min.css">
    <link rel="stylesheet" href="css/dialog.css">
</head>
<body>
<a id="login" href="javascript:;">立即登陆</a>

<!--DIALOG-->
<div class="dialogBg" id="dialogBg"></div>
<div class="dialogBox" id="dialogBox">
    <h2>欢迎登陆</h2>
    <a href="javascript:;" class="close" id="close">X</a>
    <div class="content">
        <!--具体详细展示的内容-->
    </div>
</div>

<script src="js/utils.js"></script>//同之前的utils.js
<script src="js/animate.js"></script>
<script src="js/1-1.js"></script>
</body>
</html>
复制代码

animate.js

~function () {
    var utils = (function () {
        var isCompatible = 'getElementsByClassName' in document;

        function getCss(curEle, attr) {
            var value = null, reg = null;
            if (isCompatible) {
                value = window.getComputedStyle(curEle, null)[attr];
            } else {
                if (attr === 'opacity') {
                    value = curEle.currentStyle['filter'];
                    reg = /^alpha\(opacity=(.+)\)$/i;
                    return reg.test(value) ? reg.exec(value)[1] / 100 : 1;
                }
                value = curEle.currentStyle[attr];
            }
            reg = /^-?\d+(.\d+)?(pt|px|rem|em)?$/i;
            return reg.test(value) ? parseFloat(value) : value;
        }

        function setCss(curEle, attr, value) {
            if (attr === 'opacity') {
                curEle.style.opacity = value;

                curEle.style.filter = 'alpha(opacity=' + value * 100 + ')';
                return;
            }
            !isNaN(value) && !/(fontWeight|lineHeight|zoom|zIndex)/i.test(attr) ? value += 'px' : null;
            curEle.style[attr] = value;
        }

        function setGroupCss(curEle, options) {
            if (Object.prototype.toString.call(options) !== '[object Object]') return;
            for (var attr in options) {
                if (options.hasOwnProperty(attr)) {
                    setCss(curEle, attr, options[attr])
                }
            }
        }

        function css() {
            var len = arguments.length,
                type = Object.prototype.toString.call(arguments[1]),
                fn = getCss;
            len >= 3 ? fn = setCss : (len === 2 && type === '[object Object]' ? fn = setGroupCss : null)
            return fn.apply(this, arguments);
        }

        return {
            css: css
        }
    })();

    /*
     * 动画公式
     *   t:time 已经运动的时间
     *   b:begin 当前运动方向的起始位置
     *   c:change 当前运动方向的总距离
     *   d:duration 当前运动的总时间
     */
    function linear(t, b, c, d) {
        return t / d * c + b;
    }

    /*
     * 实现动画
     *  curEle:当前要运动的元素
     *  target:当前元素运动的目标位置 {xxx:xxx...}
     *  duration:当前运动的总时间(默认值1000MS)
     *  callBack:回调函数(动画完成后我们处理什么事情)
     */
    function animate(curEle, target, duration, callBack) {
        var time = 0,
            begin = {},
            change = {};
        duration = duration || 1000;
        for (var key in target) {
            if (target.hasOwnProperty(key)) {
                begin[key] = utils.css(curEle, key);
                change[key] = target[key] - begin[key];
            }
        }

        clearInterval(curEle.animateTimer);
        curEle.animateTimer = setInterval(function () {
            time += 17;
            if (time >= duration) {
                utils.css(curEle, target);
                clearInterval(curEle.animateTimer);
                //=>动画完成后执行回调函数(验证是否为函数,是函数才执行)
                // typeof callBack === 'function' ? callBack() : null;
                callBack && callBack();
                // callBack && callBack.call(curEle);
                return;
            }

            var curPos = {};
            for (var key in target) {
                if (target.hasOwnProperty(key)) {
                    curPos[key] = linear(time, begin[key], change[key], duration);
                }
            }
            utils.css(curEle, curPos);
        }, 17);
    }

    window.animate = animate;
}();

复制代码

1-1.js 动画库实现DIALOG弹出层

var dialogRender = (function () {
    var dialogBg = document.getElementById('dialogBg'),
        dialogBox = document.getElementById('dialogBox'),
        close = document.getElementById('close');

    function show() {
        utils.css(dialogBg, 'display', 'block');
        utils.css(dialogBox, 'display', 'block');
        animate(dialogBox, {
            width: 400,
            height: 500,
            marginLeft: -200,
            marginTop: -250
        }, 500);
    }

    function hide() {
        close.onclick = function () {
            utils.css(dialogBg, 'display', 'none');
            utils.css(dialogBox, {
                display: 'none',
                width: 0,
                height: 0,
                marginLeft: 0,
                marginTop: 0
            });
        }
    }

    return {
        init: function () {
            //=>控制显示
            show();

            //=>控制隐藏
            hide();
        }
    }
})();

//=>点击登陆的时候执行DIALOG中的方法
var loginBtn = document.getElementById('login');
loginBtn.onclick = function () {
    dialogRender.init();
};
复制代码

css

html, body {
    height: 100%;
}

.login {
    display: block;
}

.dialogBg {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    z-index: 998;
    width: 100%;
    height: 100%;
    background: #000;
    opacity: 0.3;
    filter: alpha(opacity=30);
}

.dialogBox {
    display: none;
    position: fixed;
    z-index: 999;
    top: 50%;
    left: 50%;
    /*margin: -250px 0 0 -200px;
    width: 400px;
    height: 500px;*/
    margin: 0;
    width: 0;
    height: 0;
    background: #FFF;
    overflow: hidden;
}

.dialogBox h2 {
    height: 49px;
    line-height: 49px;
    text-align: center;
    background: #EEE;
    border-bottom: 1px solid #CCC;
    font-size: 16px;
    font-weight: normal;
    letter-spacing: 6px;
    overflow: hidden;
}

.dialogBox .close {
    position: absolute;
    top: 0;
    right: 0;
    width: 50px;
    height: 50px;
    line-height: 50px;
    text-align: center;
    font-size: 22px;
    font-weight: normal;
    color: #E01D20;
}
复制代码

11、扩展动画库(让其支持回调函数)

js中的定时器及动画

完整版动画库封装

  • 回调函数初步讲解

  • 扩展更多的运动方式(非匀速)

  • options对象参数的应用

回调函数

把一个函数当做实参值传递给另外一个函数,在另外一个函数中执行这个函数,这种处理机制就是回调函数机制

function fn(callBack){
    
}

function aa(){
    console.log('aa');
}

fn(aa);

//以上等价于以下写法---------------------------------

function fn(callBack) {
    //=>callBack:传递进来的匿名函数
    callBack();
}
fn(function () {
    console.log('ok');
});

//---------------------------------------------------------------------------
var ary = [12, 23];
 //通过实例找到原型上的sort方法,并且让sort方法执行,sort里面的fuction就相当于传递的匿名函数=>回调函数
 //这个function是在执行sort方法的时候,在sort方法体中把传递进来的匿名函数执行,匿名函数是在sort方法体中
 //执行的,同理:数组里面很多方法中传递的匿名函数都是回调函数
ary.sort(function (a, b) {
    return a - b;
});
ary.forEach(function () {

});
ary.map(function () {

});
setTimeout(function () {

},1000);
str.replace(reg,function () {

});
复制代码

执行animate方法,在动画执行结束之后需要做的事情(具体做什么不知道,所以传一个函数,动画结束之后执行这个函数)

animate.js 中传递一个回调函数 callBack

~function () {
    var utils = (function () {
        var isCompatible = 'getElementsByClassName' in document;

        function getCss(curEle, attr) {
            var value = null, reg = null;
            if (isCompatible) {
                value = window.getComputedStyle(curEle, null)[attr];
            } else {
                if (attr === 'opacity') {
                    value = curEle.currentStyle['filter'];
                    reg = /^alpha\(opacity=(.+)\)$/i;
                    return reg.test(value) ? reg.exec(value)[1] / 100 : 1;
                }
                value = curEle.currentStyle[attr];
            }
            reg = /^-?\d+(.\d+)?(pt|px|rem|em)?$/i;
            return reg.test(value) ? parseFloat(value) : value;
        }

        function setCss(curEle, attr, value) {
            if (attr === 'opacity') {
                curEle.style.opacity = value;

                curEle.style.filter = 'alpha(opacity=' + value * 100 + ')';
                return;
            }
            !isNaN(value) && !/(fontWeight|lineHeight|zoom|zIndex)/i.test(attr) ? value += 'px' : null;
            curEle.style[attr] = value;
        }

        function setGroupCss(curEle, options) {
            if (Object.prototype.toString.call(options) !== '[object Object]') return;
            for (var attr in options) {
                if (options.hasOwnProperty(attr)) {
                    setCss(curEle, attr, options[attr])
                }
            }
        }

        function css() {
            var len = arguments.length,
                type = Object.prototype.toString.call(arguments[1]),
                fn = getCss;
            len >= 3 ? fn = setCss : (len === 2 && type === '[object Object]' ? fn = setGroupCss : null)
            return fn.apply(this, arguments);
        }

        return {
            css: css
        }
    })();

    /*
     * 动画公式
     *   t:time 已经运动的时间
     *   b:begin 当前运动方向的起始位置
     *   c:change 当前运动方向的总距离
     *   d:duration 当前运动的总时间
     */
    function linear(t, b, c, d) {
        return t / d * c + b;
    }

    /*
     * 实现动画
     *  curEle:当前要运动的元素
     *  target:当前元素运动的目标位置 {xxx:xxx...}
     *  duration:当前运动的总时间(默认值1000MS)
     *  callBack:回调函数(动画完成后我们处理什么事情)
     */
    function animate(curEle, target, duration, callBack) {
        var time = 0,
            begin = {},
            change = {};
        duration = duration || 1000;
        for (var key in target) {
            if (target.hasOwnProperty(key)) {
                begin[key] = utils.css(curEle, key);
                change[key] = target[key] - begin[key];
            }
        }

        clearInterval(curEle.animateTimer);
        curEle.animateTimer = setInterval(function () {
            time += 17;
            if (time >= duration) {
                utils.css(curEle, target);
                clearInterval(curEle.animateTimer);
                //=>动画完成后执行回调函数(验证是否为函数,是函数才执行)
                // typeof callBack === 'function' ? callBack() : null;
                callBack && callBack();//左边不成立返回左边,左边成立才返回右边
                // callBack && callBack.call(curEle);//改变回调函数中的this,this变成当前元素
                return;
            }

            var curPos = {};
            for (var key in target) {
                if (target.hasOwnProperty(key)) {
                    curPos[key] = linear(time, begin[key], change[key], duration);
                }
            }
            utils.css(curEle, curPos);
        }, 17);
    }

    window.animate = animate;
}();

复制代码

使用这个回调函数实现直角运动动画

html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="css/reset.min.css">
    <style>
        .box {
            position: absolute;
            top: 300px;
            left: 400px;
            width: 100px;
            height: 100px;
            background: red;
            border-radius: 50%;
        }

    </style>
</head>
<body>
<div class="box" id="box"></div>

<script src="js/utils.js"></script>//同上utils.js
<script src="js/animate.js"></script> //同上animate.js 
<script src="js/2-2.js"></script>
</body>
</html>
复制代码

2-2.js

var oBox = document.getElementById('box');

function move() {
    animate(oBox, {top: 0}, 500, function () {
        utils.css(oBox, 'backgroundColor', 'green');
        animate(oBox, {left: 800}, 500, function () {
            utils.css(oBox, 'backgroundColor', 'orange');
            animate(oBox, {top: 300}, 500, function () {
                utils.css(oBox, 'backgroundColor', 'pink');
                animate(oBox, {left: 400}, 500, function () {
                    utils.css(oBox, 'backgroundColor', 'red');
                });
            });
        });
    });
}
move();
// setInterval(move, 2000);
复制代码

12、使用css3的animate实现动画

css3不兼容,标准浏览器下使用css3,ie下做个判断使用js实现(css3实现动画性能比js好)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="css/reset.min.css">
    <style>
        .box {
            position: absolute;
            top: 300px;
            left: 400px;
            width: 100px;
            height: 100px;
            background: red;
            border-radius: 50%;

            /*animation: move 2s linear 0s infinite both;*/ 
            /* 2s 匀速运动 0s的延迟 无限次运动 运动完成回到最初位置 */
        }

        @keyframes move { //@keyframes做动画  animation播放动画
            0%, 100% {
                top: 300px;
                left: 400px;
                background: red;
                transform: scale(1);
            }
            25% {
                top: 0;
                left: 400px;
                background: green;
                transform: scale(1.5);
            }
            50% {
                top: 0;
                left: 800px;
                background: orange;
                transform: scale(1);
            }
            75% {
                top: 300px;
                left: 800px;
                background: blue;
                transform: scale(1.5);
            }
        }

    </style>
</head>
<body>
<div class="box" id="box"></div>
</body>
</html>
复制代码

13、动画库最后完整版封装

当前animate动画库执行的所有动画都是匀速运动动画(只有一个linear匀速运动公式),

接下来基于这个动画库去扩展支持非匀速运动的,非匀速运动的跟linear一样也需要有个运动公式才行

重点都在运动公式上 animationEffect封装的动画公式(来自flash源码里面的动画运动公式,比jquery封装的运动动画还要强大

参考网址 old.zhufengpeixun.cn/tween/

支持多运动回调函数的动画库完整封装=> 这里主要是运动公式

html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title></title>
    <link rel="stylesheet" href="css/reset.min.css">
    <style>
        .box {
            position: absolute;
            top: 300px;
            left: 400px;
            width: 100px;
            height: 100px;
            background: red;
            border-radius: 50%;
        }

    </style>
</head>
<body>
<div class="box" id="box"></div>

<script src="js/utils.js"></script>
<script src="js/animate.js"></script>
<script src="js/2-3.js"></script>
</body>
</html>
复制代码

animate.js

~function () {
    //=>封装CSS工具方法
    var utils = (function () {
        var isCompatible = 'getElementsByClassName' in document;

        function getCss(curEle, attr) {
            var value = null, reg = null;
            if (isCompatible) {
                value = window.getComputedStyle(curEle, null)[attr];
            } else {
                if (attr === 'opacity') {
                    value = curEle.currentStyle['filter'];
                    reg = /^alpha\(opacity=(.+)\)$/i;
                    return reg.test(value) ? reg.exec(value)[1] / 100 : 1;
                }
                value = curEle.currentStyle[attr];
            }
            reg = /^-?\d+(.\d+)?(pt|px|rem|em)?$/i;
            return reg.test(value) ? parseFloat(value) : value;
        }

        function setCss(curEle, attr, value) {
            if (attr === 'opacity') {
                curEle.style.opacity = value;

                curEle.style.filter = 'alpha(opacity=' + value * 100 + ')';
                return;
            }
            !isNaN(value) && !/(fontWeight|lineHeight|zoom|zIndex)/i.test(attr) ? value += 'px' : null;
            curEle.style[attr] = value;
        }

        function setGroupCss(curEle, options) {
            if (Object.prototype.toString.call(options) !== '[object Object]') return;
            for (var attr in options) {
                if (options.hasOwnProperty(attr)) {
                    setCss(curEle, attr, options[attr])
                }
            }
        }

        function css() {
            var len = arguments.length,
                type = Object.prototype.toString.call(arguments[1]),
                fn = getCss;
            len >= 3 ? fn = setCss : (len === 2 && type === '[object Object]' ? fn = setGroupCss : null)
            return fn.apply(this, arguments);
        }

        return {
            css: css
        }
    })();

    //=>封装动画公式:匀速运动和非匀速运动
    //http://old.zhufengpeixun.cn/tween/
    var animationEffect = {
        //匀速运动
        Linear: function (t, b, c, d) {
            return c * t / d + b;
        },
        Bounce: {
            //加速
            easeIn: function (t, b, c, d) {
                return c - animationEffect.Bounce.easeOut(d - t, 0, c, d) + b;
            },
            //减速
            easeOut: function (t, b, c, d) {
                if ((t /= d) < (1 / 2.75)) {
                    return c * (7.5625 * t * t) + b;
                } else if (t < (2 / 2.75)) {
                    return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
                } else if (t < (2.5 / 2.75)) {
                    return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
                } else {
                    return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
                }
            },
            //先加速再减速
            easeInOut: function (t, b, c, d) {
                if (t < d / 2) {
                    return animationEffect.Bounce.easeIn(t * 2, 0, c, d) * .5 + b;
                }
                return animationEffect.Bounce.easeOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
            }
        },
        Quad: {
            easeIn: function (t, b, c, d) {
                return c * (t /= d) * t + b;
            },
            easeOut: function (t, b, c, d) {
                return -c * (t /= d) * (t - 2) + b;
            },
            easeInOut: function (t, b, c, d) {
                if ((t /= d / 2) < 1) {
                    return c / 2 * t * t + b;
                }
                return -c / 2 * ((--t) * (t - 2) - 1) + b;
            }
        },
        Cubic: {
            easeIn: function (t, b, c, d) {
                return c * (t /= d) * t * t + b;
            },
            easeOut: function (t, b, c, d) {
                return c * ((t = t / d - 1) * t * t + 1) + b;
            },
            easeInOut: function (t, b, c, d) {
                if ((t /= d / 2) < 1) {
                    return c / 2 * t * t * t + b;
                }
                return c / 2 * ((t -= 2) * t * t + 2) + b;
            }
        },
        Quart: {
            easeIn: function (t, b, c, d) {
                return c * (t /= d) * t * t * t + b;
            },
            easeOut: function (t, b, c, d) {
                return -c * ((t = t / d - 1) * t * t * t - 1) + b;
            },
            easeInOut: function (t, b, c, d) {
                if ((t /= d / 2) < 1) {
                    return c / 2 * t * t * t * t + b;
                }
                return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
            }
        },
        Quint: {
            easeIn: function (t, b, c, d) {
                return c * (t /= d) * t * t * t * t + b;
            },
            easeOut: function (t, b, c, d) {
                return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
            },
            easeInOut: function (t, b, c, d) {
                if ((t /= d / 2) < 1) {
                    return c / 2 * t * t * t * t * t + b;
                }
                return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
            }
        },
        Sine: {
            easeIn: function (t, b, c, d) {
                return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
            },
            easeOut: function (t, b, c, d) {
                return c * Math.sin(t / d * (Math.PI / 2)) + b;
            },
            easeInOut: function (t, b, c, d) {
                return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
            }
        },
        Expo: {
            easeIn: function (t, b, c, d) {
                return (t == 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
            },
            easeOut: function (t, b, c, d) {
                return (t == d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
            },
            easeInOut: function (t, b, c, d) {
                if (t == 0) return b;
                if (t == d) return b + c;
                if ((t /= d / 2) < 1) return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
                return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
            }
        },
        Circ: {
            easeIn: function (t, b, c, d) {
                return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
            },
            easeOut: function (t, b, c, d) {
                return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
            },
            easeInOut: function (t, b, c, d) {
                if ((t /= d / 2) < 1) {
                    return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
                }
                return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
            }
        },
        Back: {
            easeIn: function (t, b, c, d, s) {
                if (s == undefined) s = 1.70158;
                return c * (t /= d) * t * ((s + 1) * t - s) + b;
            },
            easeOut: 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;
            },
            easeInOut: function (t, b, c, d, s) {
                if (s == undefined) s = 1.70158;
                if ((t /= d / 2) < 1) {
                    return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
                }
                return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
            }
        },
        Elastic: {
            easeIn: function (t, b, c, d, a, p) {
                if (t == 0) return b;
                if ((t /= d) == 1) return b + c;
                if (!p) p = d * .3;
                var s;
                !a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
                return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
            },
            easeOut: function (t, b, c, d, a, p) {
                if (t == 0) return b;
                if ((t /= d) == 1) return b + c;
                if (!p) p = d * .3;
                var s;
                !a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
                return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
            },
            easeInOut: function (t, b, c, d, a, p) {
                if (t == 0) return b;
                if ((t /= d / 2) == 2) return b + c;
                if (!p) p = d * (.3 * 1.5);
                var s;
                !a || a < Math.abs(c) ? (a = c, s = p / 4) : s = p / (2 * Math.PI) * Math.asin(c / a);
                if (t < 1) return -.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
                return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
            }
        }
    };

    //=>实现动画
    //=>必传参数:curEle/target
    //=>选传参数:duration/callBack/effect
    //1、以后封装方法的时候,如果当前方法需要传递很多值进来,我们一般都不会定义为一个个的形参,定义为一个个的形参会有很多问题:
    //A:传递实参的顺序必须和定义的形参一一对应
    //B:如果中间少传递一项值,后面每一项的值都会错位,不方便扩展性
    //...
    //2、我们一般都采用传递一个参数集合的方式,把一些参数作为对象中的某一个属性值传递进来
    // animate({
    //     target: {top: 0},
    //     effect: animationEffect.Linear,
    //     curEle: oBox
    // });
    function animate(options) {
        //=>init parameter 初始化参数
        var _default = {
            curEle: null,
            target: {},
            duration: 1000,
            effect: animationEffect.Linear,
            callBack: null
        };
        // 传递进来的options覆盖_default默认值
        for (var key in options) {
            if (options.hasOwnProperty(key)) {
                _default[key] = options[key];
            }
        }
        //把需要用到的值都定义成一个个变量从_default拿出来
        var curEle = _default.curEle,
            target = _default.target,
            duration = _default.duration,
            effect = _default.effect,
            callBack = _default.callBack;

        //=>prepare准备 t/b/c/d  遍历target每一项把target每个方向的起始值和总距离算出来
        var time = null,
            begin = {},
            change = {};
        for (var attr in target) {
            if (target.hasOwnProperty(attr)) {
                begin[attr] = utils.css(curEle, attr);
                change[attr] = target[attr] - begin[attr];
            }
        }

        //=>move开始运动
        clearInterval(curEle.animateTimer);
        curEle.animateTimer = setInterval(function () {
            time += 17;
            if (time >= duration) {
                utils.css(curEle, target);
                clearInterval(curEle.animateTimer);
                callBack && callBack.call(curEle);//回调函数中的this都是当前元素curEle
                return;
            }
            var curPos = {};//通过target目标值计算出每个方向的当前位置
            for (var key in target) {
                if (target.hasOwnProperty(key)) {
                    curPos[key] = effect(time, begin[key], change[key], duration);//effect存的是运动公式
                }
            }
            utils.css(curEle, curPos);
        }, 17);
    }

    window.animate = animate;
    window.animateEffect = animationEffect;
}();

复制代码

2-3.js

var oBox = document.getElementById('box');

animate({
    curEle: oBox,
    target: {top: 0},
    duration: 500,
    effect: animateEffect.Bounce.easeOut,
    callBack: function () {
        //=>this:oBox 动画库中处理的
        //=>第二次运动
        animate({
            curEle: this,
            target: {left: 800},
            duration: 500,
            effect: animateEffect.Back.easeOut,
            callBack: function () {
                //=>第三次运动
                animate({
                    curEle: this,
                    target: {top: 300},
                    duration: 500,
                    effect: animateEffect.Elastic.easeOut,
                    callBack: function () {
                        //=>第四次运动
                        animate({
                            curEle: this,
                            target: {left: 400},
                            duration: 500
                        });
                    }
                });
            }
        });
    }
});
复制代码

14、for in循环遍历的一点细节问题

var obj = {name: '呵呵', age: 8};
for (var key in obj) {
    if (obj.hasOwnProperty(key)) {

    }
}
复制代码

为啥么每次for in循环要多加一个hasOwnProperty(key)?

Object.prototype.hasPubProperty = function hasPubProperty() {//验证是不是公有属性

};

/*
 * for in
 *   不仅可以遍历当前对象(或者当前实例)所有的私有属性和方法,还可以把原型上自己创建的公共属性方法进行遍历
 *
 * for
 *   只会遍历私有的属性和方法(更多的是索引),自己在原型上扩展的方法不会被遍历出来
 */

var obj = {name: '呵呵', age: 8};
for (var key in obj) {
    if (obj.hasOwnProperty(key)) { // 判断当前key这个属性是不是它的私有属性

    }
}

// var ary = [12, 23, 34];
// for (var i = 0; i < ary.length; i++) {
//     console.log(ary[i]);
// }
//
// for (var key in ary) {
//     console.log(ary[key]);
// }

复制代码

webstorm快捷键配置:

file -> setting -> editor -> live templates-javascript ->

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值