javascript new 运算符

使用New运算符,实例化一个对象,都做了那些事情?

面试时被问到这个问题,虽然自己有自己的理解,但是感觉回答的不是很好,查阅了一下网上的资料,总结一下。

因为js对象都是相互关联的,也就是说,即使是一个空的对象,他的__proto__属性是指向Object的prototype

当我们使用new这个关键字来实例化一个对象时,要注意,new后面必须要是一个对象,并且这个对象要有一个名为construct的方法。首先我们可以模拟一下new的过程,我们写这样一个类:

function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype = {
    walk:function(){
        console.log("This is a 'walk' method!")
    }
}
//构造一个伪construct方法:
Person.construct  = function(){
    var o,Constructor = Person;
    o.__proto__ = Person.prototype;
    Constructor.apply(o,arguments);
    return o;
}
var person = new Person('Bill',18);

如上代码,我们构造了一个伪construct方法,当我们在使用new关键字实例化某个类对象时,首先会触发这个类(其实也是对象,我们称他为一个类)的construct方法。

在这个方法中,我们首先创建了以个空的对象o,并且我们拿到了我们的类(对象)的引用Constructor

接着我们将我们创建的空对象的__proto__指向我们的类的prototype,这样,我们首先实现了基于原型链的继承,接着使用apply方法,让o去调用Person方法,初始化了onameage属性,最后将o返回给我们创建的person变量。

至此,new的过程就结束了。person对象拥有两个自有属性nameage,以及一个继承的方法walk

meta&viewport

调研了一下meta标签,总结一些心得。

meta标签主要是提供了有关页面的一些描述信息和HTTP标题信息,例如一些有关网页的描述和关键字等等,这些信息是用户不可见的。

<meta http-equiv="Content-Type" Content="text/html; Charset=gb2312">

定义了HTML页面所用的字符集,这个方法只是在html4中存在,在html5中可以直接通过charset属性进行字符集的设置,还有一个有意思的用法,meta可以让你的页面跳转

<meta http-equiv="Refresh" Content="5; Url=http://www.baidu.com">

页面会在5s之后跳转到百度首页,上面两个用法提到的http-equiv 属性,实际上是服务器把名称/值对添加到发送给浏览器的内容头部。

<meta http-equiv="charset" content="iso-8859-1">

这时发送到浏览器的头部就应该包含:

content-type: text/html
charset:iso-8859-1

因为所有服务器至少会发送一个:

content-type:text/html

meta标签还有一个name属性,name属性的值有author(网站作者)、description(网站描述)、keywords(网站的关键字)、generator(编辑软件)、revised(软件的版本)。
keywords和description通常是帮助搜索引擎更好的获取你页面的内容,制定搜索的关键字。

ViewPort

如果一个在PC上正常浏览的网页,放到移动设备上,移动设备会默认先将网页放入一个虚拟的窗口中,这个窗口就是viewport。这个窗口会比手机的屏幕宽大,网页加载之后,再通过整体的缩放(或者是3:1,或者是2:1),来让网页整个现实到屏幕上。

通常经过这样的缩放,页面上的元素已经很难看清楚了,为了解决这样的问题,可以使用meta标签的viewport属性,来人为的制定viewport的大小,这样,就可以避免由于缩放引起的问题。、

<meta name="viewport" content="width=device-width,height=device-height,inital-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no;" />

这里面制定的宽度为设备宽度,高度为设备的高度,inital-scale表示初始的缩放比例,maximum-scale和minimum-scale分别代表用户能缩放的最大和最小的比例,user-scalable则指定了用户是否可以进行缩放。

通过这样的设置,使viewport和设备的屏幕大小一样,因此就不会产生缩放。元素也就能够看得清了。同时,在缩放比例为100%(也就是1,也就是没有进行缩放的时候),设备的像素和css的像素相等。

js原生方法的总结

