feat: vnode hooks
This commit is contained in:
		
							parent
							
								
									8cafad1fd3
								
							
						
					
					
						commit
						1106e2208d
					
				| @ -1,4 +1,4 @@ | ||||
| import { EMPTY_OBJ, nativeOnRE } from './utils' | ||||
| import { EMPTY_OBJ, nativeOnRE, vnodeHookRE } from './utils' | ||||
| import { | ||||
|   Component, | ||||
|   ComponentClass, | ||||
| @ -92,14 +92,15 @@ export function resolveProps( | ||||
|       if (key === 'key' || key === 'ref' || key === 'slots') { | ||||
|         continue | ||||
|       } | ||||
|       // class, style & nativeOn are always extracted into a separate `attrs`
 | ||||
|       // object, which can then be merged onto child component root.
 | ||||
|       // in addition, if the component has explicitly declared props, then
 | ||||
|       // class, style, nativeOn & directive hooks are always extracted into a
 | ||||
|       // separate `attrs` object, which can then be merged onto child component
 | ||||
|       // root. in addition, if the component has explicitly declared props, then
 | ||||
|       // any non-matching props are extracted into `attrs` as well.
 | ||||
|       let isNativeOn | ||||
|       if ( | ||||
|         key === 'class' || | ||||
|         key === 'style' || | ||||
|         vnodeHookRE.test(key) || | ||||
|         (isNativeOn = nativeOnRE.test(key)) || | ||||
|         (hasDeclaredProps && !options.hasOwnProperty(key)) | ||||
|       ) { | ||||
|  | ||||
| @ -156,13 +156,14 @@ export function createRenderer(options: RendererOptions) { | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // lifecycle hooks -----------------------------------------------------------
 | ||||
|   // lifecycle lifecycleHooks -----------------------------------------------------------
 | ||||
| 
 | ||||
|   const hooks: Function[] = [] | ||||
|   const lifecycleHooks: Function[] = [] | ||||
|   const vnodeUpdatedHooks: Function[] = [] | ||||
| 
 | ||||
|   function flushHooks() { | ||||
|     let fn | ||||
|     while ((fn = hooks.shift())) { | ||||
|     while ((fn = lifecycleHooks.shift())) { | ||||
|       fn() | ||||
|     } | ||||
|   } | ||||
| @ -222,6 +223,9 @@ export function createRenderer(options: RendererOptions) { | ||||
|       for (const key in data) { | ||||
|         patchData(el, key, null, data[key], null, vnode, isSVG) | ||||
|       } | ||||
|       if (data.vnodeBeforeMount) { | ||||
|         data.vnodeBeforeMount(vnode) | ||||
|       } | ||||
|     } | ||||
|     if (childFlags !== ChildrenFlags.NO_CHILDREN) { | ||||
|       const hasSVGChildren = isSVG && tag !== 'foreignObject' | ||||
| @ -243,11 +247,16 @@ export function createRenderer(options: RendererOptions) { | ||||
|     if (ref) { | ||||
|       mountRef(ref, el) | ||||
|     } | ||||
|     if (data != null && data.vnodeMounted) { | ||||
|       lifecycleHooks.push(() => { | ||||
|         data.vnodeMounted(vnode) | ||||
|       }) | ||||
|     } | ||||
|     return el | ||||
|   } | ||||
| 
 | ||||
|   function mountRef(ref: Ref, el: RenderNode | MountedComponent) { | ||||
|     hooks.push(() => { | ||||
|     lifecycleHooks.push(() => { | ||||
|       ref(el) | ||||
|     }) | ||||
|   } | ||||
| @ -438,10 +447,14 @@ export function createRenderer(options: RendererOptions) { | ||||
|     } | ||||
| 
 | ||||
|     const el = (nextVNode.el = prevVNode.el) as RenderNode | ||||
| 
 | ||||
|     // data
 | ||||
|     const prevData = prevVNode.data | ||||
|     const nextData = nextVNode.data | ||||
| 
 | ||||
|     if (nextData != null && nextData.vnodeBeforeUpdate) { | ||||
|       nextData.vnodeBeforeUpdate(nextVNode, prevVNode) | ||||
|     } | ||||
| 
 | ||||
|     // patch data
 | ||||
|     if (prevData !== nextData) { | ||||
|       const prevDataOrEmpty = prevData || EMPTY_OBJ | ||||
|       const nextDataOrEmpty = nextData || EMPTY_OBJ | ||||
| @ -483,6 +496,12 @@ export function createRenderer(options: RendererOptions) { | ||||
|       isSVG && nextVNode.tag !== 'foreignObject', | ||||
|       null | ||||
|     ) | ||||
| 
 | ||||
|     if (nextData != null && nextData.vnodeUpdated) { | ||||
|       vnodeUpdatedHooks.push(() => { | ||||
|         nextData.vnodeUpdated(nextVNode, prevVNode) | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function patchComponent( | ||||
| @ -1064,12 +1083,19 @@ export function createRenderer(options: RendererOptions) { | ||||
|   // unmounting ----------------------------------------------------------------
 | ||||
| 
 | ||||
|   function unmount(vnode: VNode) { | ||||
|     const { flags, children, childFlags, ref } = vnode | ||||
|     if (flags & VNodeFlags.ELEMENT || flags & VNodeFlags.FRAGMENT) { | ||||
|     const { flags, data, children, childFlags, ref } = vnode | ||||
|     const isElement = flags & VNodeFlags.ELEMENT | ||||
|     if (isElement || flags & VNodeFlags.FRAGMENT) { | ||||
|       if (isElement && data != null && data.vnodeBeforeUnmount) { | ||||
|         data.vnodeBeforeUnmount(vnode) | ||||
|       } | ||||
|       unmountChildren(children as VNodeChildren, childFlags) | ||||
|       if (teardownVNode !== void 0) { | ||||
|         teardownVNode(vnode) | ||||
|       } | ||||
|       if (isElement && data != null && data.vnodeUnmounted) { | ||||
|         data.vnodeUnmounted(vnode) | ||||
|       } | ||||
|     } else if (flags & VNodeFlags.COMPONENT) { | ||||
|       if (flags & VNodeFlags.COMPONENT_STATEFUL) { | ||||
|         unmountComponentInstance(children as MountedComponent) | ||||
| @ -1187,7 +1213,7 @@ export function createRenderer(options: RendererOptions) { | ||||
|       mountRef(ref, instance) | ||||
|     } | ||||
|     if (instance.mounted) { | ||||
|       hooks.push(() => { | ||||
|       lifecycleHooks.push(() => { | ||||
|         ;(instance as any).mounted.call(instance.$proxy) | ||||
|       }) | ||||
|     } | ||||
| @ -1227,10 +1253,20 @@ export function createRenderer(options: RendererOptions) { | ||||
|       // will be added to the queue AFTER the parent's, but they should be
 | ||||
|       // invoked BEFORE the parent's. Therefore we add them to the head of the
 | ||||
|       // queue instead.
 | ||||
|       hooks.unshift(() => { | ||||
|       lifecycleHooks.unshift(() => { | ||||
|         ;(instance as any).updated.call(instance.$proxy, nextVNode) | ||||
|       }) | ||||
|     } | ||||
| 
 | ||||
|     if (vnodeUpdatedHooks.length > 0) { | ||||
|       const vnodeUpdatedHooksForCurrentInstance = vnodeUpdatedHooks.slice() | ||||
|       vnodeUpdatedHooks.length = 0 | ||||
|       lifecycleHooks.unshift(() => { | ||||
|         for (let i = 0; i < vnodeUpdatedHooksForCurrentInstance.length; i++) { | ||||
|           vnodeUpdatedHooksForCurrentInstance[i]() | ||||
|         } | ||||
|       }) | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   function unmountComponentInstance(instance: MountedComponent) { | ||||
|  | ||||
| @ -4,7 +4,9 @@ export const NOOP = () => {} | ||||
| 
 | ||||
| export const onRE = /^on/ | ||||
| export const nativeOnRE = /^nativeOn/ | ||||
| export const reservedPropRE = /^(?:key|ref|slots)$|^nativeOn/ | ||||
| export const vnodeHookRE = /^vnode/ | ||||
| export const handlersRE = /^on|^nativeOn|^vnode/ | ||||
| export const reservedPropRE = /^(?:key|ref|slots)$|^nativeOn|^vnode/ | ||||
| 
 | ||||
| export function normalizeStyle( | ||||
|   value: any | ||||
|  | ||||
| @ -5,7 +5,7 @@ import { | ||||
| } from './component' | ||||
| import { VNodeFlags, ChildrenFlags } from './flags' | ||||
| import { createComponentClassFromOptions } from './componentUtils' | ||||
| import { normalizeClass, normalizeStyle, onRE, nativeOnRE } from './utils' | ||||
| import { normalizeClass, normalizeStyle, handlersRE } from './utils' | ||||
| 
 | ||||
| // Vue core is platform agnostic, so we are not using Element for "DOM" nodes.
 | ||||
| export interface RenderNode { | ||||
| @ -270,7 +270,8 @@ export function cloneVNode(vnode: VNode, extraData?: VNodeData): VNode { | ||||
|           clonedData.class = normalizeClass([clonedData.class, extraData.class]) | ||||
|         } else if (key === 'style') { | ||||
|           clonedData.style = normalizeStyle([clonedData.style, extraData.style]) | ||||
|         } else if (onRE.test(key) || nativeOnRE.test(key)) { | ||||
|         } else if (handlersRE.test(key)) { | ||||
|           // on*, nativeOn*, vnode*
 | ||||
|           const existing = clonedData[key] | ||||
|           clonedData[key] = existing | ||||
|             ? [].concat(existing, extraData[key]) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user