0%

Transition组件原理

例如:

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组件的子节点被编译为默认插槽

  1. Transition组件本身不会渲染任何额外的内容,它只是通过默认插槽读取过渡元素,并渲染需要过渡的元素

  2. 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]);
}
}
//判断一个VNode是否需要过渡
const needTransition = vnode.transition;
if (needTransition) {
//调用transition.beforeEnter钩子,将DOM元素作为参数传递
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
//卸载元素时应该调用transition.leave钩子函数
function unmount(vnode) {
//判断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) {
//将卸载动作封装到performRemov函数中
const performRemove = () => parent.removeChild(vnode.el);
}
if (needTransition) {
//如果需要过渡处理,调用transition.leave钩子
//同时将DOM元素和performRemove函数作为参数传递
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();
//在过渡元素的VNode对象上添加transition相应的钩子函数
innerVNode.transition = {
beforeEnter(el) {
//设置初始状态,添加enter-from和enter-active类
el.classList.add("enter-from");
el.classList.add("enter-active");
},
enter(el) {
//下一帧切换到结束状态
nextFrame(() => {
//移除enter-from类,添加enter-to类
el.classList.remove("enter-from");
el.classList.add("enter-to");
//监听transitioned事件完成收尾工作
el.addEventListener("transitioned", () => {
el.classList.remove("enter-to");
el.classList.remove("enter-active");
});
});
},
leave(el, performRemove) {
//设置离场过渡的初始状态,添加leave-from和leave--active类
el.classList.add("leave-from");
el.classList.add("leave-active");
//强制refolw使得初始状态生效
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");
//调用transition.leave钩子函数的第二个参数,完成DOM元素的卸载
performRemove();
});
});
},
};
return innerVNode;
};
},
};