Math对象

  1. Math.random():产生一个0~1之间的随机数。例:0.39049036731012166
  2. Math.floor(x):x可以是任意一个数值或者表达式,返回值是小于等于x,且最接近x的整数。例:Math.floor(Math.random()),返回0
  3. Math.ceil(x):对数字向上取整,返回大于或等于x的最接近的整数。
  4. Math.round(x):对数字进行四舍五入。
  5. Math.pow(x,y):计算x的y次方,若结果为虚数或负数则返回NaN。,若计算结果过大,返回Infinity。
  6. Math.sqrt(x):计算x的平方根。若x小于0则返回NaN。

Number方法

Number()方法将对象的值转化为数字:

true => 1; false => 0; "214214124" => 214214124;
new Date() => 1256657776588;
"214214124 123" => NaN

JSON对象

  1. JSON.stringify(o):用来序列化JavaScript对象,也就是将JavaScript对象转换为JSON字符串。
  2. JSON.parse(s):用来还原Json字符串为JavaScript对象。

Date对象

Date对象用来处理时间和日期,使用关键字new实例化Date对象。若

new Date():以当前日期作为初始值,实例化一个Date对象。也可以用如下的方式实例化Date对象:

//根据某个时间点创建一个时间戳(实例化一个Date对象)
new Date("month dd,yyyy hh:mm:ss");
new Date("month dd,yyyy");
new Date(yyyy,mth,dd,hh,mm,ss);
new Date(yyyy,mth,dd);

new Date(ms);  //需要创建的时间和GMT时间1970年1月1日之间相差的毫秒数。

常用get方法:

getDate() 从 Date 对象返回一个月中的某一天 (1 ~ 31)。
getDay() 从 Date 对象返回一周中的某一天 (0 ~ 6,分别对应周日~周一)。
getMonth() 从 Date 对象返回月份 (0 ~ 11)。
getFullYear() 从 Date 对象以四位数字返回年份。
getHours() 返回 Date 对象的小时 (0 ~ 23)。
getMinutes() 返回 Date 对象的分钟 (0 ~ 59)。
getSeconds() 返回 Date 对象的秒数 (0 ~ 59)。
getMilliseconds() 返回 Date 对象的毫秒(0 ~ 999)。
getTime() 返回 197011 日至今的毫秒数。

常用set方法(set方法会改变Date对象的时间点):

setDate() 设置 Date 对象中月的某一天 (1 ~ 31)。
setMonth() 设置 Date 对象中月份 (0 ~ 11)。
setFullYear() 设置 Date 对象中的年份(四位数字)。
setYear() 请使用 setFullYear() 方法代替。
setHours() 设置 Date 对象中的小时 (0 ~ 23)。
setMinutes() 设置 Date 对象中的分钟 (0 ~ 59)。
setSeconds() 设置 Date 对象中的秒钟 (0 ~ 59)。

还有一些其他的方法:

toString() 把 Date 对象转换为字符串。

js继承学习笔记

由一段代码印发的思考

function A(){}
var a = new A();
A.prototype = {x:3};
console.log(a.x);

想一下这段代码会输出什么,会输出3么,如果你的答案是3,那么恭喜你,下面的东西也是你需要的。

首先,正确的答案是undefined,不相信可以在控制台输出一下,结果一定是undefined,也就是说,a中并不存在一个 x属性,如果我们将代码改成这样,再看看结果是什么样子的:

function A(){}
var a = new A();
Object.prototype.x=3;
console.log(a.x);

这次再试一下,你会发现输出了3,是否找到问题了呢?

当我们在创建一个构造函数,也就是function A的时候,虽然没有规定他的prototype属性,但是JavaScript中明确指出,没一个JavaScript对象都和另一个对象关联,就是原型,换句话说,每一个JavaScript对象都有原型,那就证明A也是有原型的,而且原型值指向Object对象。

所以,当我们实例化一个A的对象a的时候,a会继承A的属性,而A的属性中并不存在自有属性,所以A的属性实际上就是继承自Object,因此,a的原型是指向Object的。

第一段代码,a的原型指向Object,这时我们设置A的prototype,也就是改变了A的原型,但是之前实例化的a的原型并没有继承A的属性,而是直接指向了Object,所以并不会受到影响。而Object的属性中也没有一个属性是x,JS中使用一个不存在的属性会返回一个undefined。

