feat: template ref handling + ref unmount
This commit is contained in:
		
							parent
							
								
									10a2cf47ea
								
							
						
					
					
						commit
						8f9afdff64
					
				| @ -31,7 +31,14 @@ import { | |||||||
|   FULL_PROPS |   FULL_PROPS | ||||||
| } from './patchFlags' | } from './patchFlags' | ||||||
| import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler' | import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler' | ||||||
| import { effect, stop, ReactiveEffectOptions } from '@vue/reactivity' | import { | ||||||
|  |   effect, | ||||||
|  |   stop, | ||||||
|  |   ReactiveEffectOptions, | ||||||
|  |   isRef, | ||||||
|  |   Ref, | ||||||
|  |   toRaw | ||||||
|  | } from '@vue/reactivity' | ||||||
| import { resolveProps } from './componentProps' | import { resolveProps } from './componentProps' | ||||||
| import { resolveSlots } from './componentSlots' | import { resolveSlots } from './componentSlots' | ||||||
| import { | import { | ||||||
| @ -80,7 +87,11 @@ export interface RendererOptions { | |||||||
|     oldValue: any, |     oldValue: any, | ||||||
|     isSVG: boolean, |     isSVG: boolean, | ||||||
|     prevChildren?: VNode[], |     prevChildren?: VNode[], | ||||||
|     unmountChildren?: (children: VNode[]) => void |     parentComponent?: ComponentInstance | null, | ||||||
|  |     unmountChildren?: ( | ||||||
|  |       children: VNode[], | ||||||
|  |       parentComponent: ComponentInstance | null | ||||||
|  |     ) => void | ||||||
|   ): void |   ): void | ||||||
|   insert(el: HostNode, parent: HostNode, anchor?: HostNode): void |   insert(el: HostNode, parent: HostNode, anchor?: HostNode): void | ||||||
|   remove(el: HostNode): void |   remove(el: HostNode): void | ||||||
| @ -121,7 +132,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|     // patching & not same type, unmount old tree
 |     // patching & not same type, unmount old tree
 | ||||||
|     if (n1 != null && !isSameType(n1, n2)) { |     if (n1 != null && !isSameType(n1, n2)) { | ||||||
|       anchor = getNextHostNode(n1) |       anchor = getNextHostNode(n1) | ||||||
|       unmount(n1, true) |       unmount(n1, parentComponent, true) | ||||||
|       n1 = null |       n1 = null | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -237,7 +248,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|       patchElement(n1, n2, parentComponent, isSVG, optimized) |       patchElement(n1, n2, parentComponent, isSVG, optimized) | ||||||
|     } |     } | ||||||
|     if (n2.ref !== null && parentComponent !== null) { |     if (n2.ref !== null && parentComponent !== null) { | ||||||
|       setRef(n2.ref, parentComponent, n2.el) |       setRef(n2.ref, n1 && n1.ref, parentComponent, n2.el) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -306,7 +317,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
| 
 | 
 | ||||||
|       if (patchFlag & FULL_PROPS) { |       if (patchFlag & FULL_PROPS) { | ||||||
|         // element props contain dynamic keys, full diff needed
 |         // element props contain dynamic keys, full diff needed
 | ||||||
|         patchProps(el, n2, oldProps, newProps, isSVG) |         patchProps(el, n2, oldProps, newProps, parentComponent, isSVG) | ||||||
|       } else { |       } else { | ||||||
|         // class
 |         // class
 | ||||||
|         // this flag is matched when the element has dynamic class bindings.
 |         // this flag is matched when the element has dynamic class bindings.
 | ||||||
| @ -343,6 +354,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|                 prev, |                 prev, | ||||||
|                 isSVG, |                 isSVG, | ||||||
|                 n1.children as VNode[], |                 n1.children as VNode[], | ||||||
|  |                 parentComponent, | ||||||
|                 unmountChildren |                 unmountChildren | ||||||
|               ) |               ) | ||||||
|             } |             } | ||||||
| @ -361,7 +373,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|       } |       } | ||||||
|     } else if (!optimized) { |     } else if (!optimized) { | ||||||
|       // unoptimized, full diff
 |       // unoptimized, full diff
 | ||||||
|       patchProps(el, n2, oldProps, newProps, isSVG) |       patchProps(el, n2, oldProps, newProps, parentComponent, isSVG) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (dynamicChildren != null) { |     if (dynamicChildren != null) { | ||||||
| @ -389,6 +401,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|     vnode: VNode, |     vnode: VNode, | ||||||
|     oldProps: any, |     oldProps: any, | ||||||
|     newProps: any, |     newProps: any, | ||||||
|  |     parentComponent: ComponentInstance | null, | ||||||
|     isSVG: boolean |     isSVG: boolean | ||||||
|   ) { |   ) { | ||||||
|     if (oldProps !== newProps) { |     if (oldProps !== newProps) { | ||||||
| @ -404,6 +417,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|             prev, |             prev, | ||||||
|             isSVG, |             isSVG, | ||||||
|             vnode.children as VNode[], |             vnode.children as VNode[], | ||||||
|  |             parentComponent, | ||||||
|             unmountChildren |             unmountChildren | ||||||
|           ) |           ) | ||||||
|         } |         } | ||||||
| @ -419,6 +433,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|               null, |               null, | ||||||
|               isSVG, |               isSVG, | ||||||
|               vnode.children as VNode[], |               vnode.children as VNode[], | ||||||
|  |               parentComponent, | ||||||
|               unmountChildren |               unmountChildren | ||||||
|             ) |             ) | ||||||
|           } |           } | ||||||
| @ -550,6 +565,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|     if (n2.ref !== null && parentComponent !== null) { |     if (n2.ref !== null && parentComponent !== null) { | ||||||
|       setRef( |       setRef( | ||||||
|         n2.ref, |         n2.ref, | ||||||
|  |         n1 && n1.ref, | ||||||
|         parentComponent, |         parentComponent, | ||||||
|         (n2.component as ComponentInstance).renderProxy |         (n2.component as ComponentInstance).renderProxy | ||||||
|       ) |       ) | ||||||
| @ -690,7 +706,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|     if (shapeFlag & TEXT_CHILDREN) { |     if (shapeFlag & TEXT_CHILDREN) { | ||||||
|       // text children fast path
 |       // text children fast path
 | ||||||
|       if (prevShapeFlag & ARRAY_CHILDREN) { |       if (prevShapeFlag & ARRAY_CHILDREN) { | ||||||
|         unmountChildren(c1 as VNode[]) |         unmountChildren(c1 as VNode[], parentComponent) | ||||||
|       } |       } | ||||||
|       hostSetElementText(container, c2 as string) |       hostSetElementText(container, c2 as string) | ||||||
|     } else { |     } else { | ||||||
| @ -719,7 +735,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|           ) |           ) | ||||||
|         } else { |         } else { | ||||||
|           // c2 is null in this case
 |           // c2 is null in this case
 | ||||||
|           unmountChildren(c1 as VNode[], true) |           unmountChildren(c1 as VNode[], parentComponent, true) | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -754,7 +770,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|     } |     } | ||||||
|     if (oldLength > newLength) { |     if (oldLength > newLength) { | ||||||
|       // remove old
 |       // remove old
 | ||||||
|       unmountChildren(c1, true, commonLength) |       unmountChildren(c1, parentComponent, true, commonLength) | ||||||
|     } else { |     } else { | ||||||
|       // mount new
 |       // mount new
 | ||||||
|       mountChildren(c2, container, anchor, parentComponent, isSVG, commonLength) |       mountChildren(c2, container, anchor, parentComponent, isSVG, commonLength) | ||||||
| @ -855,7 +871,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|     // i = 0, e1 = 0, e2 = -1
 |     // i = 0, e1 = 0, e2 = -1
 | ||||||
|     else if (i > e2) { |     else if (i > e2) { | ||||||
|       while (i <= e1) { |       while (i <= e1) { | ||||||
|         unmount(c1[i], true) |         unmount(c1[i], parentComponent, true) | ||||||
|         i++ |         i++ | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
| @ -898,7 +914,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|         const prevChild = c1[i] |         const prevChild = c1[i] | ||||||
|         if (patched >= toBePatched) { |         if (patched >= toBePatched) { | ||||||
|           // all new children have been patched so this can only be a removal
 |           // all new children have been patched so this can only be a removal
 | ||||||
|           unmount(prevChild, true) |           unmount(prevChild, parentComponent, true) | ||||||
|           continue |           continue | ||||||
|         } |         } | ||||||
|         let newIndex |         let newIndex | ||||||
| @ -914,7 +930,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|           } |           } | ||||||
|         } |         } | ||||||
|         if (newIndex === undefined) { |         if (newIndex === undefined) { | ||||||
|           unmount(prevChild, true) |           unmount(prevChild, parentComponent, true) | ||||||
|         } else { |         } else { | ||||||
|           newIndexToOldIndexMap[newIndex - s2] = i + 1 |           newIndexToOldIndexMap[newIndex - s2] = i + 1 | ||||||
|           if (newIndex >= maxNewIndexSoFar) { |           if (newIndex >= maxNewIndexSoFar) { | ||||||
| @ -981,28 +997,45 @@ export function createRenderer(options: RendererOptions) { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function unmount(vnode: VNode, doRemove?: boolean) { |   function unmount( | ||||||
|  |     vnode: VNode, | ||||||
|  |     parentComponent: ComponentInstance | null, | ||||||
|  |     doRemove?: boolean | ||||||
|  |   ) { | ||||||
|  |     // unset ref
 | ||||||
|  |     if (vnode.ref !== null && parentComponent !== null) { | ||||||
|  |       setRef(vnode.ref, null, parentComponent, null) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     const instance = vnode.component |     const instance = vnode.component | ||||||
|     if (instance != null) { |     if (instance != null) { | ||||||
|       unmountComponent(instance, doRemove) |       unmountComponent(instance, doRemove) | ||||||
|       return |       return | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     const shouldRemoveChildren = vnode.type === Fragment && doRemove |     const shouldRemoveChildren = vnode.type === Fragment && doRemove | ||||||
|     if (vnode.dynamicChildren != null) { |     if (vnode.dynamicChildren != null) { | ||||||
|       unmountChildren(vnode.dynamicChildren, shouldRemoveChildren) |       unmountChildren( | ||||||
|  |         vnode.dynamicChildren, | ||||||
|  |         parentComponent, | ||||||
|  |         shouldRemoveChildren | ||||||
|  |       ) | ||||||
|     } else if (vnode.shapeFlag & ARRAY_CHILDREN) { |     } else if (vnode.shapeFlag & ARRAY_CHILDREN) { | ||||||
|       unmountChildren(vnode.children as VNode[], shouldRemoveChildren) |       unmountChildren( | ||||||
|  |         vnode.children as VNode[], | ||||||
|  |         parentComponent, | ||||||
|  |         shouldRemoveChildren | ||||||
|  |       ) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     if (doRemove) { |     if (doRemove) { | ||||||
|       hostRemove(vnode.el) |       hostRemove(vnode.el) | ||||||
|       if (vnode.anchor != null) hostRemove(vnode.anchor) |       if (vnode.anchor != null) hostRemove(vnode.anchor) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function unmountComponent( |   function unmountComponent(instance: ComponentInstance, doRemove?: boolean) { | ||||||
|     { bum, effects, update, subTree, um }: ComponentInstance, |     const { bum, effects, update, subTree, um } = instance | ||||||
|     doRemove?: boolean |  | ||||||
|   ) { |  | ||||||
|     // beforeUnmount hook
 |     // beforeUnmount hook
 | ||||||
|     if (bum !== null) { |     if (bum !== null) { | ||||||
|       invokeHooks(bum) |       invokeHooks(bum) | ||||||
| @ -1013,7 +1046,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     stop(update) |     stop(update) | ||||||
|     unmount(subTree, doRemove) |     unmount(subTree, instance, doRemove) | ||||||
|     // unmounted hook
 |     // unmounted hook
 | ||||||
|     if (um !== null) { |     if (um !== null) { | ||||||
|       queuePostFlushCb(um) |       queuePostFlushCb(um) | ||||||
| @ -1022,11 +1055,12 @@ export function createRenderer(options: RendererOptions) { | |||||||
| 
 | 
 | ||||||
|   function unmountChildren( |   function unmountChildren( | ||||||
|     children: VNode[], |     children: VNode[], | ||||||
|  |     parentComponent: ComponentInstance | null, | ||||||
|     doRemove?: boolean, |     doRemove?: boolean, | ||||||
|     start: number = 0 |     start: number = 0 | ||||||
|   ) { |   ) { | ||||||
|     for (let i = start; i < children.length; i++) { |     for (let i = start; i < children.length; i++) { | ||||||
|       unmount(children[i], doRemove) |       unmount(children[i], parentComponent, doRemove) | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -1037,13 +1071,35 @@ export function createRenderer(options: RendererOptions) { | |||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   function setRef( |   function setRef( | ||||||
|     ref: string | Function, |     ref: string | Function | Ref<any>, | ||||||
|  |     oldRef: string | Function | Ref<any> | null, | ||||||
|     parent: ComponentInstance, |     parent: ComponentInstance, | ||||||
|     value: HostNode | ComponentInstance |     value: HostNode | ComponentInstance | null | ||||||
|   ) { |   ) { | ||||||
|     const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs |     const refs = parent.refs === EMPTY_OBJ ? (parent.refs = {}) : parent.refs | ||||||
|  |     const rawData = toRaw(parent.data) | ||||||
|  | 
 | ||||||
|  |     // unset old ref
 | ||||||
|  |     if (oldRef !== null && oldRef !== ref) { | ||||||
|  |       if (isString(oldRef)) { | ||||||
|  |         refs[oldRef] = null | ||||||
|  |         const oldSetupRef = rawData[oldRef] | ||||||
|  |         if (isRef(oldSetupRef)) { | ||||||
|  |           oldSetupRef.value = null | ||||||
|  |         } | ||||||
|  |       } else if (isRef(oldRef)) { | ||||||
|  |         oldRef.value = null | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (isString(ref)) { |     if (isString(ref)) { | ||||||
|  |       const setupRef = rawData[ref] | ||||||
|  |       if (isRef(setupRef)) { | ||||||
|  |         setupRef.value = value | ||||||
|  |       } | ||||||
|       refs[ref] = value |       refs[ref] = value | ||||||
|  |     } else if (isRef(ref)) { | ||||||
|  |       ref.value = value | ||||||
|     } else { |     } else { | ||||||
|       if (__DEV__ && !isFunction(ref)) { |       if (__DEV__ && !isFunction(ref)) { | ||||||
|         // TODO warn invalid ref type
 |         // TODO warn invalid ref type
 | ||||||
| @ -1055,7 +1111,7 @@ export function createRenderer(options: RendererOptions) { | |||||||
|   return function render(vnode: VNode | null, dom: HostNode): VNode | null { |   return function render(vnode: VNode | null, dom: HostNode): VNode | null { | ||||||
|     if (vnode == null) { |     if (vnode == null) { | ||||||
|       if (dom._vnode) { |       if (dom._vnode) { | ||||||
|         unmount(dom._vnode, true) |         unmount(dom._vnode, null, true) | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       patch(dom._vnode, vnode, dom) |       patch(dom._vnode, vnode, dom) | ||||||
|  | |||||||
| @ -3,10 +3,11 @@ export function patchDOMProp( | |||||||
|   key: string, |   key: string, | ||||||
|   value: any, |   value: any, | ||||||
|   prevChildren: any, |   prevChildren: any, | ||||||
|  |   parentComponent: any, | ||||||
|   unmountChildren: any |   unmountChildren: any | ||||||
| ) { | ) { | ||||||
|   if ((key === 'innerHTML' || key === 'textContent') && prevChildren != null) { |   if ((key === 'innerHTML' || key === 'textContent') && prevChildren != null) { | ||||||
|     unmountChildren(prevChildren) |     unmountChildren(prevChildren, parentComponent) | ||||||
|   } |   } | ||||||
|   el[key] = value |   el[key] = value | ||||||
| } | } | ||||||
|  | |||||||
| @ -13,6 +13,7 @@ export function patchProp( | |||||||
|   prevValue: any, |   prevValue: any, | ||||||
|   isSVG: boolean, |   isSVG: boolean, | ||||||
|   prevChildren?: VNode[], |   prevChildren?: VNode[], | ||||||
|  |   parentComponent?: any, | ||||||
|   unmountChildren?: any |   unmountChildren?: any | ||||||
| ) { | ) { | ||||||
|   switch (key) { |   switch (key) { | ||||||
| @ -27,7 +28,14 @@ export function patchProp( | |||||||
|       if (isOn(key)) { |       if (isOn(key)) { | ||||||
|         patchEvent(el, key.slice(2).toLowerCase(), prevValue, nextValue) |         patchEvent(el, key.slice(2).toLowerCase(), prevValue, nextValue) | ||||||
|       } else if (!isSVG && key in el) { |       } else if (!isSVG && key in el) { | ||||||
|         patchDOMProp(el, key, nextValue, prevChildren, unmountChildren) |         patchDOMProp( | ||||||
|  |           el, | ||||||
|  |           key, | ||||||
|  |           nextValue, | ||||||
|  |           prevChildren, | ||||||
|  |           parentComponent, | ||||||
|  |           unmountChildren | ||||||
|  |         ) | ||||||
|       } else { |       } else { | ||||||
|         patchAttr(el, key, nextValue, isSVG) |         patchAttr(el, key, nextValue, isSVG) | ||||||
|       } |       } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user