共计 3063 个字符,预计需要花费 8 分钟才能阅读完成。
前言
记一次 vue 组件中使用 transition 和 transition-group 设置过渡动画, 总结来说可分为分为 name 版, js 钩子操作类名版, js 钩子操作行内样式版 …
template 模板结构
// 单个元素 | |
<transition name="自定义名字"> | |
<p v-if="show">hello</p> | |
</transition> | |
// 列表元素: 注意 group 的直接子元素是 v -for 渲染出来的 | |
<ul class="list"> | |
<transition-group name="list"> | |
<li v-for="(item, index) in gameList" :key="item.id"> | |
<app-horizontal :itemData="item"></app-horizontal> | |
</li> | |
</transition-group> | |
</ul> |
name 版,name 为组件中的属性
出现的过程: name-enter(初始态) => name-enter-active(中间态) => name-enter-to(终止态) | |
消失的过程: name-leave => name-leave-active => name-leave-to |
以进场过渡动画为例子
我们可以分别设置 enter 阶段 和 enter-to 阶段的动画 | |
1. 设置进入时需要过渡的属性 | |
.name-enter | |
{ | |
opacity: 0; | |
transform: translateY(30px) | |
} | |
2. 然后在 name-enter-active 中设置过渡时间 | |
.name-enter-active {transition: all .3s;} | |
3. 最后在 name-enter-to 中写上终止态属性 | |
其实终止态的 opacity: 1;transform: none; 是默认的, 可以不用写 | |
.name-enter-to { | |
opacity: 1; | |
transform: translateY(0); | |
} | |
如果要给列表中的元素设置交错的效果, 元素不多的话可以添加 delay 属性 | |
.name-enter-active:nth-child(3n+1) {transition-delay: 0s;} | |
.name-enter-active:nth-child(3n+2) {transition-delay: .1s;} | |
.name-enter-active:nth-child(3n+3) {transition-delay: .2s;} | |
离场动画同理... |
js 钩子实现过渡动画: 通过操作类名; 就是 name 版的 js 实现
// 例如实现上述列表依次显示 | |
<ul class="list"> | |
<transition-group | |
v-bind:css="false" | |
v-on:before-enter="beforeEnter" | |
v-on:enter="enter" | |
v-on:after-enter="afterEnter"> | |
<li v-for="(item, index) in gameList" | |
:key="item.id" | |
:data-delay="index*100" | |
> | |
<app-horizontal :itemData="item"></app-horizontal> | |
</li> | |
</transition-group> | |
</ul> | |
// | |
methods: { | |
// 事先定义上述类名 | |
// 在 beforeEnter enter afterEnter 钩子中手动操作上述类名 | |
// 初始态 | |
beforeEnter(dom) {dom.classList.add('list-enter', 'list-enter-active'); | |
}, | |
// 中间态 | |
enter(dom,done) { | |
// 通过 setTimeout + dataset 实现过渡 | |
let delay = dom.dataset.delay; | |
setTimeout(function () {dom.classList.remove('list-enter'); | |
dom.classList.add('list-enter-to'); | |
// 监听 transitionend 事件 | |
var transitionend = window.ontransitionend ? "transitionend" : "webkitTransitionEnd"; | |
dom.addEventListener(transitionend, function onEnd() { | |
// 移除事件 | |
dom.removeEventListener(transitionend, onEnd); | |
// 调用 done(), 表示动画已完成 | |
done()}); | |
}, delay) | |
}, | |
// 终止态 | |
afterEnter(dom) {dom.classList.remove('list-enter-to', 'list-enter-active'); | |
} | |
} |
js 钩子过渡动画: 通过操作行内属性, 自定义动画
<ul class="list"> | |
<transition-group | |
v-bind:css="false" | |
v-on:before-enter="beforeEnter" | |
v-on:enter="enter" | |
v-on:after-enter="afterEnter"> | |
<li v-for="(item, index) in gameList" | |
:key="item.id" | |
:data-delay="index*100" | |
data-y = "100%" | |
> | |
<app-horizontal :itemData="item"></app-horizontal> | |
</li> | |
</transition-group> | |
</ul> | |
// 对应的操作方法; 添加自定义的 dataset, 给 dom 设置 css 样式; 根据需求添加 | |
methods: { | |
// 初始态 | |
beforeEnter(dom) {let { x = 0, y = 0, opacity = 0} = dom.dataset; | |
dom.style.cssText = `transition: .3s;opacity: ${opacity};transform: translateX(${x}) translateY(${y});`; | |
}, | |
// 中间态 | |
enter(dom,done) { | |
let delay = dom.dataset.delay; | |
setTimeout(function () {dom.style.cssText = `transition: .3s;opacity: 1;transform: translateX(0) translateY(0);`; | |
// 监听 transitionend 事件 | |
var transitionend = window.ontransitionend ? "transitionend" : "webkitTransitionEnd"; | |
dom.addEventListener(transitionend, function onEnd() {dom.removeEventListener(transitionend, onEnd); | |
done();}); | |
}, delay) | |
}, | |
// 终止态 | |
afterEnter(dom) {dom.style.cssText = "";} | |
} |
这里记录一下监听 css3 的 animation 动画和 transition 事件:
webkit-animation 动画有三个事件:开始事件: webkitAnimationStart | |
结束事件: webkitAnimationEnd | |
重复运动事件: webkitAnimationIteration | |
css3 的过渡属性 transition: 一个事件 | |
过渡结束: webkitTransitionEnd | |
正文完
发表至: javascript
2019-07-09