第二段代码,我们直接给Object的prototype添加一个x的属性,此时在a中就可以拿到x属性的值了。

如果我们将第二段代码中的

Object.prototype.x=3;

替换成

Object.x=3;

你会发现还是会输出同样的结果,其实js的继承,只有在查询属性的时候才会体现出来,查找一个对象的属性的时候,先会在对象的自有属性中进行查找,如果有就直接返回,如果没有会在对象的原型中查找,如果原型中也没有找到,就在原型的原型中查找,,,,这样传说中的原型链也就形成了。

有些时候我们在使用new方法创建对象的时候,比如new Date()这样的方式创建的对象,他的prototype指向的是DDate对象,而Date的prototype也继承自Object。

Javascript 笔试题集锦

1.有关this的使用

下面这段代码会输出什么?

var length = 10;
function fn() {
    console.log(this.length);
}
var obj = {
    length: 5,
    method: function(fn) {
        fn();
        arguments[0]();
    }
};
obj.method(fn, 1);

 答案:10,2;

 this是包含它的函数作为方法被调用时所属的对象。

 调用fn()方法的时候,默认是window对象,所以第一方法会输出10;

 使用arguments[0]()方法的时候,调用方法的对象是arguments,此时this指向arguments,我们传递了两个参数,所以输出结果是2

2.var和函数的提前声明

下面这段代码会输出什么?

function fn(a) {
    console.log(a);
    var a = 2;
    function a() {}
    console.log(a);
}
fn(1);

 答案:function a() {},2;

varfunction是会提前声明的,而且function还会优先于var,如果是这样,那上面的代码就等价于:

function fn(a) {
    var a;
    function a() {}
    console.log(a);
    a = 2;
    console.log(a);
}
fn(1);

这样就比较容易理解了,而且我们声明的变量对传入的参数进行了覆盖;

3、局部变量和全局变量

下面这段代码会输出什么?

var f = true;
if (f === true) {
    var a = 10;
}
function fn() {
    var b = 20;
    c = 30;
}
fn();
console.log(a);
console.log(b);
console.log(c);

 答案:10,报错,30;

首先我们先明确一下,只有在函数内定义的变量才是局部变量,在{...}内定义的变量并不一定就是局部变量。但是不管在哪里,如果变量没有通过关键字var声明的变量,都是全局变量。在使用一个没有定义的变量的时候会报错,但是如果使用了一个没有定义的属性的话,只会返回undefined

4、给基本类型数据添加属性

下面这段代码会输出什么?

var a = 10;
a.pro = 10;
console.log(a.pro + a);
var s = 'hello';
s.pro = 'world';
console.log(s + s.pro);

 答案:NaN,helloundefined;

给基本类型数据添加属性并不会报错,但是如果引用该属性,则会返回undefined,10+undefined会返回NaN,而字符串"hello"+undefined时,undefined会被转换成字符串,所以输出了helloundefined

5、判断一个字符串中出现次数最多的字符,并统计次数

下面这段代码会输出什么?

 答案1:hash table 方式:

var s = 'aaabbbcccaaabbbaaa';
var obj = {};
var maxn = -1;
var letter;
for(var i = 0; i < s.length; i++) {
    if(obj[s[i]]) {
        obj[s[i]]++;
        if(obj[s[i]] > maxn) {
            maxn = obj[s[i]];
            letter = s[i];
        }
    } else {
        obj[s[i]] = 1;
        if(obj[s[i]] > maxn) {
            maxn = obj[s[i]];
            letter = s[i];
        }
    }
}
alert(letter + ': ' + maxn);

 答案2:正则表达式方法:

var s = 'aaabbbcccaaabbbaaabbbbbbbbbb';
var a = s.split('');
a.sort();
s = a.join('');
var pattern = /(\w)\1*/g;
var ans = s.match(pattern);
ans.sort(function(a, b) {
    return a.length < b.length;
});;
console.log(ans[0][0] + ': ' + ans[0].length);

html标签语义化

语义化的理解

