persisted,这个 prop 没有在 Vue 的官方文档中出现,不过我们可以通过源码知道:
图中代码源自 Vue.js 3.2.45 版本
当 persisted 设置为 true 时,表示该过渡不会实际插入或移除 DOM 元素。相反,他只会切换元素的显示和隐藏状态(display: none)。这意味着元素始终存在于 DOM 中,但其可见性会根据状态进行切换。(原文:If true, indicates this is a transition that doesn't actually insert/remove the element, but toggles the show / hidden status instead.)
同时,当 persisted 为 true 的情况下,过渡钩子会被注入,但是会被渲染器跳过。这意味着渲染器中不会执行 Transition 组件相关钩子。(原文:The transition hooks are injected, but will be skipped by the renderer.)
自定义指令可以通过调用注入的 Transition 相关钩子控制过渡效果。(原文:Instead, a custom directive can control the transition by calling the injected hooks (e.g. v-show).)
注意 @before-enter 和 @enter 两个 JavaScript 钩子的执行时机,在第一次加载页面时,这两个钩子是不会执行的。除非传入 appear prop 为 true。
由上图源码可知,在未完成挂载的情况下,appear 为 true 才会执行 onBeforeAppear 或 onBeforeEnter 钩子、onAppear 或 onEnter 钩子。
这里提到了 v-show 指令,编译器中会判断 Transition 的子元素是否使用 v-show 指令,如果使用 v-show 指令,则会注入 persisted: true 到 Transition 的 prop 中:
注释中提到了 v-show 指令,我们再看看 v-show 的源码:
一开始看到注释中的这句话时,并不理解其中的意思:
// Instead, a custom directive can control the transition by calling the injected hooks (e.g. v-show).
直到看到 v-show 的源码时,瞬间明白了,自定义指令也可以像 v-show 一样,通过调用注入的 Transition 相关钩子控制过渡效果。如下面的自定义指令的例子:
<script src="../../../dist/vue.global.js"></script>
<style>
.btn-container {
display: inline-block;
position: relative;
height: 1em;
}
</style>
<div id="demo">
<div class="btn-container">
<button @click="show = !show">Toggle</button>
<transition
persisted
@before-enter="onBeforeEnter"
@enter="onEnter"
@leave="onLeave"
>
<div v-my-transition="show">This is a custom transition example.</div>
</transition>
</div>
</div>
<script>
const { createApp, ref } = Vue
createApp({
setup() {
const show = ref(true)
const onBeforeEnter = (el) => {
el.style.opacity = 0; // 初始透明度为0
}
const onEnter = (el, done) => {
el.offsetHeight; // 强制重绘
el.style.transition = 'opacity 0.5s'; // 设置过渡效果
el.style.opacity = 1; // 进入时透明度变为1
done(); // 完成过渡
}
const onLeave = (el, done) => {
el.style.transition = 'opacity 0.5s'; // 设置过渡效果
el.style.opacity = 0; // 离开时透明度变为0
setTimeout(done, 500); // 等待过渡完成后调用done
}
return {
show,
onBeforeEnter,
onEnter,
onLeave
}
},
directives: {
'my-transition': {
beforeMount(el, { value }, { transition }) {
if (transition && value) {
transition.beforeEnter(el)
}
},
mounted(el, { value }, { transition }) {
if (transition && value) {
transition.enter(el)
}
},
updated(el, { value, oldValue }, { transition }) {
if (!value === !oldValue) return
if (transition) {
if (value) {
transition.beforeEnter(el)
transition.enter(el)
} else {
transition.leave(el, () => {
console.log('leave done')
})
}
}
}
}
}
}).mount('#demo')
</script>
上面的代码自定义了一个指令 my-transition ,该自定义指令通过调用注入的 transition 钩子,实现了动画过渡效果。
上面的代码传入了 persisted 为 true 的 prop ,好处是传入了 persisted 为 true 的 prop 后,渲染器会跳过 transition 钩子,避免了重复执行 transition 钩子。
总结
persisted,这个 prop 没有在 Vue 的官方文档中出现,有关 persisted 的含义与 Transition 组件结合自定义组件的用法也是通过阅读源码学习到的。
这也是阅读源码的好处之一吧,可以学习到官方文档外的相关用法,拓展自己的知识。
至于为啥 Vue 官方文档 为啥没有提到 persisted ,也没有说到自定义指令可以结合 Transition 组件一起使用自定义过渡效果,估计是考虑到这种用法在日常开发中用得不多吧。
但是对于前端开发工程师来说,通过阅读源码学习一些拓展的知识,对自身没有坏处。
作者:云浪
链接:https://juejin.cn