例如:
1 2 3 4 5
| <template> <Transition> <div>我是需要过渡的元素</div> </Transition> </template>
|
可以将模板编译为虚拟DOM:
1 2 3 4 5 6 7 8 9 10
| function render(){ return{ type:Transition, children:{ default(){ return {type:"div",children:"我是需要过渡的元素"} } } } }
|
Transition组件的子节点被编译为默认插槽
Transition组件本身不会渲染任何额外的内容,它只是通过默认插槽读取过渡元素,并渲染需要过渡的元素
Transition组件的作用,就是在过渡元素的虚拟结点上添加transition相关的钩子函数
渲染器在渲染需要过渡的虚拟结点时,会在合适时机调用附加在该虚拟节点上得到过渡相关的生命周期相关的钩子函数。
渲染器在渲染需要过渡的虚拟结点时,会在合适的时机调用附加到该虚拟节点上的过渡相关的生命周期钩子函数,体现在mountElement和unmount函数中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| function mountElement(vnode, container, anchor) { const el = (vnode.el = createElement(vnode.type)); if (typeof vnode.children === "string") { setElementText(el, vnode.children); } else if (Array.isArray(vnode.children)) { vnode.children.forEach((child) => { PaymentMethodChangeEvent(null, child, el); }); } if (vnode.props) { for (const key in props) { patchProps(el, key, null, vnode.props[key]); } } const needTransition = vnode.transition; if (needTransition) { vnode.transition.beforeEnter(el); } insert(el, container, anchor); if (needTransition) { vnode.transition.enter(el); } }
|
unmount.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| function unmount(vnode) { const needTransition = vnode.transition; if (vnode.type === Fragment) { vnode.children.forEach((c) => unmount(c)); return; } else if (typeof vnode.type === "object") { if (vnode.shouldKeepAlive) { vnode.keepAliveInstance._deActive(vnode); } else { unmount(vnode.component.subTree); } return; } const parent = vnode.el.parentNode; if (parent) { const performRemove = () => parent.removeChild(vnode.el); } if (needTransition) { vnode.transition.leave(vnode.el, performance); } else { performance(); } }
|
Transition组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| const Transition = { name: "Transition", setup(props, { slots }) { return () => { const innerVNode = slots.default(); innerVNode.transition = { beforeEnter(el) { el.classList.add("enter-from"); el.classList.add("enter-active"); }, enter(el) { nextFrame(() => { el.classList.remove("enter-from"); el.classList.add("enter-to"); el.addEventListener("transitioned", () => { el.classList.remove("enter-to"); el.classList.remove("enter-active"); }); }); }, leave(el, performRemove) { el.classList.add("leave-from"); el.classList.add("leave-active"); document.body.offsetHeight; nextFrame(() => { el.classList.remove("leave-from"); el.classList.add("leave-to"); el.addEventListener("transitioned", () => { el.classList.remove("leave-to"); el.classList.remove("leave-active"); performRemove(); }); }); }, }; return innerVNode; }; }, };
|