Vue组件渲染函数及VNode生成函数h()、createVNode()

您所在的位置:网站首页 vue2中使用h函数 Vue组件渲染函数及VNode生成函数h()、createVNode()

Vue组件渲染函数及VNode生成函数h()、createVNode()

2024-07-10 18:06| 来源: 网络整理| 查看: 265

源文件目录:

packages/runtime-core/src/vnode.ts

packages/runtime-core/src/h.ts

Vue组件实现模板解析渲染的几种方式 单文件组件(SFC)中,Vue组件可以使用定义渲染模板; 任何组件都可以通过配置中tempalte property传入模板字符串定义渲染模板; 定义render()方法,作为组件的渲染函数进行纯JS渲染。 VNode的TS类型定义源码

VNode中常见的重要属性如下:

type: VNode的类型。(代表类型的字符串,VNode对象,Component对象,Text类型Symbol,Static类型Symbol,Comment类型Symbol,Fragment类型Symbol等) props: VNode本身的属性。官方这里可选定义了:key,ref,和VNode的一些生命周期钩子:onVnodeBeforeMount,onVnodeMounted,onVnodeBeforeUpdate,onVnodeUpdated,onVnodeBeforeUnmount,onVnodeUnmounted等。Props可以在h()函数的第二个参数传入。 children: 子VNode; key: VNode的唯一标志符; el: VNode在DOM中挂载的元素对象 // packages/runtime-core/src/vnode.ts export interface VNode { /** * @internal */ // 判断是否是VNode的内部标志:__v_isVNode __v_isVNode: true /** * @internal */ // VNode设置为永远不是响应式的 [ReactiveFlags.SKIP]: true // VNode 的类型: // export type VNodeTypes = // | string // | VNode // | Component // | typeof Text // | typeof Static // | typeof Comment // | typeof Fragment (Fragment是Vue3引入的新节点类型,用来包裹多个根元素组件,让用户可以不用强制创建单一根元素组件。) // | typeof TeleportImpl // | typeof SuspenseImpl type: VNodeTypes props: (VNodeProps & ExtraProps) | null key: string | number | null ref: VNodeNormalizedRef | null /** * SFC only. This is assigned on vnode creation using currentScopeId * which is set alongside currentRenderingInstance. */ scopeId: string | null /** * SFC only. This is assigned to: * - Slot fragment vnodes with :slotted SFC styles. * - Component vnodes (during patchsuspense` ydration) so that its root node can * inherit the component's slotScopeIds */ slotScopeIds: string[] | null children: VNodeNormalizedChildren component: ComponentInternalInstance | null dirs: DirectiveBinding[] | null transition: TransitionHooks | null // DOM el: HostNode | null anchor: HostNode | null // fragment anchor target: HostElement | null // teleport target targetAnchor: HostNode | null // teleport target anchor staticCount: number // number of elements contained in a static vnode // suspense suspense: SuspenseBoundary | null ssContent: VNode | null ssFallback: VNode | null // optimization only shapeFlag: number patchFlag: number dynamicProps: string[] | null dynamicChildren: VNode[] | null // application root node only appContext: AppContext | null } h()函数

从源码上看,h()函数主要是对不同的传参形式进行了重载。在内部,还是调用createNode()函数。

