Files
knowledge-kit/Chapter2 - Web FrontEnd/2.25.md
2020-02-25 17:46:51 +08:00

194 lines
9.5 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 大前端动画
> 大前端开发中经常会遇到动画的开发那么什么是动画在物理学中运动就是研究物体在时间维度和空间维度上改变的现象所以动画也一样动画主要研究2个因素发生运动物体的**时间**和**空间**。
#### Web前端开发中的动画
在 Web 前端开发中实现动画有2种方式。要么依靠 CSS 实现动画,要么依靠 JS 控制实现动画。
##### CSS 实现动画
首先要说 CSS 中的4个概念animation、transition、transform、translate
| 属性 | 含义 |
| :---: | :---: |
| transition\(过度动画\) | 用于设置元素的样式过渡效果,和 animation 有类似的效果,但存在使用场合有着较大差别 |
| transform\(变形\) | 用于设置元素的旋转、位移、缩放。和设置元素的动画并没直接关系,就跟写 css 属性一样 |
| translate\(移动\) | 用于设置元素的位置,就是 transform 的一个属性 |
| animation动画 | 用于设置怨毒的动画属性它是一个简写有6个属性值 |
**transition**
字面意思过渡是指元素从属性a的某个值过渡到属性a的另一个值这就是一个状态的改变但是需要一个条件来触发从而发生这种转变比如 `&:hover,&:checked,&:focus、媒体查询或者 JS`
```
#box {
height: 100px;
width: 100px;
background: green;
transition: transform 1s ease-in 1s;
}
#box:hover{
transform: rotate(180deg) scale(0.5,0.5);
transform: translateX(100px);
transform: translateY(100px) translateX(100px) scale(0.5, 0.5);
}
<div id="box"></div>
```
分析:给 div 添加了一个过渡动画,动画指定了 transform 动画,触发时机为当鼠标移上去的时候。因此当鼠标移入的时候元素的 transform 属性发生变化,那么这个时候触发了 transition 动画,当鼠标移除的时候也产生了 transform 的变化,因此还是会触发 transition产生动画。
上面设置了3个 transform 只有最后一个生效
因此 transition 产生动画的条件是设置的 property 发生变化,这种动画的特点是需要一个驱动力去触发。因此就存在一些缺点:
1. 需要事件触发,没法在网页加载时自动发生
2. 是一次性的,不能重复发生,除非再次触发
3. 只可以定义开始状态和结束状态,不能定义中间状态,因此没有丰富的动画空间
4. 一条 transition 规则,只能定义一个属性的变化,不能涉及多个属性
语法:**transitionproperty duration timing-function delay**
| 属性 |含义 |
| :---: | :---: |
| transition-property | 规定设置过渡效果的 css 属性名称 |
| transition-duration | 规定完成过渡效果需要时间 |
| transition-timing-function | 规定速度效果的速度曲线 |
| transition-delay | 规定动画效果何时开始 |
**animation**
animation 总体来说是对 transition 的增强,不再受限于触发时机和动画的属性值。
```
.box {
height: 100px;
width: 100px;
border: 15px solid black;
animation: changebox 4s ease-in-out 1s 1 alternate running forwards;
}
.box:hover {
animation-play-state: paused;
}
@keyframes changebox {
10% {
background: red;
}
50% {
width: 80px;
}
70% {
border: 15px solid yellow;
}
100% {
width: 180px;
height: 180px;
}
}
<div class="box"></div>
```
**animation: animation-name, animation-duration, animation-timing-function, animation-delay, animation-iteration-count, animation-direction, animation-fill-mode**
|属性 | 含义 |
| :----: | :----: |
| animation-name | 用来调用@keyframes定义好的动画,与@keyframes定义的动画名称一致 |
| animation-duration | 指定元素播放动画所持续的时间 |
| animation-timing-function | 指定速度效果的速度曲线,是针对每一个小动画所在时间范围内的变化频率|
| animation-delay| 定义在执行动画之前的等待时间|
| animation-iteration-count| 定义动画的播放次数可选具体次数或者无限次infinite|
| animation-direction |设置动画播放方向normal按时间轴顺序、alternate轮流即来回往复进行) |
| animation-play-state| 控制元素的播放状态running继续、paused暂停|
| animation-fill-mode | 控制动画结束后元素的样式有4个值 none回到动画之前的状态、forwards元素停留在动画结束后的状态、backwords动画回到第一帧的状态、both根据 animation-direction 轮流应用 forwards 和 backwords 规则)。注意与 iteration-count 不要冲突|
总结:单个动画效果、简单的由 transtion 实现,复杂的用 animation 实现。animation 出现后市面上出现了很多这种 css 动画库,其中我在使用 animate.css 推荐小伙伴们使用下
##### JS 实现动画
大家用 JS 写动画立马想到的是 setTimeout 和 setInterval但是较好的动画体验是保持在 60fps 最好上面的2个 api 由于会受到 runloop 的影响并不会特别准时JS 有个 requestAnimationFrame api 可以保持动画在 60fps
JS 实现动画的本质就是控制元素在时间和空间上的变化的研究。
假如要实现一个匀速直线动画,让一个 div 在 3秒内在水平方向上从向由右移动500px。那么如何实现先从物理问题上解决吧。
总时间: 3s
总位移: 500px
那么每秒移动多少 500px/3s
我们设计一个 JS 函数。4个参数 属性开始值,属性结束值,动画执行时间,回调函数
大体思路是外界传入上面4个参数我们可以记录函数调用刚开始的时刻也就是开始时间start然后通过 performance.now\(\) 拿到当前时间now然后 period = \(now-start\) 就是经过的时间。然后通过 period/time 就是时间的进度百分比,拿这个百分比再去乘以总的属性值差就是当前的属性值,然后将计算结果实时调用回调函数(这个回调函数就是指定这个属性值如何应用到动画元素上)
```
/**
* 执行补间动画方法
*
* @param {Number} start 开始数值
* @param {Number} end 结束数值
* @param {Number} time 补间时间
* @param {Function} callback 每帧回调
* @param {Function} timing 速度曲线,默认匀速
*/
function animate(start, end, time, callback, timing = t => t) {
let startTime = performance.now() // 设置开始的时间戳
let period = end - start // 拿到数值差值
// 创建每帧之前要执行的函数
function loop() {
liveAnimationFunction = requestAnimationFrame(loop) // 下一调用每帧之前要执行的函数
const passTime = performance.now() - startTime // 获取当前时间和开始时间差
let per = passTime / time // 计算当前已过百分比
if (per >= 1) { // 判读如果已经执行
per = 1 // 设置为最后的状态
cancelAnimationFrame(raf) // 停掉动画
}
const pass = period * timing(per) // 通过已过时间百分比*开始结束数值差得出当前的数值
callback(pass)
}
let liveAnimationFunction = requestAnimationFrame(loop) // 下一阵调用每帧之前要执行的函数
}
function doMove(easing) {
asing])
}
function move(box, value) {
box.style.transform = `translateX(${value}px)`
}
```
#### Native 端动画iOS为例
其实动画的本质就是元素时间和空间上发生变化的研究。在 web 前端如此,在 native 端也是如此,不过就是换了一些 api 如此。
举个例子,就拿上面所说的水平位移为例,下面给 iOS 的原生代码
```
//CALayer 层动画
CABasicAnimation *positionAnimation = [CABasicAnimation animation];
//指定动画路径是水平方向x轴
positionAnimation.keyPath = @"position.x";
//指定位移距离
positionAnimation.toValue = @1000;
//下面2行代码让动画停留在动画结束的位置
positionAnimation.fillMode = kCAFillModeForwards;//(效果完全等同于 css 中的 animation-fill-mode属性
positionAnimation.removedOnCompletion = NO;
[self.animationView.layer addAnimation:positionAnimation forKey:nil];
```
css 中的 animation-fill-mode控制动画结束后元素的样式有4个值 none回到动画之前的状态、forwards元素停留在动画结束后的状态、backwords动画回到第一帧的状态、both根据 animation-direction 轮流应用 forwards 和 backwords 规则))和 nativeiOS端的 fillMode 属性一致。
下面提出 iOS 端的 fillMode 取值选项
```
/* `fillMode' options. */
CA_EXTERN CAMediaTimingFillMode const kCAFillModeForwards
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
CA_EXTERN CAMediaTimingFillMode const kCAFillModeBackwards
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
CA_EXTERN CAMediaTimingFillMode const kCAFillModeBoth
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
CA_EXTERN CAMediaTimingFillMode const kCAFillModeRemoved
API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
```
看得出来 fillMode web 端和 native 端是一模一样的。
再举个例子,平时我们有可能画一根横线,在 web 端 和 native 端都存在 view 这样的概念,在 web 端可能会是一个 div高度设置为1或者是 canvas 实现canvas 拿到当前上下文、绘制路径、关闭路径、填充颜色)。在 native 端也一样,开启绘图上下文、拿到上下对象、绘制路径、上色、关闭上下文。
所以其他具体的例子也就不举了,本质上大前端的所有动画干的事情都一样,所以我们需要处理好时间和位置的关系。