情人节动画笔记

来源:互联网 发布:每日推荐软件 编辑:程序博客网 时间:2024/03/29 02:29

github: https://github.com/miyiyiy/Tanabata_Demo

慕课网教程--H5+JS+CSS实现情人节动画

1. 页面布局

总共3幅图,实现横向布局,整个效果以小男孩为前提,在3个主题页面中切换并在每个主题页面中会有不同的效果呈现

页面滚动和小男孩走动,通过两者速率变化,产生视觉差,形成总体效果

页面是一个横向布局,包含3个主题,页面之间无缝拼接,实现滚动

布局上很好处理,我们做3个块级元素,每一个块元素代表一个主题页面容器节点。然后设置一个父容器是3个块元素的宽,通过float处理,这样就形成了一个横向的3个无缝拼接的页面

页面布局结构如下:

<ul class='content-wrap'>    <!-- 第一副画面 -->    <li> 页面1 </li>    <!-- 第二副画面 -->    <li> 页面2 </li>    <!-- 第三副画面 -->    <li> 页面3 </li></ul>

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

  • 移动父容器,改变父容器的坐标
  • 移动每一个子容器的坐标
移动父容器简单很多,只需要改变父容器X轴的坐标就可以了。如果父容器中子元素有很多的话,那么我们会考虑第二种算法,可以做成动态加载

改变坐标的处理的两种方法:传统的top、left坐标,CSS3中的transform属性。

传统的就是修改元素style是坐标属性,这个没什么好说的,使用简单,一般都需要配合定时器使用。

CSS3引入了一个新的属性transform,transform 属性向元素应用 2D 或 3D 转换,该属性允许我们对元素进行旋转、缩放、移动或倾斜。其中会有一个值translate3d(x,y,z) 是用来控制元素的位置在页面上的三轴的位置的,translate3d这里指明了3d就是启用了3d加速,也就是启动GPU来处理,性能更强

transition 可以实现简单的动画属性

这里需要特别注意的就是:

transform属性是静态属性,不是动画属性,一旦写到style里面,将会直接显示作用,无任何变化过程

简单的一句话描述就是

通过设置transition的一些参数,让translate3d这个属性发生变化

具体实现见Swipe中的scrollTo()


2. 小男孩的动画

小孩男走路是贯穿三个主题页面,因此小男孩在布局上不能嵌入任何一个页面内,否则无法切换到下一个页面中了。所以最终小男孩的布局与页面根节点属于并列结构

小男孩的布局很简单,但是要注意3个问题:

  • 小男孩其实只会在当前页面移动,所以是相对父级#content的范围
  • 小男孩的布局处理,因为小孩男是合成的"雪碧图",通过坐标取图,因此不能用CSS处理自适应布局了,需要动态调整//在圣诞节动画中有提到自适应处理
  • 采用动画的元素需要设置绝对定位
小男孩总是会沿着中间那个路线走动。因为背景图是靠百分比控制的,会随着分辨率的变化而变化。但是人物是固定的尺寸是无法变化的(合成图的关系),这里只能通过JS动态调整

小男孩的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-imagebackground-repeatbackground-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() {});


3.异步编程处理

通过$.Deferred处理过的代码,很明显没有了回调的嵌套,虽然代码量看起来多了点,但是实际上,每一个代码执行部分都被封装了起来,只留了Deferred的接口处理了,等于是我们把执行的流程控制交给了Deferred,这样的好处就是我们在写嵌套函数的时候,可以用deferred提供的管道风格编写同步代码了

dtd.then(function() {   //操作1}).then(function() {   //操作2}).then(function() {  //操作3})

这里要了解3个步骤

var dtd = $.Deferred();  //创建dtd.resolve();          //成功dtd.then()              //执行回调

4. 视差效果

以小男孩走路变化,页面就跟着变化,两个元素用不同的速率变化就会产生视觉差的效果,感觉人物就是走了几个页面

其中需要注意

  • 小男孩的走路区间只是一个页面单位,相对点是父级的div
  • 页面滚动只有二个页面单位,因为本身会占据一个

注意以上这两点主要是为了设置比例的问题

  • 小男孩如果走到中间位置,那么比例是0.5 换算下就是  0.5*页面宽度
  • 页面要到中间位置就是,比例是1,换算就是 1*页面宽度
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);})

5. 太阳动画、云动画

CSS3的animation会有8个属性去定义一个动画的一些参数

animation-name
规定要绑定的keyframes的名称,随便你取,不过为了日后维护的方便,建议取一个跟动作相关名称相近的名称比较好
animation-duration
规定完成这个动画所需要的时间
animation-iteration-count
动画播放次数,默认值为1,infinite为无限制,假如设置为无限制,那么动画就会不停地播放
元素的布局上,我都是保留的原尺寸,如果需要自适应,单独可以用百分比控制,通过background-size 一般可以设置 100% 100%的方式平铺元素,这样设置后图片就能自适应大小缩放了

6. 开门关门--开灯关灯

开门关门的效果比较简单,用transition插件可以实现

在实现的时候还需要注意几个问题

  • 开关门是2组动画,需要2组transition的实现
  • 开关门是否完成,是需要监听2个动画是否完成才可以
  • 为了支持线性编程的逻辑,需要通过Deferred改善代码

开门的left的坐标是往反向变化,所以变化的值是:

  • 左边0%到-50%  
  • 右边50%到100%

关门的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的随机处理、最终值的计算等等

执行的流程:

  • getImagesName随机6张图片,snowflakeURl定义一个地址的范围
  • createSnowBox创建雪花元素的节点,并且增加一个snowRoll的样式,也就是旋转的关键帧实现
  • 定时器设置200ms不断的生成雪花对象,计算出3个属性的初始值,通过createSnowBox创建雪花元素,并且附上初始值,然后执行transition附上最终值,执行动画
  • 动画结束后执行$(this).remove()  删除这个对象


8.音乐播放

var audio = new Audio(url);   //创建一个音频对象并传入地址audio.loop  = loop ||  false; //是否循环audio.play(); //开始播放


END