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 ->