github: https://github.com/miyiyiy/Tanabata_Demo
慕课网教程--H5+JS+CSS实现情人节动画
1. 页面布局
总共3幅图,实现横向布局,整个效果以小男孩为前提,在3个主题页面中切换并在每个主题页面中会有不同的效果呈现
页面滚动和小男孩走动,通过两者速率变化,产生视觉差,形成总体效果
页面是一个横向布局,包含3个主题,页面之间无缝拼接,实现滚动
布局上很好处理,我们做3个块级元素,每一个块元素代表一个主题页面的容器节点。然后设置一个父容器是3个块元素的宽,通过float处理,这样就形成了一个横向的3个无缝拼接的页面
页面布局结构如下:
var config={//整体布局配置
keepZoomRatio:false,//界面比,设成true保持固定比
layer:{//界面宽度和高度
'width':'100%',
'height':'100%',
'top':0,
'left':0
},
}
if(config.keepZoomRatio){
var proportionY=900/1440;
var screenHeight=$(document).height();
var zoomHeight=screenHeight*proportionY;
var zoomTop=(screenHeight-zoomHeight)/2;
config.layer.height=zoomHeight;
config.layer.top=zoomTop;
}
function Swipe(contianer)//界面设置
{
var element=contianer.find(':first');
var swipe={};
//li页面数量
var slides=element.find('>');
//获取容器尺寸
var width=contianer.width();
var height=contianer.height();
element.css({
width:(slides.length*width)+'px',
height: height+'px'
});
//设置每个li页面的宽度
$.each(slides,function(index){
var slide=slides.eq(index);
slide.css({
width : width+'px',
height: height+'px'
});
});
swipe.scrollTo=function (x,speed) {//实现页面的滚动效果
/* body... */
//执行动画移动
element.css({
'transition-timing-function':'linear',
'transition-duration':speed+'ms',
'transform':'translate3d(-'+(x)+'px,0px,0px)'
});
return this;
};
return swipe;
}
页面的横向布局我们已经实现好了,那么如何实现页面与页面之间的切换呢?
一般来说要根据布局的结构来,大体有2种:
改变坐标的处理的两种方法:传统的top、left坐标,CSS3中的transform属性。
传统的就是修改元素style是坐标属性,这个没什么好说的,使用简单,一般都需要配合定时器使用。
CSS3引入了一个新的属性transform,transform 属性向元素应用 2D 或 3D 转换,该属性允许我们对元素进行旋转、缩放、移动或倾斜。其中会有一个值translate3d(x,y,z) 是用来控制元素的位置在页面上的三轴的位置的,translate3d这里指明了3d就是启用了3d加速,也就是启动GPU来处理,性能更强
transition 可以实现简单的动画属性这里需要特别注意的就是:
transform属性是静态属性,不是动画属性,一旦写到style里面,将会直接显示作用,无任何变化过程
简单的一句话描述就是
通过设置transition的一些参数,让translate3d这个属性发生变化
2. 小男孩的动画
小孩男走路是贯穿三个主题页面,因此小男孩在布局上不能嵌入任何一个页面内,否则无法切换到下一个页面中了。所以最终小男孩的布局与页面根节点属于并列结构
小男孩的布局很简单,但是要注意3个问题:
小男孩的top坐标值 = 中间路段的中间坐标值 - 小男孩的高度
var pathY=function () {
var data=getValue('.a_background_middle');
return data.top+data.height/2;
}();
var $boy=$('#boy');
var boyHeight=$boy.height();
var boyWidth=$boy.width();
//修正小男孩的正确位置
//路的中间位置减去小孩的高度 25是一个修正值
$boy.css({
top:pathY-boyHeight+25
});
CSS Sprites在国内很多人叫
CSS
精灵,其实这个技术不新鲜,原理就是:
靠不断的切换图片让人感觉视觉上不断在变化
传统的就是靠定时器不断去改变一个元素的background-image属性了,简单的来说就是靠不断的替换图片,但是值得注意的问题就是图片如果很多,加载会比较慢,会占用大量网络资源
大多数的做法就是把图片都合成一张大图再利用CSS的以下属性
background-image background-repeat background-position
组合进行背景定位,background-position可以用数字精确的定位出背景图片的位置
for example:
.slowWalk
{
/* 填入动画 式规则 */
/* 规定@keyframes动画的名称 */
-webkit-animation-name: person-slow;
/* 规定动画完成一个周期所花费的秒或毫秒。默认为0 */
-webkit-animation-duration: 950ms;
/* 规定动画被播放的次数。默认是1,infinite: 循环播放; */
-webkit-animation-iteration-count: infinite;
/* 动画切换的方式是一针一帧的改变 */
-webkit-animation-timing-function: steps(1,start);
-webkit-animation-play-state: running;//人物的状态控制
}
@-webkit-keyframes person-slow{
0%{
background-position: -0px -291px;
}
25%{
background-position: -602px -0px;
}
50%{
background-position: -302px -291px;
}
75%{
background-position: -151px -291px;
}
100%{
background-position: -0px -291px;
}
}
人物走动:
$boy.transition({
'left': $("#content").width() + 'px',
}, 10000, 'linear', function() {});
通过$.Deferred处理过的代码,很明显没有了回调的嵌套,虽然代码量看起来多了点,但是实际上,每一个代码执行部分都被封装了起来,只留了Deferred的接口处理了,等于是我们把执行的流程控制交给了Deferred,这样的好处就是我们在写嵌套函数的时候,可以用deferred提供的管道风格编写同步代码了
dtd.then(function() { //操作1 }).then(function() { //操作2 }).then(function() { //操作3 })
这里要了解3个步骤
var dtd = $.Deferred(); //创建
dtd.resolve(); //成功
dtd.then() //执行回调
4. 视差效果
以小男孩走路变化,页面就跟着变化,两个元素用不同的速率变化就会产生视觉差的效果,感觉人物就是走了几个页面
其中需要注意
注意以上这两点主要是为了设置比例的问题
var config={//增加前面配置
setTime:{
walkToThird:6000,
walkToMiddle:6500,
walkToEnd:6000,
walkTobridge:2000,
bridgeWalk:2000,
walkToShop:1500,
walkOutShop:1500,
openDoorTime:800,
shutDoorTime:500,
waitRotate:850,
waitFlower:800}
}
boy.walkTo(config.setTime.walkToThird,0.6).then(function(){
scrollTo(config.setTime.walkToMiddle,1);
return boy.walkTo(config.setTime.walkToMiddle,0.5);
})
CSS3的animation会有8个属性去定义一个动画的一些参数
animation-name
规定要绑定的keyframes的名称,随便你取,不过为了日后维护的方便,建议取一个跟动作相关名称相近的名称比较好
animation-duration
规定完成这个动画所需要的时间
animation-iteration-count
动画播放次数,默认值为1,infinite为无限制,假如设置为无限制,那么动画就会不停地播放
元素的布局上,我都是保留的原尺寸,如果需要自适应,单独可以用百分比控制,通过background-size 一般可以设置 100% 100%的方式平铺元素,这样设置后图片就能自适应大小缩放了
6. 开门关门--开灯关灯
开门关门的效果比较简单,用transition插件可以实现
在实现的时候还需要注意几个问题
开门的left的坐标是往反向变化,所以变化的值是:
关门的left还原到0%与50%即可。
在开门的同时会有一个灯光的变化,开门灯亮,关门灯灭,这个动作本身不难,主要是配合开关门之后的一个效果,需要依赖开关门的事件回调
由于开关门的代码封装了Deferred,很容易添加这个效果的逻辑
代码实现部分:
//开门
openDoor().then(function() {
//开灯
lamp.bright();
})
//关门
shutDoor().then(function() {
//灯灭
lamp.dark();
});
通过融入Deferred对象,我们可以很好的控制这个逻辑了,在then中直接书写回调后的开灯效果了。
其他功能类似、不赘述
animation-fill-mode的属性,forwards的意思就是保留在最终的状态
7.飘花实现
实现原理:
通过定时器调用JS代码不断的动态创建雪花节点,随机选择一个图片作为其背景,赋予三个初始的样式属性top,left与opacity,通过transition动画过度的方式执行这3个属性的动画变化。整个原理其实也是很简单的,主要涉及了一些细节的问题:例如元素的创建、图片的随机、开始的left与opacity的随机处理、最终值的计算等等
执行的流程:
8.音乐播放
var audio = new Audio(url); //创建一个音频对象并传入地址 audio.loop = loop || false; //是否循环 audio.play(); //开始播放
END