标签语义化,最开始接触到这个概念的时候理解的是对于开发者来说,让html代码的可读性更强,编写更规范,方便于扩展和维护。让开发的人一眼就知道这个标签里面放的什么东西。后面经过了解,标签语义化的另一个好处是使得HTML对爬虫和机器人更加友好,方便爬虫抓取网页的重要部分的内容,改进搜索引擎的优化。

html本身是一种语言,在没有css的帮助下,html自身的结构也能很好的展示内容(虽然这也是默认的css在起作用),i标签和b标签都可以达到强调的效果,但是w3c标准中还对这些标签的使用作出了明确的区分。但是大家使用的时候往往都是很随意的。比如页面中随意嵌套的div,不规范的嵌套规则,往往这样的页面,即使达到了你想要展示的效果,日后维护起来也是比较恶心的。

HTML中新添加的标签语义更加明显,像addressfooterheadernav等等,单从标签的名字就可以看出标签应该被用来做什么,同时,爬虫也会根据页面中的这些具有语义的标签去判断和抓取页面的相关内容,并分析关键字的权重,文档规范化了,就更加有益于搜索引擎获取你页面的关键信息。

让HTML和CSS各司其职,是一件美好的实情,HTML5的核心思想就是语义,所以我们只看标签表达的含义,而不是表现出来的样式,样式交给CSS就可以了,而不是为了实现某种表现效果而强行使用某个标签。

显然HTML5中并没有废除所有没有语义的标签,有些时候可能所有的语义标签都不能满足我们的需求,我们就可以考虑使用divspan这样的没有语义的标签来达到我们的目的,有一个原则,就是如果有比divspan更加合适的标签,我们就不适用他们。

之前也见过一些问题,说的是针对盲人阅读的时候,开发应注意什么,当时并没有理解这个问题,现在看,html的语义化也在一定程度上会帮助盲人阅读器去更好的解析页面的内容,从而帮助用户更好的去理解你的页面。总而言之,所有的规范或者标准的制定,都是为了保证通用行,让所有人开发出来的东西都可以被所有人使用。

语义化标签的积累

  1. figure:用于规定独立的流内容(图像、图标、照片、代码等)。块级元素,有自带的margin值。
  2. figcaption:与figure配套使用,用于定义figure元素的标题。块级元素。
  3. nav:标记导航,网页中的链接群,nav中通常是ul无序列表,面包屑链接用ol有序列表。
  4. article:表示的是一个文档、页面、应用或是网站中的一个独立的容器,可以嵌套使用(要体现部分与整体的关系)。
  5. section:区块定义标签(表示的是文档或是应用的一个一般的块)。
  6. aside:定义侧栏标签(表示一部分内容与页面的主体并不是有很大的关系,但是可以独立存在)。
  7. footer:页脚标签(与
    标签对应的标签),用他可以实现的功能有:附录、索引、版权页、许可协议等。

gulp学习记录

gulp是干嘛的?

先来看官网的介绍:

对我这种初学者来讲,看完之后并没有什么卵用,然而,在平时的使用中,似乎可以大概了解gulp做的事情,比如帮助我们在本地起一个服务器,帮助我们编译less、sass文件,压缩代码,合并、打包文件,图片压缩等等。

说白了,当我们使用gulp的时候,无非就是为了让它帮我们对代码做一些事情,然后放到服务器上跑起来。当然这个说法可能不准确,但是我感觉可以先这样去理解。

如何开始?

首先,我们可以试着用gulp起一个静态的服务器。

npm install gulp -g     //全局安装gulp
npm install gulp --save-dev //接着在你的项目文件夹下面安装gulp
//--save-dev 是为了将gulp信息添加到你的package.json中,如果你是在一个空的项目中开始的,那你可能需要先执行npm init,按照提示,生成一个新的package.json文件。

上述步骤完成之后,我们就可以开始使用gulp了。

如何使用?

如果你想让gulp帮你去做一些事情,也就是完成一些特定的任务,我们就要创建一系列任务让gulp帮我们去完成。

在你的项目文件夹(根)下,创建一个gulpfile.js的文件,我们将会在这里创建任务,首先需要引入gulp:

