|
42 | 42 | patchProps(el, key, null, vnode.props[key])
|
43 | 43 | }
|
44 | 44 | }
|
| 45 | + // 判断一个 VNode 是否需要过渡 |
| 46 | + const needTransition = vnode.transition |
| 47 | + if (needTransition) { |
| 48 | + // 调用 transition.beforeEnter 钩子,并将 DOM 元素作为参数传递 |
| 49 | + vnode.transition.beforeEnter(el) |
| 50 | + } |
45 | 51 |
|
46 | 52 | insert(el, container, anchor)
|
| 53 | + if (needTransition) { |
| 54 | + // 调用 transition.enter 钩子,并将 DOM 元素作为参数传递 |
| 55 | + vnode.transition.enter(el) |
| 56 | + } |
47 | 57 | }
|
48 | 58 |
|
49 | 59 | const queue = new Set()
|
|
516 | 526 | patchChildren(n1, n2, el)
|
517 | 527 | }
|
518 | 528 |
|
519 |
| - // 卸载操作 |
520 | 529 | function unmount (vnode) {
|
| 530 | + // 判断 VNode 是否需要过渡处理 |
| 531 | + const needTransition = vnode.transition |
521 | 532 | if (vnode.type === Fragment) {
|
522 | 533 | vnode.children.forEach(c => unmount(c))
|
523 | 534 | return
|
524 | 535 | } else if (typeof vnode.type === 'object') {
|
525 |
| - // vnode.shouldKeepAlive 是一个布尔值,用来标识该组件是否应该被 KeepAlive |
526 | 536 | if (vnode.shouldKeepAlive) {
|
527 |
| - // 对于需要被 KeepAlive 的组件,我们不应该真的卸载它,而应调用该组件的父组件, |
528 |
| - // 即 KeepAlive 组件的 _deActivate 函数使其失活 |
529 | 537 | vnode.keepAliveInstance._deActivate(vnode)
|
530 | 538 | } else {
|
531 | 539 | unmount(vnode.component.subTree)
|
|
534 | 542 | }
|
535 | 543 | const parent = vnode.el.parentNode
|
536 | 544 | if (parent) {
|
537 |
| - parent.removeChild(vnode.el) |
| 545 | + // 将卸载动作封装到 performRemove 函数中 |
| 546 | + const performRemove = () => parent.removeChild(vnode.el) |
| 547 | + if (needTransition) { |
| 548 | + // 如果需要过渡处理,则调用 transition.leave 钩子, |
| 549 | + // 同时将 DOM 元素和 performRemove 函数作为参数传递 |
| 550 | + vnode.transition.leave(vnode.el, performRemove) |
| 551 | + } else { |
| 552 | + // 如果不需要过渡处理,则直接执行卸载操作 |
| 553 | + performRemove() |
| 554 | + } |
538 | 555 | }
|
539 | 556 | }
|
540 | 557 |
|
|
677 | 694 | const Text = Symbol()
|
678 | 695 | const Fragment = Symbol()
|
679 | 696 |
|
680 |
| - const Teleport = { |
681 |
| - __isTeleport: true, |
682 |
| - process (n1, n2, container, anchor, internals) { |
683 |
| - // 通过 internals 参数取得渲染器的内部方法 |
684 |
| - const { patch, patchChildren, move } = internals |
685 |
| - // 如果旧 VNode n1 不存在,则是全新的挂载,否则执行更新 |
686 |
| - if (!n1) { |
687 |
| - // 挂载 |
688 |
| - // 获取容器,即挂载点 |
689 |
| - const target = typeof n2.props.to === 'string' |
690 |
| - ? document.querySelector(n2.props.to) |
691 |
| - : n2.props.to |
692 |
| - // 将 n2.children 渲染到指定挂载点即可 |
693 |
| - n2.children.forEach(c => patch(null, c, target, anchor)) |
694 |
| - } else { |
695 |
| - // 更新 |
696 |
| - patchChildren(n1, n2, container) |
697 |
| - // 如果新旧 to 参数的值不同,则需要对内容进行移动 |
698 |
| - if (n2.props.to !== n1.props.to) { |
699 |
| - // 获取新的容器 |
700 |
| - const newTarget = typeof n2.props.to === 'string' |
701 |
| - ? document.querySelector(n2.props.to) |
702 |
| - : n2.props.to |
703 |
| - // 移动到新的容器 |
704 |
| - n2.children.forEach(c => move(c, newTarget)) |
| 697 | + const Transition = { |
| 698 | + name: 'Transition', |
| 699 | + setup (props, { slots }) { |
| 700 | + return () => { |
| 701 | + const innerVNode = slots.default() |
| 702 | + |
| 703 | + innerVNode.transition = { |
| 704 | + beforeEnter (el) { |
| 705 | + // 设置初始状态:添加 enter-from 和 enter-active 类 |
| 706 | + el.classList.add('enter-from') |
| 707 | + el.classList.add('enter-active') |
| 708 | + }, |
| 709 | + enter (el) { |
| 710 | + // 在下一帧切换到结束状态 |
| 711 | + nextFrame(() => { |
| 712 | + // 移除 enter-from 类,添加 enter-to 类 |
| 713 | + el.classList.remove('enter-from') |
| 714 | + el.classList.add('enter-to') |
| 715 | + // 监听 transitionend 事件完成收尾工作 |
| 716 | + el.addEventListener('transitionend', () => { |
| 717 | + el.classList.remove('enter-to') |
| 718 | + el.classList.remove('enter-active') |
| 719 | + }) |
| 720 | + }) |
| 721 | + }, |
| 722 | + leave (el, performRemove) { |
| 723 | + // 设置离场过渡的初始状态:添加 leave-from 和 leave-active 类 |
| 724 | + el.classList.add('leave-from') |
| 725 | + el.classList.add('leave-active') |
| 726 | + // 强制 reflow,使得初始状态生效 |
| 727 | + document.body.offsetHeight |
| 728 | + // 在下一帧修改状态 |
| 729 | + nextFrame(() => { |
| 730 | + // 移除 leave-from 类,添加 leave-to 类 |
| 731 | + el.classList.remove('leave-from') |
| 732 | + el.classList.add('leave-to') |
| 733 | + |
| 734 | + // 监听 transitionend 事件完成收尾工作 |
| 735 | + el.addEventListener('transitionend', () => { |
| 736 | + el.classList.remove('leave-to') |
| 737 | + el.classList.remove('leave-active') |
| 738 | + // 调用 transition.leave 钩子函数的第二个参数,完成 DOM 元素的卸载 |
| 739 | + performRemove() |
| 740 | + }) |
| 741 | + }) |
| 742 | + } |
705 | 743 | }
|
| 744 | + |
| 745 | + return innerVNode |
706 | 746 | }
|
707 | 747 | }
|
708 | 748 | }
|
|
0 commit comments