动画效果在前端知识体系里面属于特殊的存在
有的前端工作基本不需要动画效果,比如 后台管理系统
有的前端工作基本全是动画效果,比如广告H5页面
俗话说的好:技多不压身
多点技能在以后的工作中 总会更有竞争力
下面就是跟着大帅老师学习动画的自身的体验和学习记录
如果您觉得我的文章对您有所帮助,请不吝啬的给个赞,谢谢
先看动画效果
目标网站是再国外,网速各方面条件可以不是太好,目标网站预览有问题的,直接看我的demo地址
相关链接整理
- 1.初始项目地址-可以用这个初始项目跟着视频一起敲代码
- 2.教学视频地址
- 3.模仿对象的网址
- 4.PIXI-官方地址
- 5.PIXI-中文文档-别人翻译的
- 6.gasp-官方地址
- 6.gasp-中文文档-别人翻译的
- 7.本文完整代码
- 8.我写完后的预览地址
目标网页动效的信息提取
这次要模仿的动效是一个自行车刹车的动效,我们先看看从目标网页能得知这个动效用了哪些框架,或者什么有用的信息
- 通过控制台下面的 页面元素得知 使用的
canvas我们目前只是知道它用的是canvas,但具体有没有用框架,或者用了什么框架,我们是不得而知,我们这里选用PIXI,当前你也可以选择 其他的你熟悉的 - 通过 文件内容,可以得知 使用动效框架
gasp找不到也也没有关系,你也可以选择你所擅长的任何熟悉的动画框架;
框架熟悉
PIXI
-
网址:pixijs.com/
-
简介:一个超快的2D渲染引擎
-
下面用到的API
# 1. 创建一个应用 【你可以理解为创建一个 canvas元素】 let app = new PIXI.Application({具体配置}) # 2.将应用的视图挂载在页面的某个元素 才会展示【你可以理解为将canvas元素绑定到 页面元素上】 document.querySelector(selector).appendChild(app.view) # 3.资源加载器;可以加载 图片 音视频文件 let loader = new PIXI.Loader() # 4.挂载资源 loader.add(imageName,imagePath) # 5. 资源加载回调函数 loader.onComplete.add(()=>{ }) # 6.创建一个容器【你可以理解为 一个div 父组件,里面可以加载很多字元素】 let actionButton = new PIXI.Container() # 7.创建精灵【你可以理解为 一个元素】 let sp new PIXI.Sprite(this.loader.resources['上面资源的key'].texture) # 8.可以将精灵 加到 容器上 【你可以理解为div子元素 添加到父元素上,才能展示】 actionButton.addChild(sp) # 9.设置精灵或者容器的 属性【你可以理解为设置 元素的 宽高 等属性】 sp.属性 = 值 # 10. 给精灵添加监听事件 actionButton.on('mousedown',()=>{}) // 相当于 监听 元素的事件
gasp
-
简介:是一个动画的库
-
案例中用到的API
# 1. to 代表达到某个 动效,可设置相关配置 gsap.to(btnCircle.scale,{duration:1,x:1.3,y:1.3,repeat:-1}) / btnCircle.scale 对元素的 scale 进行动效 duration:时长 repeat:-1 无限循环 # 2.不间断的调用 loop 事件 gsap.ticker.add(loop) # 3.移除 loop 事件 gsap.ticker.remove(loop)
逐步分解
准备环境的搭建
VSCode 预览插件
使用 Live preview(微软的那一款)
基本环境
基本环境直接使用大帅老师提供的初始环境
大家可以foke 下来,跟着视频一一来实现
第一步 - 按钮的波纹效果
先看效果
思路
-
其实就是一个外面的橙色的环形的圈,把它 从缩小状态 再慢慢的一步一步的 成比例变大
-
再配合着透明度随着缩放比例变大而便小
具体核心代码
show(){
// 1.创建 “按住” 的按钮
let actionButton = this.createActionButton()
this.stage.addChild(actionButton)
}
/**
* 创建 “按住” 的 按钮
*
*/
createActionButton(){
// 4. 按住的动效【场景 和 容器的 使用】
// 容器可以理解为 div 场景只有一个 理解为body
// pivot 圆心的点
let actionButton = new PIXI.Container()
let btnImage = this.helpGetSprite({key:'btn.png'})
let btnCircle = this.helpGetSprite({key:'btn_circle.png'})
let btnCircle2 = this.helpGetSprite({key:'btn_circle.png'})
actionButton.addChild(btnImage)
actionButton.addChild(btnCircle)
actionButton.addChild(btnCircle2)
// 5.修改 坐标
btnCircle.pivot.x = btnCircle.pivot.y = (btnCircle.width/2)
btnCircle2.pivot.x = btnCircle2.pivot.y = (btnCircle2.width/2)
btnImage.pivot.x = btnImage.pivot.y = (btnImage.width/2)
// to 到达某个动作;duration 时长 x y 变成什么样子 repeat 循环
btnCircle.scale.x = btnCircle.scale.y = 0.8
gsap.to(btnCircle.scale,{duration:1,x:1.3,y:1.3,repeat:-1})
gsap.to(btnCircle,{duration:1,alpha:0,repeat:-1})
// 配置可以交互
actionButton.interactive = true
actionButton.buttonMode = true
return actionButton
}
第二步 - 刹车的动效
先看效果
思路如下
- 给 “按住”的按钮添加 点击和放开的事件,点击的事件触发
- 将车把手 以一定的角度 旋转以达到 刹车的效果
- 当点击事件释放,那么就恢复原样就好了
核心代码如下
show(){
// 1.创建 “按住” 的按钮
let actionButton = this.createActionButton()
// 1.1 添加交互事件:mousedown 鼠标点击事件
actionButton.on('mousedown',()=>{
// 按下刹车的动效
gsap.to(bikeLeverImge,{duration:.6,rotation:Math.PI/180*-30})
})
// 1.2 mouseup 鼠标释放
actionButton.on('mouseup',()=>{
// 刹车恢复原位的动效
gsap.to(bikeLeverImge,{duration:.6,rotation:0})
})
// 2.创建车身的容器和车身
let {bikeContainer,bikeLeverImge} = this.createBikeContainer()
// 注意:addChild 有先后顺序,先addChild 的 图层在下面
this.stage.addChild(bikeContainer)
this.stage.addChild(actionButton)
}
/**
* 创建车身和把手的容器
*/
createBikeContainer(){
// 自行车整体的容器;你可以理解为一个大的容器
let bikeContainer = new PIXI.Container()
bikeContainer.scale.x = bikeContainer.scale.y = 0.3
// 自行车最下面的轮子+车身的图片=>在图层的最下面,所以先 addChild
let bikeImge = this.helpGetSprite({key:'brake_bike.png'})
bikeContainer.addChild(bikeImge)
// 自行车 按刹车的把柄
let bikeLeverImge = this.helpGetSprite({key:'brake_lever.png'})
bikeContainer.addChild(bikeLeverImge)
bikeLeverImge.pivot.x = 455;
bikeLeverImge.pivot.y = 455;
bikeLeverImge.x = 722;
bikeLeverImge.y = 900;
// 自行车的龙头
let bikeHandlerbarImge = this.helpGetSprite({key:'brake_handlerbar.png'})
bikeContainer.addChild(bikeHandlerbarImge)
return {bikeContainer,bikeLeverImge}
}
第三步 - 粒子效果
先看动效
思路如下
-
点击刹车的时候,触动事件
-
在页面上随机颜色创建几个小球,小球从上到下运动(沿着Y轴),速度越来越快,随着速度变快,变成了一条线
-
不断的重复这个运动
-
至于小球的从上到下沿着某个角度下来,只需要将小球的所在容器旋转角度
-
当松开刹车的时候,小球恢复原样,保持不动
代码如下
show(){
// 1.创建 “按住” 的按钮
let actionButton = this.createActionButton()
// 1.1 添加交互事件:mousedown 鼠标点击事件
actionButton.on('mousedown',()=>{
// 按下刹车的动效
gsap.to(bikeLeverImge,{duration:.6,rotation:Math.PI/180*-30})
// 粒子效果停止
pause()
})
// 1.2 mouseup 鼠标释放
actionButton.on('mouseup',()=>{
// 刹车恢复原位的动效
gsap.to(bikeLeverImge,{duration:.6,rotation:0})
// 粒子效果开始
start()
})
// 2.创建车身的容器和车身
let {bikeContainer,bikeLeverImge} = this.createBikeContainer()
// 注意:addChild 有先后顺序,先addChild 的 图层在下面
this.stage.addChild(bikeContainer)
this.stage.addChild(actionButton)
// 3. 创建粒子
let {particleContainer,start,pause} = this.createParticleContainer()
this.stage.addChild(particleContainer)
// 初始的时候:默认开启粒子效果
start()
}
/**
* 创建粒子 和 粒子容器的设置
*/
createParticleContainer(){
// 创建粒子的容器
let particleContainer = new PIXI.Container()
// NOTE:重点:将容器旋转一定的角度;那么里面的粒子就不需要 计算按照一定的角度 下降,只需要沿着 Y 轴运动即可
particleContainer.pivot.x = window.innerWidth/2
particleContainer.pivot.y = window.innerHeight/2
particleContainer.x = window.innerWidth/2
particleContainer.y = window.innerHeight/2
// 旋转容器
particleContainer.rotation = 35 * Math.PI/180
let particles = []
let colors = [0xf1cf54, 0xb5cea8,0xf1cf54,0x818181,0x0000]
for(let i=0;i<10;i++){
// 循环创建粒子:颜色随机
let gr =new PIXI.Graphics()
gr.beginFill(colors[Math.floor(Math.random()*colors.length)])
gr.drawCircle(0,0,6)
gr.endFill()
// 保存每个创建出来的粒子实例 并记录 他初始的 xy 坐标位置:主要是为了 停下来的时候,全部都要复位
let pItem = {
sx:Math.random() * window.innerWidth,
sy:Math.random() * window.innerHeight,
gr
}
gr.x = pItem.sx
gr.y = pItem.sy
particleContainer.addChild(gr)
particles.push(pItem)
}
let speed = 0
/**
* 循环函数:
* 1. 初始速度为了 0 ,每次速度增加 .5;但是最高速度为 20
* 2. 每次循环 每个粒子的 Y 轴都会 往下移动,移动的量为 当前Y值+当前速度;
* 3. 每次循环 检查每个粒子 是否超出 window的范围Y值,也就是 页面里看不到了,那么就 y 直接赋值为0;从最上方开始
* 4. 以上便构成了从慢到快的粒子速度效果
*/
function loop (){
// 速度慢慢变快,但也不能 太快,限制一个 最快速度
speed += .5
speed = Math.min(speed,20)
for (let i=0;i<particles.length;i++){
let pItem = particles[i]
pItem.gr.y += speed
if(speed>=20){
pItem.gr.scale.y = 40
pItem.gr.scale.x = .03
}
if(pItem.gr.y>window.innerHeight) pItem.gr.y = 0
}
}
/**
* 开始:默认就是开始 动画效果
* 速度归零
* 循环事件 开始
*/
function start(){
speed = 0
gsap.ticker.add(loop)
}
/**
* 结束:鼠标点击 按钮的时候
* 移除事件
* 将每个粒子的 位置 设置为初始值 + 加一些 动画效果,使得视觉更加的流畅和自然
*/
function pause(){
gsap.ticker.remove(loop)
// 暂停的时候;移除事件,并且位置回归,并加动画
for (let i=0;i<particles.length;i++){
let pItem = particles[i]
pItem.gr.scale.y = 1
pItem.gr.scale.x = 1
// 缓动效果很关键 ease:'elastic.out'
gsap.to(pItem.gr,{duration:.6,x:pItem.sx,y:pItem.sy,ease:'elastic.out'})
}
}
return {particleContainer,start,pause}
}
总结
大帅老师拆解每一步,跟这老师一步一步做,做了一遍,貌似不算难。但其实不是;那是老师教的好 试想一下,如果是你做 即使你思路都对了,说不定一个小小的点,卡住就是 一天,甚至两天都可能!
我在跟着老师敲代码的情况下,都卡住了一会,再对照视频一遍遍看,才解决;事后看,确实是简单的错误,但里面包含了很多的知识点
这个案例我们应该把它看作一个起点,里面还有很多的知识点没有深挖,这仅仅只是开始而已
比如说:我发现中文网站上对这两个框架的 解析 教学 资料 其实是很少的,那么这就是一个机会,可以借此学习 等等
最后推荐下大帅老师,确实很厉害,干货多多;
在公众号里搜 大帅老猿,在他这里可以学到很多东西