一、JavaScript 基础
[TOC]
1. 数据类型###
最新的 ECMAScript 标准定义了 7 种数据类型:
基本数据类型
Number
Boolean
String
Undefined
Null
Symbol (ECMAScript 6 新定义)
复杂数据类型
Object
- JavaScript 中,可以使用 typeof 获取变量数据类型,typeof(a) 与 typeof a 等价。
var n = 10;
var b = true;
var s = 'foobar';
typeof(n); // 'number'
typeof b; // 'boolean'
typeof s; // 'string'
1.1 数值 Number####
- JavaScript 只有一种数字类型。数字可以带小数点,也可以不带。
var x1 = 34.00; //使用小数点来写
var x2 = 34; // 不使用小数点来写
极大或极小的数字可以通过科学(指数)计数法来书写:
var y = 123e5; // 12300000
var z = 123e-5; // 0.00123
1.2 布尔 Boolean####
- 布尔(逻辑)只有两个值:true 和 false。
在 if 语句中,0 null '' false NaN 均表示 false 值。
var t = true;
var f = false;
var num = 10;
var s = '';
if (num > 5) { } // true
if (s) { } // false
1.3 字符串 String####
- JavaScript 的字符串类型用于表示文本数据。用单引号''或双引号""表示。
var s1 = 'foo'; // 单引号表示
var s2 = "bar"; // 双引号表示
1.4 Undefined####
- 一个没有被赋值的变量会有个默认值 undefined,undefined 是全局对象的一个属性。也就是说,它是全局作用域的一个变量。
var a;
typeof a; // 'undefined'
1.5 Null####
- Null 类型只有一个值: null,值 null 是一个 JavaScript 字面量,表示空值,即没有对象被呈现。它是 JavaScript 原始值 之一。
var foo = null;
typeof foo; // 'null'
与 undefined 不同点
typeof null // object (ECMAScript 的 bug, 应该为 null)
typeof undefined // undefined
null === undefined // false
null == undefined // true
1.6 Symbol####
- Symbol 是一种特殊的、不可变的数据类型,可以作为对象属性的标识符使用。
1.7 对象 Object####
- 对象有两种创建方式,创建时,对象的属性以名称和值对的形式 (name : value) 来定义。属性由逗号 , 分隔。
// 通过new创建
var fruit = new Object({
name: 'apple',
color: 'red'
});
// 通过花括号{}创建
var person = {
name: 'mike',
gender: 'male',
age: 21,
// 存放一个函数
getAge: function() {
return this.name;
}
}
对象属性有两种访问方式
var name = person.name; // 通过 对象.属性名 访问
var age = person['age']; // 通过 对象['属性名'] 访问
如果属性值是函数,则通过 对象.属性名() 或者 对象'属性名' 调用
var age = person.getAge();
var age2 = person['getAge']();
修改属性值同样有两种方式
person.name = 'Jack';
person['age'] = 25;
删除属性:使用 delete
console.log(person.name); // 'Jack'
// 删除 name 属性
delete person.name;
console.log(person.name); // undefined
1.7.1 特殊对象:数组 Array####
- 数组是特殊的对象,可以存放任意类型的值。有两种创建方式:
// 构造函数创建
var names = new Array('mike', 'joe');
// 快速创建
var cars = ["Audi", "BMW", "Volvo"];
数组里面的元素通过数组下标访问(下标从0开始)
var name = names[0]; // 'mike'
var car = cars[1]; // 'BMW'
二、JavaScript 进阶###
1. 字符串属性和函数####
length : 获取字符串长度
var str = 'foobar';
var length = str.length; // length = 6
charAt(index) :获取指定位置的字符
参数 index : 在字符串中的下标
var str = 'hello';
var c = str.charAt(1); // 获取位置(下标)在1处的字符串
console.log(c); // 'e'
concat(str, str2, ...) :用于连接两个或多个字符串
参数 str :要拼接的字符串
var greeting = 'hello,';
var name = 'Mike';
var str = greeting.concat(name); // 'hello,Mike'
indexOf(searchStr, [fromIndex]):获取某个指定字符串在字符串中首次出现的位置。
- 参数 searchStr :要搜索的字符串
- 参数 fromIndex :可选,起始的搜索位置(下标),不传此参数表示从字符串开始处查找
var str = 'JavaScript';
// 获取 a 首次出现的位置
var index = str.indexOf('a'); // index = 1
lastIndexOf(searchStr, [fromIndex]):获取某个指定字符串在字符串中最后出现的位置。
- 参数 searchStr :要搜索的字符串
- 参数 fromIndex :可选,起始的搜索位置(下标),不传此参数表示从字符串
结尾处查找
var str = 'JavaScript';
// 获取 a 最后出现的位置
var index = str.lastIndexOf('a'); // index = 3
replace(regexp/substr,replacement):替换与正则表达式或指定字符串匹配的子串。
- 参数 regexp :要匹配的正则表达式
- 参数 substr :要匹配的字符串
- 参数 replacement :要替换的字符串
注意####
- 此方法不会改变原来的字符串,只会返回一个替换后的新字符串。
使用字符串匹配只会替换第一个查找到的字符串
如果需要替换所有匹配的字符串,需要使用正则表达式且使用全局标志 g
例1:使用字符串匹配
var str = 'java';
var newStr = str.replace('j', 'k'); // newStr = 'kava'
// 使用字符串匹配只会替换第一个查找到的字符串
var newStr2 = str.replace('a', 'e'); // newStr2 = 'jeva'
例2:使用正则表达式匹配
var str = 'java';
// 不使用全局标志 g ,只会替换第一个匹配的字符串
var newStr = str.replace(/a/, 'e'); // newStr = 'jeva'
// 使用全局标志 g ,替换所有匹配的字符串
var newStr2 = str.replace(/a/g, 'e'); // newStr2 = 'jeve';
split(separator, [count]) 把一个字符串按指定分隔符分割成字符串数组。
- 参数 separator :以此参数作为分隔符,将字符串分割为数组
- 参数 count :可选。限定分割后的字符串数组长度
var str = 'mike,jane,joe,lance';
var names = str.split(','); // names = ['mike', 'jane', 'joe', 'lance'];
var names2 = str.split(',', 2); // names = ['mike', 'jane'];
slice(start, [end]) :截取字符串的一部分,并返回被截取的字符串
- 参数 start :截取的起始位置。如果是负数,则该参数规定的是从字符串的尾部开始算起的位置。也就是说,-1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。
- 参数 end :可选。截取的结束位置(不包含 end)。若未指定此参数,则要提取的子串包括 start 到原字符串结尾的字符串。如果该参数是负数,那么它规定的是从字符串的尾部开始算起的位置。
var str = 'hello, world';
// 截取 world (从下标7开始,到末尾)
var newStr = str.slice(7);
// 截取 wo (从下标7开始,到下标9结束)
var newStr2 = str.slice(7, 9);
substr(start, [length]) :截取从 start 开始的指定长度的字符串
- 参数 start :截取的起始位置。如果是负数,则该参数规定的是从字符串的尾部开始算起的位置。也就是说,-1 指字符串的最后一个字符,-2 指倒数第二个字符,以此类推。
- 参数 length :可选。截取的长度。如果不指定,那么返回从 start 开始到结尾的字符串。
var str = 'hello, world';
// 截取 world (从下标7开始,到末尾)
var newStr = str.substr(7);
// 截取 wo (从下标7开始,截取2个字符)
var str2 = str.substr(7, 2);
toLowerCase() :将字符串转换为小写
var str = 'Hello'.toLowerCase(); // str = 'hello'
toUpperCase() :将字符串转换为大写
var str = 'Hello'.toUpperCase(); // str = 'HELLO'
2. 数组属性函数####
length :获取数组元素个数
var arr = [1, 3, 5, 7];
var len = arr.length; // len = 4
concat(arr, [arr2], ...) :连接一个或两个或多个数组
- 参数arr :要连接的对象。可以是具体的值,也可以是数组对象。可以传1个或多个
此方法不会改变原来数组,仅是返回一个新的数组
例1:传值
var arr = ['a', 'b', 'c'];
var arr2 = arr.concat('d', 'e'); // arr2 = ['a', 'b', 'c', 'd', 'e']
例2:传数组
var arr = [1, 3, 5];
var arr2 = arr.concat([7, 9]); // arr2 = [1, 3, 5, 7, 9]
join([separator]) :将一个数组通过指定分隔符连接成一个字符串
- 参数separator : 可选。指定要使用的分隔符。如果省略该参数,则使用逗号 , 作为分隔符。
var arr = ['foo', 'bar'];
var str = arr.join(' '); // str = 'foo bar';
reverse() :反转数组(颠倒数组中元素的顺序。)
注意:此方法将直接修改数组
var arr = ['a', 'b', 'c'];
arr.reverse(); // arr = ['c', 'b', 'a']
push(element, [element2], ...)
:向数组的末尾添加一个或多个元素,并返回新的长度
- 参数 element :要添加的元素,可以添加多个
注意:此方法将直接修改数组
var arr = [1, 2, 3];
var len = arr.push(4, 5); // arr = [1, 2, 3, 4, 5]; len = 5
unshift(element, [element2], ...) :向数组的开头添加一个或多个元素,并返回新的长度
- 参数 element :要添加的元素,可以添加多个
注意:此方法将直接修改数组
var arr = [1, 2, 3];
var len = arr.unshift(4, 5); // arr = [4, 5, 1, 2, 3]; len = 5
- pop() :删除数组的最后一个元素,并返回这个被删除的元素
注意:此方法将直接修改数组
var arr = ['a', 'b', 'c'];
var element = arr.pop(); // arr = ['a', 'b']; element = 'c'
- shift() :删除并返回数组的第一个元素
注意:此方法将直接修改数组
var arr = ['a', 'b', 'c'];
var element = arr.shift(); // arr = ['b', 'c']; element = 'a'
slice(start, [end]) :截取数组的一部分,并返回被截取的数组
- 参数 start :截取的起始位置。如果是负数,则该参数规定的是从数组的尾部开始算起的位置。也就是说,-1 指数组的最后一个元素,-2 指倒数第二个元素,以此类推。
- 参数 end :可选。截取的结束位置(不包含 end)。若未指定此参数,则要提取的数组包括 start 到原数组结尾的部分。如果该参数是负数,那么它规定的是从数组的尾部开始算起的位置。
注意:此方法不会修改数组,仅返回截取后的新数组
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.slice(1); // arr2 = [2, 3, 4, 5]
var arr3 = arr.slice(1, 3); // arr3 = [2, 3]
- splice(index, count, [element], [element2], [...]) :删除从 index 开始指定长度的元素,将新元素添加到被删除的位置,并返回被删除的元素
- 参数 index :添加/删除元素的位置,使用负数可从数组结尾处规定位置。
- 参数 count :要删除的元素数量。如果设置为 0,则不会删除元素。
- 参数 element :可选。要添加的元素
var arr = [1, 2, 3, 4, 5];
var elements = arr.splice(1, 2, 6, 7); // arr = [1, 6, 7, 4, 5]; elements = [2, 3]
- sort([sortby]) :对数组的元素进行排序
- 参数 sortby :可选。规定排序顺序。必须是函数。
- 如果是数值,则按数值升序排序
如果是字符串数组,则按 ascii 码升序排序
注意:此方法将直接修改数组
// 字符串排序
var arr = ['s', 'e', 'f', 'a'];
arr.sort(); // arr = ['a', 'e', 'f', 's']
// 数值排序
var arr2 = [4, 5, 2, 1, 3];
arr2.sort(); // arr2 = [1, 2, 3, 4, 5]
// 仅仅是按 asc 码排序
var arr3 = ['10', '2', '30', '15'];
arr3.sort(); // arr3 = ['10', '15', '2', '30']
// 自定义排序(元素两两比较)
// 若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。
// 若 a 等于 b,则返回 0。
// 若 a 大于 b,则返回一个大于 0 的值。
function sortNumber(a, b) {
return parseInt(a) > parseInt(b);
}
var arr4 = ['10', '2', '30', '15'];
arr4.sort(sortNumber); // arr4 = ['2', '10', '15', '30']
- filter(callback) :过滤数组中的元素
- 参数 callback :用于过滤数组元素的 函数
注意:此方法不会改变原数组
var arr = [1, 2, 3, 4, 5];
// 获取数组中大于3的元素
var arr2 = arr.filter(function(value){
return value > 3;
});
// arr = [1, 2, 3, 4, 5]
// arr2 = [4, 5]
toString() :将数组转换为字符串并返回,数组元素用逗号 , 分割。作用同 arr.join()
var arr = [1, 2, 3];
var str = arr.toString(); // str = '1,2,3'
- match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
- 该方法类似 indexOf() 和 lastIndexOf(),但是它返回指定的值,而不是字符串的位置。
语法:
stringObject.match(searchvalue)
stringObject.match(regexp)
参数描述:
- searchvalue 必需。规定要检索的字符串值。
三、兼容性和正则###
正则###
/*是否带有小数*/
function isDecimal(strValue ) {
var objRegExp= /^\d+\.\d+$/;
return objRegExp.test(strValue);
}
/*校验是否中文名称组成 */
function ischina(str) {
var reg=/^[\u4E00-\u9FA5]{2,4}$/; /*定义验证表达式*/
return reg.test(str); /*进行验证*/
}
/*校验是否全由8位数字组成 */
function isStudentNo(str) {
var reg=/^[0-9]{8}$/; /*定义验证表达式*/
return reg.test(str); /*进行验证*/
}
/*校验电话码格式 */
function isTelCode(str) {
var reg= /^((0\d{2,3}-\d{7,8})|(1[3584]\d{9}))$/;
return reg.test(str);
}
/*校验邮件地址是否合法 */
function IsEmail(str) {
var reg=/^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/;
return reg.test(str);
}
严格模式###
strict
防止拖拽的时候选中文字###
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();
event兼容ie678的写法###
var event = event || window.event;// 兼容性ie678
scrollTop兼容性写法###
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
小知识###
JSON.parse() 将JSON字符串转js对象
JSON.stringify() 将js对象转JSON字符串
函数声明###
1:自定义函数
function abs(){alert(111);}
2:函数变量声明
var abs = funciton(){}
3:利用function关键字声明
var abc = new function(){}
4:变量提升
在函数内部声明变量会把改声明提到函数最顶端,只提升变量,不赋值
5:返回值return
计算完成之后返回结果,在函数内部用return来设置返回值,一个函数只能有一个返回值,注意:所有自定义函数是没有返回值的
6:this
指自己本身,主要指事件的调用者
7:表单自动获取焦点:focus()
8:判断用户输入事件 :
正常浏览器 : oninput
Ie 678 支持的 : onpropertychange
8:onchange 事件,当改变的时候
1:兄弟节点
nextSibling 下一个兄弟 亲的 ie 678 认识
nextElementSibling 其他浏览器认识的
previousSibling 同理 上一个兄弟
previousElementSibling
我们想要兼容 我们可以合写 || 或者
兼容性写法:var div = one.nextElementSibling || one.nextSibling;
div.style.backgroundColor = "red";(注意:必须先写正常浏览器再写ie678)
:2:子节点
firstChild 第一个孩子 ie678
firstElementChild 第一个孩子 正常浏览器
兼容性写法:var one.firstElementChild || one.firstChild;
lastChild 最后一个孩子 ie678
lastElementChild 最后一个孩子 真常浏览器
3:孩子节点
hildNodes 选出全部的孩子
childNodes:它是标准属性,它返回指定元素的子元素集合,包括HTML节点,所有属性,文本节点 (嫡出)
火狐 谷歌等高本版会把换行也看做是子节点
children 重要 选取所有的孩子 (只有元素节点)
这个更好 跟喜欢它 。 (庶出)
ie 678 包含 注释节点 这个要避免开。
DOM操作##
- appendChild(); 添加孩子 append 添加的意思
意思: 添加孩子 放到盒子的 最后面。 - insertBefore(插入的节点,参照节点) 子节点 添加孩子
写满两个参数
demo.insertBefore(test,childrens[0]);
放到了第一个孩子的前面
如果第二个参数 为 null 则 默认这新生成的盒子放到最后面。
demo.insertBefore(test,null);
3:removeChild() 孩子节点
4:cloneNode();
复制节点
括号里面可以跟参数 , 如果 里面是 true 深层复制, 除了复制本盒子,还复制子节点
如果为 false 浅层复制 只复制 本节点 不复制 子节点。
5: 1. 获取节点属性
getAttribute(属性) 获取属性
通过这个方法,可以得到 某些元素的 某些属性 。
alert(demo.getAttribute("title"));
6: 设置节点属性
setAttribute(“属性”,”值”);
比如说,我们想要把 一个 类名 改为 demo
div.setAttribute(“class”,”demo”);
7:删除某个属性
removeAttribute(“属性”);
demo.removeAttribute(“title”)
这个盒子就没有title 属性 给删掉了 。
A.appendChild(B);
B 一定是 A 孩子 同时 b 放到了a 的里面 装到里面去了 最后面。 b 放到 a 里面
A.insertBefore(B,C)
B C 都是 A 的孩子
把 b 放到 a 里面 ,但是 是 c 的前面
8:声明日期:var date = new Date();
9:常用的日期的方法
获取日期和时间
getDate() 获取日 1-31
getDay () 获取星期 0-6
getMonth () 获取月 0-11
getFullYear () 获取完整年份(浏览器都支持)
getHours () 获取小时 0-23
getMinutes () 获取分钟 0-59
getSeconds () 获取秒 0-59
getMilliseconds () 获取当前的毫秒
getTime () 返回累计毫秒数(从1970/1/1午夜)
10:定时器
setInterval( function(){} , 1000 )
倒计时
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
<style>
body{
font-size:30px;
text-align: center;
color:red;
}
</style>
<script>
window.onload = function(){
var demo = document.getElementById("demo");
var endTime = new Date("2015/12/12 17:30:00"); // 最终时间
setInterval(clock,1000); // 开启定时器
function clock(){
var nowTime = new Date(); // 一定是要获取最新的时间
// console.log(nowTime.getTime()); 获得自己的毫秒
var second = parseInt((endTime.getTime() - nowTime.getTime()) / 1000);
// 用将来的时间毫秒 - 现在的毫秒 / 1000 得到的 还剩下的秒 可能处不断 取整
// console.log(second);
// 一小时 3600 秒
// second / 3600 一共的小时数 /24 天数
var d = parseInt(second / 3600 / 24); //天数
//console.log(d);
var h = parseInt(second / 3600 % 24) // 小时
// console.log(h);
var m = parseInt(second / 60 % 60);
//console.log(m);
var s = parseInt(second % 60); // 当前的秒
console.log(s);
/* if(d<10)
{
d = "0" + d;
}*/
d<10 ? d="0"+d : d;
h<10 ? h="0"+h : h;
m<10 ? m="0"+m : m;
s<10 ? s="0"+s : s;
demo.innerHTML = "距离抢购时间还剩: "+d+"天 "+h+"小时 "+m+"分钟 "+s+"秒";
}
}
</script>
</head>
<body>
<div id="demo"></div>
</body>
11:时钟案例
分两步进行的。
第一步: 要得到现在的 时 分 秒
但是这里面有一个小玄机 。
比如现在是 9点整 时针指向 9 是没错的
但是如果现在是 9点半 时针应该指向的是 9到10 之间 才对
所以,我们不但要得到现在的小时 ,还要得到 已经过去了多少分
ms = date.getMilliseconds(); // 现在的毫秒数
s = date.getSeconds() + ms / 1000; // 得到秒 1.3 s
m = date.getMinutes() + s / 60; // 得到的是分数 45.6分钟
h = date.getHours() % 12 + m / 60 ;
旋转角度原理
秒针 一秒 走多少度呢 ?
一圈 360 ° 一共有 60 秒 每秒 6 °
分针 一圈 360 一圈走 60次 每次 6° 每分钟 6°
时针 一圈 360 一共 12 个 表盘没有24小时 每个小时 走 30°
<script>
var hour = document.getElementById("hour");
var minute = document.getElementById("minute");
var second = document.getElementById("second");
// 开始定时器
var s = 0,m = 0, h = 0, ms = 0;
setInterval(function() {
// 内容就可以了
var date = new Date(); // 得到最新的时间
ms = date.getMilliseconds(); // 现在的毫秒数
s = date.getSeconds() + ms / 1000; // 得到秒 1.3 s
m = date.getMinutes() + s / 60; // 得到的是分数 45.6分钟
h = date.getHours() % 12 + m / 60 ;
// console.log(h);
// 旋转角度
// 一圈 360 ° 一共有 60 秒 每秒 6 ° 现在是 s秒
second.style.WebkitTransform = "rotate("+ s*6 +"deg)";
// 变化 旋转 deg 度
minute.style.WebkitTransform = "rotate("+ m*6 +"deg)";
hour.style.WebkitTransform = "rotate("+ h*30 +"deg)";
second.style.MozTransform = "rotate("+ s*6 +"deg)";
// 变化 旋转 deg 度
minute.style.MozTransform = "rotate("+ m*6 +"deg)";
hour.style.MozTransform = "rotate("+ h*30 +"deg)";
},30);
</script>
12:定时器之 setTimeout()
时间去哪儿了 类似于定时炸弹 。。
setTimeout(“函数”, 时间 )
setInterval(fn,5000); 每隔 5秒钟,就去执行函数fn一次
setTimeout(fn,5000); 5秒钟之后,去执行 fn 函数, 只执行一次
13:深层次的看待定时器区别
setInterval是排队执行的
假如 间隔时间是1秒, 而执行的程序的时间是2秒 上次还没执行完的代码会排队, 上一次执行完下一次的就立即执行, 这样实际执行的间隔时间为2秒
setTimeout延迟时间为1秒执行, 要执行的代码需要2秒来执行,那这段代码上一次与下一次的执行时间为3秒.
案例:秒钟自动跳转页面:
JS 页面跳转: window.location.href = ”http://www.itcast.cn” ; BOM
函数自己调用自己的过程 我们称之为 : 递归调用 自残
<script>
var demo = document.getElementById("demo");
var count = 5;
var speed = 1000;
setTimeout(goIndexPage,speed); // 1秒钟之后去执行 goIndexPage这个函数
function goIndexPage() {
count--;
demo.innerHTML = "<a href='http://www.baidu.com'>本页面将在第"+count+"秒钟之后跳转页面</a>";
if(count <= 0)
{
// 如果 count 小于 0 就到了时间了 我们应该跳转页面
window.location.href = "http://www.baidu.com";
}
else
{
setTimeout(goIndexPage,speed); // 递归调用 自己调用自己
}
}
</script>
14:arguments 对象
function fn(a,b,c) { console.log(a+b+c); alert(arguments.length;)}
fn(1,3,4,6);
arguments.length; 返回的是 实参的个数。
但是这个对象有讲究,他只在正在使用的函数内使用。
arguments.callee;
返回的是正在执行的函数。 也是在函数体内使用。 在使用函数递归调用时推荐使用arguments.callee代替函数名本身。
function fn() { console.log(arguments.callee); }
这个callee 就是 : function fn() { console.log(arguments.callee); }
15:字符串对象常用方法
15.1转换为字符串
a. + “” 2+ “” = “2” 2+”ab” = “2ab”
b. String() 转换为字符串
c. toString(基数) ; 基数就是进制
var txt = 10;
txt.toString(2) 二进制 1010
15.2获取字符位置方法
charAt,获取相应位置字符(参数: 字符位置)
charCodeAt获取相应位置字符unicode编码(参数: 字符位置)
var txt = “abcedf”;
比如, txt.charAt(4); 索引号一定是从0开始 返回的结果是 d
我们根据我们输入的 位数 返回相应的 字符 。
unicode编码 是我们字符的字符的唯一表示 。
案例:无缝滚动
<script>
var scroll = document.getElementById("scroll");
var ul = scroll.children[0];
var num = 0; //控制左侧值 left
var timer = null; // 定时器
timer = setInterval(autoPlay,20);
function autoPlay() {
num--;
//console.log(num);
num<=-1200 ? num = 0 : num;
ul.style.left = num + "px";
}
scroll.onmouseover = function() { // 鼠标经过大盒子 停止定时器
clearInterval(timer);
}
scroll.onmouseout = function() {
timer = setInterval(autoPlay,20); // 开启定时器
}
</script>
16:缓冲动画:
缓动动画公式:
一个盒子初始值 是 0 要走到 400 px 的位置
假如说,初始值 leader 0 target 400
box.style.left = xxxx + “px”
leader = leader + (target - leader ) /10 ;
offset家族##
1:offsetTop