var gulp = require('gulp'),  

要完成某些特殊的任务,我们需要载入不同的依赖文件,例如,我们需要编译我们的less文件,就需要安装gulp-less这个包。使用如下命令安装并并将包信息保存到package.json中:

npm install gulp-less --save //如需其他的依赖包,安装的方式也是一样的

现在我们来创建一个任务来编译我们的less文件:

//用gulp.task()来创建一个任务。
gulp.task(‘less’, function () {
//用gulp.src()来定义一个或者多个文件来源,下面的写法就是选择所有的less文件
return gulp.src(‘styles/*.less’)
//pipe()是对文件做的操作,我们可以把pipe()处理的过程理解为一个车间的流水线,原料由src()提供,经过不同的加工步骤(pipe)的处理后再放回流水线上。
.pipe(less())
//gulp.dest()用来设定目的地的路径,我们这里就是指的css文件输出的路径。
.pipe(gulp.dest(‘/styles’));
});

写完了上述方法,我们的任务文件应该是这样的:

var gulp = require('gulp');
var less = require('gulp-less');

gulp.task('less', function () {
  return gulp.src(config.app+'/styles/*.less')
    .pipe(less())
    .pipe(gulp.dest(config.app+'/style'));
});

首先在项目内新建一个文件夹styles,之后再文件夹中创建一个main.less文件,并添加一些代码:

body{
  padding: 0;
  margin: 0;
}

之后我们执行gulp命令,启动任务:

gulp less

你会发现,你的styles文件夹下多出了一个main.css的文件,正式main.less编译之后的结果。

有没有感觉gulp并没有那么高大上了呢?其他的任务也都是一样的原理。分享一个比较有用的文章:

gulp使用指南

flex布局归纳

Flexbox布局旨在提供一个更佳有效的布局方式,更好的控制项目的对齐和自由分配容器空间,即使它们的大小是未知的或动态的。flex布局让从前的“盒子”具有了弹性,让大小可变,方向可变,顺序可变,可以伸展,也可以收缩。

css各种属性知识总结

有关margin的值

margin属性规定了元素的外边距,这个属性可以有1~4个值(padding属性的赋值规则也是一样的),其作用和写法如下:

margin:10px;  //元素的上、下、左、右边距都为10;
margin:10px 20px;  //元素的上、下边距为10px,左、右边距都为20px;
margin:10px 20px 30px; //元素的上边距是10px,左边距和右边距为                         20,下边距为30;
margin:10px 20px 30px 40px;  //元素的上、下、左、右边距分别为           10、20、30、40px

margin属性存在边距合并的问题,块级元素的上下边距会合并(当两个垂直边距相遇的时候,选取最大的值)。当元素时浮动定位的时候,左右的边距并不会合并。

经常会出现这样一种情况,存在一个父元素div,想让这个父元素中的子元素和这个父元素的顶部有一些距离,就像下面的代码:

然而结果可能并不像我们想想的样子:

根据规范,一个盒子如果没有上补白(padding-top)和上边框(border-top),那么这个盒子的上边距会和其内部文档流中的第一个子元素的上边距重叠。在例子里面可以理解为chass=".middle"的div与class='firstChild'的div的上边距重合,这会导致父元素也被子元素的margin挤了下来。

对于何时使用margin,何时使用padding?

我的理解是,margin既然作为外边距(元素周围生成额外的空白区),他应该是分离同级的元素,让他们之间存在一些间隔的空隙。padding为内边距,感觉叫“补白”更贴切一些,顾名思义,是为了让容器元素和子元素之间存在一些空隙。所以上边的例子更加适合使用padding而不是使用margin。
还有当不需要讲margin合并时,可以使用padding代替。


有关position的值

static

position的默认属性,没有特殊的规则,此时会忽略元素的lefttoprightbottomz-index属性,元素正常的出现在文档流中。

relative

相对定位,相对于该元素position属性为static时的位置去定位,根据规定的lefttoprightbottom属性值来对元素的位置进行修正。

absolute

绝对定位,元素相对于static定位以外的第一个父元素进行定位,可以使用lefttoprightbottom等属性对元素位置进行修正。并且如果绝对定位的元素的位置已经存在了元素,并且这个元素时relative或者static定位,那么决定定位的元素会出现在上层的位置。如果该元素时absolute或者fixed定位,那么他们的层级由他们在文档中出现的顺序决定

fixed

相对于浏览器窗口的定位,也可以称为固定定位,也可以根据规定的lefttoprightbottom属性值来对元素的位置进行修正。

inherit

继承父元素的定位信息(position的值)。

有关border-radius的取值

border-radius规定元素的圆角属性,其写法如下:

border-radius:10px; //四个角由四个圆弧代替,每个圆弧的半径相同,都为10px
border-radius:10px 10px 5px 5px; //从左上角开始,圆弧的半径分别为10,10,5,5像素
border-radius:10px 10px 5px; //从左上角开始,圆弧的半径分别为10,10,5,10像素
border-radius:10px 10px 10px 10px /5px 5px 5px 5px; 
//将四个圆角继续分解称为四个垂直方向的圆弧和四个水平方向的元素,则这八个值中的前四个代表水平方向上的四个圆弧的半径(从左上角开始),后四个值代表垂直方向上的圆弧的半径。

有关bacakground的取值

background用来设置所有背景属:

background-color:red,#ffffff,rgba(0,0,0,0.7) //规定背景颜色
background-position//规定如何定位背景图像。可以通过百分比取值,如:x% y%;或用像素取值,如:10px(水平) 10px(竖直);这两种方式均基于元素左上角点。同时还可以使用预定的组合值,如:top center(第一个值代表竖直方向,可选值有top、center、bottom,第二个值代表水平法相,可选值有left center right)。
background-size:
//规定背景图片的尺寸。可以使用px:100px 100px;百分比:100%(宽度) 100%(高度),图片可能会变形;cover,将图片扩展至足够大,覆盖整个背景区域,图像不会发生形变;contain:将图片扩展至足够大,使图片宽度和告诉适应内容区域。
background-repeat//规定是否重复背景图片,以及如何重复。no-repeat/repeat(水平和竖直方向)/repeat-x/repeat-y/inherit(继承父元素)。
background-origin//用来规定background-position属性从哪里开始定位:padding-box:相对于内边距来定位,原点在左上角(不包括border的宽度);border-box:相对于边框来定位,原点在左上角(包括border的宽度);content-box:相对于content区域定位(不包括padding的宽度)。
background-clip//用来规定背景的显示范围,也就是裁剪的范围:border-box/padding-box/content-box。
background-attachment//规定背景图片是否随着元素内的元素滚动而滚动。scroll/fixed/inherit。
background-image//设置背景图片的路径。url('URL')。默认值为none。

有关box-shadow的取值

添加一个或多个阴影:

box-shadow:h-shadow v-shadow blur spread color inset;

分别代表:水平阴影的位置(允许负值),竖直阴影的位置(允许负值),模糊距离(可选),阴影尺寸(可选),阴影颜色,将外部阴影改为内部阴影。


有关float的取值

css3动画

在之前实习的时候玩过一些CSS3的动画效果,感觉还是挺有意思的(除了有点麻烦),分享一些学习经验,也是对自己学习的一个总结。

css3中的主要模块有选择器框模型背景边框(圆角和阴影很常用),文本效果(好像不是很常用),2D/3D转换动画多列布局(好像也不常用)等等。在css3的背景中,已经可以设置背景的尺寸了,也可以通过background-origin属性设置背景图片的定位区域。

图片

当我们分别设置了这些值得时候,背景就会出现在不同的位置了。下面我们就可以进入正题了。

2D转换

关于2D转换,顾名思义,转换是在2D平面上进行了,这里主要介绍以下三种常用方法:

translate()  //移动元素
transform: translate(50px,100px);  //把元素在x轴方向移动50px,在y轴方向移动100px;
rotate()   //旋转元素
transform: translate(30deg);  //把元素旋转30度(方向试一试就知道了)
scale()   //改变元素的尺寸
transform: scale(0.5,4);   //把元素的宽改成原来的0.5,高改为原来的4倍

2D转换的方法在实现动画效果的时候是很常用的。

3D转换

rotateX() //将元素围绕其 X 轴以给定的度数进行旋转
rotateY() //将元素围绕其 Y 轴以给定的度数进行旋转

好了,了解了上面的基本方法,我们实现一个简单的动画效果。先看html代码图片下载,图片下载

<img class="img baby" src="baby.png">
<img class="img ballon" src="ballon.png">

CSS代码:

.img{
    position:absolute;
    left:50px;
}
.baby{
    top:86px;
}

现在页面上应该就是下面这个样子了。

图片

下面我们看一下怎么让这个图片动起来:

@keyframes规则

想要了解css3动画,要先简单介绍一下@keyframes规则,它用于规定动画的过程,在@keyframes中规定某项 CSS 样式,就能创建由当前样式逐渐改为新样式的动画效果(@keyframes浏览器支持)。比如这样:

@keyframes changeBg
{
from {background: red;}
to {background: yellow;}
}
div
{
animation: changeBg 5s;
}

复制代码运行一下就能看到效果了。同时我们还可以这样写:

@keyframes changeBg
{
    0%   {background: red;}
    25%  {background: yellow;}
    50%  {background: blue;}
    100% {background: green;}
}

这样我们就可以多次的改变样式了,同时我们还可以改变多个样式:

@keyframes changeBg
{
    0%   {background: red; left:0px; top:0px;}
    25%  {background: yellow; left:200px; top:0px;}
    50%  {background: blue; left:200px; top:200px;}
    75%  {background: green; left:0px; top:200px;}
    100% {background: red; left:0px; top:0px;}
}

刚才我们实际上进行了两部分行为,一部分是定义动画过程,一个是让元素应用动画效果。下面简单再完善一下如何使用动画:

animation:name duration function delay iteration-count direction 
//当给元素定义这个属性的时候,就是要对这个元素使用动画效果了,这个属性包括6个值,分别表示:
动画的名称(对应@keyframes),
动画的执行时间(这个时间代表动画执行的总时间,而不是阶段时间,单位是毫秒),
动画的速度曲线(匀速linear、低速-加快-变慢ease、以低速开始ease-in、以低速结束ease-out、以低速开始和结束ease-in-out),
规定动画开始之前的延迟时间,
规定该动画播放的次数(数字n,或者无限次播放infinite)

掌握了这些之后,我们就可以为我们之前的html添加动画效果了,首先我们定义一下动画过程。

@-webkit-keyframes ballon{
    from{
        -weblit-transform:rotate(-30deg);
        -weblit-transform-origin:center bottom;
    }
    to{
        -weblit-transform:rotate(30deg);
        -weblit-transform-origin:center bottom;
    }
}

动画过程定义好了之后,我们就可以使用了:

.ballon{
    -webkit-animation:ballon 2s linear 0s infinite alternate
}

这样一个简单的气球摆动的动画就完成了,复杂的动画也都是通简单的动画组合而成的。在使用css3写动画的时候,注意要先写出静态的页面,通常的动画效果只是在页面加载完成后执行一次,这种情况下我们需要先完成动画页面的最终样式的布局,在此基础上添加动画效果(因为动画执行完成之后会回到它的默认状态)。

在制作复杂的组合动画,或者单次动画的时候,尽量使用百分比方式定义动画,这样更容易掌控整个动画过程;当动画的行为比较简单且需要重复展示的时候(比如云彩的飘动等),可以使用from...to的方式定义动画。


还有一个小技巧,之前我们介绍过动画开始之前可以设置延迟时间,但是当动画行为过多的时候,延迟时间会变得复杂且难以管理,这时我们可以使用另一种方式,我们首先要计算出页面所有动画执行完成所需要的时间,假设是10s,其中某一个动画在5s的时候才开始执行,我们可以在使用这个动画的时候就规定这个动画的时间为10s,但是在前50%我们什么都不去做,这样就实现了延迟的效果了。