// 这里定义了一系列h()函数的重载形式,用来让用户更容易使用。 // h()函数用来生成VNode,用户用来在组件中手动编写render()函数方法,用来代替template。 // !!————————从这里开始都是重载编写部分——————————————!! // 传入字符串类型,生成DOM元素 // 可以传入两个参数,也可以传入三个参数。对应下面第一个和第二个重载形式。 export function h(type: string, children?: RawChildren): VNode export function h( type: string, props?: RawProps | null, children?: RawChildren | RawSlots ): VNode // 传入文本类型符号或注释类型符号,生成对应VNode: // export const Text = Symbol(__DEV__ ? 'Text' : undefined) // export const Comment = Symbol(__DEV__ ? 'Comment' : undefined) // export const Static = Symbol(__DEV__ ? 'Static' : undefined) export function h( type: typeof Text | typeof Comment, children?: string | number | boolean ): VNode export function h( type: typeof Text | typeof Comment, props?: null, children?: string | number | boolean ): VNode // 下面是特殊类型节点的生成,不重点了解。 // 生成fragment类型VNode export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode export function h( type: typeof Fragment, props?: RawProps | null, children?: VNodeArrayChildren ): VNode // teleport (target prop is required) export function h( type: typeof Teleport, props: RawProps & TeleportProps, children: RawChildren ): VNode // suspense 组件类型节点 export function h(type: typeof Suspense, children?: RawChildren): VNode export function h( type: typeof Suspense, props?: (RawProps & SuspenseProps) | null, children?: RawChildren | RawSlots ): VNode // functional component export function h( type: FunctionalComponent, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode // catch-all for generic component types export function h(type: Component, children?: RawChildren): VNode // concrete component export function h( type: ConcreteComponent | string, children?: RawChildren ): VNode export function h( type: ConcreteComponent | string, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren ): VNode // 没有属性props的组件 export function h( type: Component, props: null, children?: RawChildren | RawSlots ): VNode // exclude `defineComponent` constructors export function h( type: ComponentOptions, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode // fake constructor type returned by `defineComponent` or class component export function h(type: Constructor, children?: RawChildren): VNode export function h( type: Constructor, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode // fake constructor type returned by `defineComponent` export function h(type: DefineComponent, children?: RawChildren): VNode export function h( type: DefineComponent, props?: (RawProps & P) | ({} extends P ? null : never), children?: RawChildren | RawSlots ): VNode // !!————————重载编写部分结束——————————————!! // 这里是h()函数的具体实现:可以看到就是根据不同的形式调用createVNode() export function h(type: any, propsOrChildren?: any, children?: any): VNode { const l = arguments.length if (l === 2) { if (isObject(propsOrChildren) && !isArray(propsOrChildren)) { // single vnode without props if (isVNode(propsOrChildren)) { return createVNode(type, null, [propsOrChildren]) } // props without children return createVNode(type, propsOrChildren) } else { // omit props return createVNode(type, null, propsOrChildren) } } else { if (l > 3) { children = Array.prototype.slice.call(arguments, 2) } else if (l === 3 && isVNode(children)) { children = [children] } return createVNode(type, propsOrChildren, children) } } createVNode函数: h()函数调用的原始函数 // 根据是否是开发环境选择不同的方法,核心都是_createVNode函数。 export const createVNode = (__DEV__ ? createVNodeWithArgsTransform : _createVNode) as typeof _createVNode function _createVNode( type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT, props: (Data & VNodeProps) | null = null, children: unknown = null, patchFlag: number = 0, dynamicProps: string[] | null = null, isBlockNode = false ): VNode { // 判断传入的type是否合法(为falsy),不合法报错。 // 这时type会被设定为注释类型。 if (!type || type === NULL_DYNAMIC_COMPONENT) { if (__DEV__ && !type) { warn(`Invalid vnode type when creating vnode: ${type}.`) } type = Comment } // 判断传入的类型如果本身是VNode,就复制一个新的VNode返回。 if (isVNode(type)) { // createVNode receiving an existing vnode. This happens in cases like // (动态组件!) // #2078 make sure to merge refs during the clone instead of overwriting it const cloned = cloneVNode(type, props, true /* mergeRef: true */) if (children) { normalizeChildren(cloned, children) } return cloned } // class component normalization. if (isClassComponent(type)) { type = type.__vccOpts } // class & style normalization. if (props) { // for reactive or proxy objects, we need to clone it to enable mutation. if (isProxy(props) || InternalObjectKey in props) { props = extend({}, props) } let { class: klass, style } = props if (klass && !isString(klass)) { props.class = normalizeClass(klass) } if (isObject(style)) { // reactive state objects need to be cloned since they are likely to be // mutated if (isProxy(style) && !isArray(style)) { style = extend({}, style) } props.style = normalizeStyle(style) } } // encode the vnode type information into a bitmap const shapeFlag = isString(type) ? ShapeFlags.ELEMENT : __FEATURE_SUSPENSE__ && isSuspense(type) ? ShapeFlags.SUSPENSE : isTeleport(type) ? ShapeFlags.TELEPORT : isObject(type) ? ShapeFlags.STATEFUL_COMPONENT : isFunction(type) ? ShapeFlags.FUNCTIONAL_COMPONENT : 0 if (__DEV__ && shapeFlag & ShapeFlags.STATEFUL_COMPONENT && isProxy(type)) { type = toRaw(type) warn( `Vue received a Component which was made a reactive object. This can ` + `lead to unnecessary performance overhead, and should be avoided by ` + `marking the component with \`markRaw\` or using \`shallowRef\` ` + `instead of \`ref\`.`, `\nComponent that was made reactive: `, type ) } // VNode的初始值定义。包含VNode的所有属性参数。 const vnode: VNode = { __v_isVNode: true, [ReactiveFlags.SKIP]: true, type, props, key: props && normalizeKey(props), ref: props && normalizeRef(props), scopeId: currentScopeId, slotScopeIds: null, children: null, component: null, suspense: null, ssContent: null, ssFallback: null, dirs: null, transition: null, el: null, anchor: null, target: null, targetAnchor: null, staticCount: 0, shapeFlag, patchFlag, dynamicProps, dynamicChildren: null, appContext: null } // validate key if (__DEV__ && vnode.key !== vnode.key) { warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type) } normalizeChildren(vnode, children) // normalize suspense children if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) { const { content, fallback } = normalizeSuspenseChildren(vnode) vnode.ssContent = content vnode.ssFallback = fallback } if ( shouldTrack > 0 && // avoid a block node from tracking itself !isBlockNode && // has current parent block currentBlock && // presence of a patch flag indicates this node needs patching on updates. // component nodes also should always be patched, because even if the // component doesn't need to update, it needs to persist the instance on to // the next vnode so that it can be properly unmounted later. (patchFlag > 0 || shapeFlag & ShapeFlags.COMPONENT) && // the EVENTS flag is only for hydration and if it is the only flag, the // vnode should not be considered dynamic due to handler caching. patchFlag !== PatchFlags.HYDRATE_EVENTS ) { currentBlock.push(vnode) } return vnode }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3