Основываясь на vue, вам нужно знать о vuetransition
а такжеtransition-group
Пользовались и поняли.
transition
пара документации vuetranstion
Компоненты уже имеют очень подробныеанализировать.
Вот мое понимание:
transtion
Это абстрактный компонент, предоставляемый Vue, который поможет нам управлять дочерними элементами, которые он оборачивает, в нужное время.
Подходящее время:
-
beforeEnter
dom генерируется из js и просто вставляется во фрейм страницы (соответствует началу анимации на рисунке ниже) -
enter
Следующий кадр после dom вставляется на страницу (соответствует анимации на следующем рисунке) -
afterEnter
Следующий кадр после завершения анимации dom (соответствует концу анимации на рисунке ниже)
Здесь неоднократно упоминалось понятие фрейма, я рассказывал о нем в прошлой статье, если интересно, можете глянуть.
transition-group
ransition-group
Компонент группирует каждый элемент в обернутом спискеtranstion
работа компонента.
html
<div id="app" @click="num === 0 ? num++ : num = 5">
<transition-group name="list">
<item v-for="n in num" :key=n />
</transition-group>
</div>
css
.list-enter {
opacity: 0;
transform: translateY(100%);
}
.list-enter-active {
transition: .3s;
}
/* enter-to其实可以不用写, 没有显性写明,就是默认的opacity: 1;transform: none; */
.list-enter-to {
opacity: 1;
transform: translateY(0);
}
Затем добавьте разные задержки для каждого элемента списка.
transition-delay
css
.list-enter-active:nth-child(5n+2) {
transition-delay: .3s;
}
.list-enter-active:nth-child(5n+3) {
transition-delay: .5s;
}
.list-enter-active:nth-child(5n+4) {
transition-delay: .7s;
}
.list-enter-active:nth-child(5n+5) {
transition-delay: .9s;
}
Использование transition-delay с селекторами css действительно может обеспечить поэтапные переходы,
Но недостаток тоже очевиден, нужно писать много css, а модифицировать не гибко.
Затем мы используем JavaScript-хук vue для его реализации.
setTimeout
html
<div id="app" @click="num === 0 ? num++ : num = 5">
<!-- 这里加上 v-bind:css="false" 让vue跳过对css的检测,让我们更好控制 动画完成的时机 -->
<transition-group
v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter">
<item v-for="(n,index) in num" :key=n :data-delay=index*100 />
</transition-group>
</div>
При использовании только переходов JavaScript вы должны использовать обратные вызовы done при вводе и выходе. В противном случае они будут вызываться синхронно и переход завершится немедленно.
new Vue({
el: "#app",
data: () => ({
num: 0
}),
methods: {
//让我们在 beforeEnter enter afterEnter 钩子里,把 vue 帮我们做的事,自己做一遍:
//添加移除 class 类名,监听 transitionend 事件。
beforeEnter(dom) {
dom.classList.add('list-enter', 'list-enter-active');
},
enter(dom,done) {
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() 告诉vue动画已完成,以触发 afterEnter 钩子
});
}, delay)
},
afterEnter(dom) {
dom.classList.remove('list-enter-to', 'list-enter-active');
}
}
})
Пока это работает хорошо, и достигается эффект ступенчатых переходов без написания большого количества css.
Оглядываясь назад, мы сделали всего 2 вещи, используя.list-enter .list-enter-to
а такжеsetTimeout
Скажите браузеру помещать элемент списка в разное время, начиная сopacity 0 translateY(100%
) Переход к ,opacity 1 translateY(0)
.
Сообщите браузеру различные состояния элемента в дополнение к имени класса,
Мы можем напрямую манипулировать dom и писать встроенные стили,
Помимо того, что имена классов CSS вообще не пишутся,
Там также может быть больше программируемости.
style
html
<div id="app" @click="num ? num++ : num=5">
<transition-group
v-bind:css="false"
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter">
<item v-for="(n,index) in num"
:key=n
:data-delay=index*100
data-y="100%"
/>
</transition-group>
</div>
new Vue({
el: "#app",
data: () => ({
num: 0
}),
methods: {
beforeEnter(dom) {
let { x = 0, y = 0, s = 1, opacity = 0 } = dom.dataset;
dom.style.cssText = `transition: .3s;opacity: ${opacity};transform: scale(${s}) translateX(${x}) translateY(${y});`;
},
enter(dom,done) {
let delay = dom.dataset.delay;
setTimeout(function () {
dom.style.cssText = `transition: .3s;opacity: 1;transform: scale(1) translateX(0) translateY(0);`;
//监听 transitionend 事件
var transitionend = window.ontransitionend ? "transitionend" : "webkitTransitionEnd";
dom.addEventListener(transitionend, function onEnd() {
dom.removeEventListener(transitionend, onEnd);
done(); //调用done() 告诉vue动画已完成,以触发 afterEnter 钩子
});
}, delay)
},
afterEnter(dom) {
dom.style.cssText = "";
}
}
})
Ну да, но поскольку все они на js, единственным ограничением является ваша фантазия.
html
<item v-for="(n,index) in num"
:key=n
:data-delay=index*100
:data-x="index%2 === 0 ? '-50%' : '50%'"
:data-y="getRandom()+'%'"
:data-s="Math.random()"
/>
getRandom() {
var rate = Math.floor(Math.random() * 90 + 10);
return Math.random() > 0.5 ? rate : -1 * rate;
}
использованная литература
[Перевод] Советы по превращению интерактивных анимаций из «хороших» в «превосходные»