因需求关系,要求作到添加购物车时,有个小球从点击添加的按钮经过运动轨迹到达购物车位置, 由于是须要获取动态位置, 经过css渲染动画
爱莫能助, 很幸运的是, vue-transition内置组件提供js钩子函数
, 为我提供完成的动画的保障javascript
首先, 让咱们了解下vue transition的一些特性:css
Props:
name - string,用于自动生成 CSS 过渡类名。例如:name: 'fade' 将自动拓展为.fade-enter,.fade-enter-active等。默认类名为 "v"
appear - boolean,是否在初始渲染时使用过渡。默认为 false。
css - boolean,是否使用 CSS 过渡类。默认为 true。若是设置为 false,将只经过组件事件触发注册的 JavaScript 钩子。
type - string,指定过渡事件类型,侦听过渡什么时候结束。有效值为 "transition" 和 "animation"。默认 Vue.js 将自动检测出持续时间长的为过渡事件类型。
mode - string,控制离开/进入的过渡时间序列。有效的模式有 "out-in" 和 "in-out";默认同时生效。
duration - number | { enter: number, leave: number } 指定过渡的持续时间。默认状况下,Vue 会等待过渡所在根元素的第一个 transitionend 或 animationend 事件。
enter-class - string leave-class - string appear-class - string enter-to-class - string leave-to-class - string appear-to-class - string enter-active-class - string leave-active-class - string appear-active-class - string 事件: before-enter before-leave before-appear enter leave appear after-enter after-leave after-appear enter-cancelled leave-cancelled (v-show only) appear-cancelled 复制代码
具体的一些使用方法,由于与本文内容不是很贴边,在这里不详细讲了 剩余的就不在这里说了, 开始主题html
不知道你们在写原生js的时候,有没有遇到过这样的一个问题前端
一个DOM元素从display: none变为display: block的时候,想要它想vue的transition同样,利用动画过渡过来, 你颇有可能会这么写vue
<div class="c-transition__container" style="display: none;"></div>
复制代码
.c-transition__container {
width: 100px;
height: 100px;
background: red;
transition-duration: .5s;
transition-property: transform;
}
复制代码
const oDiv = document.getElementsByClassName('c-transition__container')[0]
document.onclick = function() {
oDiv.style.transform = 'translate3d(100px, 0, 0)'
oDiv.style.display = 'block'
}
复制代码
事实老是难以接受, 这么写是不会有平滑过渡的效果,而是直接在最终的位置显示java
沮丧的你今后弃坑,发誓不再碰前端:laughing:web
别着急, 下面讲解如何实现从0到1的平滑
浏览器
首先咱们要了解浏览器的渲染时机
app
for(let i = 0; i < 100; i++) {
oDiv.style.transform = 'translate(100px, 0, 0)'
}
复制代码
以上的for循环语句里操做了100次的div, 但实际上浏览器并不会渲染100次, 根据上文函数
咱们能够得知, 浏览器的UI Render是在每一个macroTask最后清空microTask队列后才会触发一次, 可是浏览器会根据实际状况来肯定是否须要渲染, 一般在每隔16.7ms的状况下会渲染一次, 在此期间,浏览器会将全部的DOM操做推入到队列
中,在进行渲染的时候会一个一个取出,直到清空队列。
浏览器渲染过程:
JavaScript:JavaScript 实现动画效果,DOM 元素操做等。(Cpu)
Style(计算样式):肯定每一个 DOM 元素应该应用什么 CSS 规则。(Cpu)
Layout(布局):计算每一个 DOM 元素在最终屏幕上显示的大小和位置。因为 web 页面的元素布局是相对的,因此其中任意一个元素的位置发生变化,都会联动的引发其余元素发生变化,这个过程叫 reflow。(每一个DOM对应一个渲染层)(Cpu)
Paint(绘制):在多个层上绘制 DOM 元素的的文字、颜色、图像、边框和阴影等, 这个过程叫作repaint。(Cpu)
Composite(渲染层合并):按照合理的顺序合并图层而后显示到屏幕上。(进入GPU)(render Tree 解析渲染)
复制代码
理解了以上部分, 那么接下来的问题就好办了
咱们逐句分析刚才的案例:
translate(100px, 0, 0)
,而且更新了状态display: block
, 注意这个时候, 也就是我刚才提到的浏览器, 并无进行直接进行渲染,而是将它推入到了队列里, 但记得一句, DOM Tree是实时更新的, 此时虽然没有渲染,可是DOM Tree里的状态已经更新了,这个时候DOM transform已经变成了100px, 当真正渲染的时候, 是从100px变为100px,并非从0变成100px,因此咱们看到的是没有过渡效果的。从以上的分析,咱们能够基本了解为何会是这种现象, 下面我来说下解决方案:
首先就是你们所熟知的setTimeout,这个的确能够解决以上问题, 可是setTimeout属于macroTask, 每一个task的最后都会触发一次UI Render, 以上操做会形成屡次渲染, 因此并不推荐使用
(推荐) 强制浏览器清空队列进行渲染操做
在获取布局信息操做的时候, 会强制浏览器清空队列进行渲染, API有如下几个: innerHeight、scrollTop、offsetHeight、getBoundingClientRect等等
这个时候, 浏览器从新进行回流重绘渲染
操做, 这个时候触发DOM操做均可以获得有效回馈
Vue transitionjs钩子函数其实就是原生js写的动画, 一样从无到有进行平滑, 你学会了吗?