返回一个”虚拟节点“,通常缩写为 VNode:一个普通对象,其中包含向 Vue 描述它应在页面上渲染哪种节点的信息,包括所有子节点的描述。它的目的是用于手动编写的渲染函数:
render() {
return h('h1', {}, 'Some title')
}
参数
type
- 类型:String | Object | Function
详细:HTML 标签名、组件、异步组件或函数式组件。使用返回 null 的函数将渲染一个注释。此参数是必需的。
props
类型:Object
详细:一个对象,与我们将在模板中使用的 attribute、prop 和事件相对应。可选。
children
类型:String | Array | Object
- 详细:子代 VNode,使用 h() 生成,或者使用字符串来获取“文本 VNode”,或带有插槽的对象。可选。
h('div', {}, [
'Some text comes first.',
h('h1', 'A headline'),
h(MyComponent, {
someProp: 'foobar'
})
])
源码
```javascript // type 元素的类型 // propsOrChildren 数据对象, 这里主要表示(props, attrs, dom props, class 和 style) // children 子节点也是一个any类型
export function h(type: any, propsOrChildren?: any, children?: any): VNode { if (arguments.length === 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 (isVNode(children)) { children = [children] } return createVNode(type, propsOrChildren, children) } }
function createVNode(
type: VNodeTypes | ClassComponent | typeof NULLDYNAMIC_COMPONENT,
props: (Data & VNodeProps) | null = null,
children: unknown = null,
// 更新标志
patchFlag: number = 0,
// 自定义属性
dynamicProps: string[] | null = null,
// 是否是动态节点,(v-if v-for)
isBlockNode = false
): VNode {
// type必传参数
if (!type || type === NULL_DYNAMIC_COMPONENT) {
if (__DEV && !type) {
warn(Invalid vnode type when creating vnode: ${type}.
)
}
type = Comment
}
// Class 类型的type标准化 // class component normalization. if (isFunction(type) && ‘vccOpts’ in type) { type = type.vccOpts }
// class & style normalization. if (props) { // props 如果是响应式,clone 一个副本 if (isProxy(props) || InternalObjectKey in props) { props = extend({}, props) } let { class: klass, style } = props
// 标准化class, 支持 string , array, object 三种形式
if (klass && !isString(klass)) {
props.class = normalizeClass(klass)
}
// 标准化style, 支持 array ,object 两种形式
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 模型 const vnode: VNode = { v_isVNode: true, v_skip: true, type, props, key: props && normalizeKey(props), ref: props && normalizeRef(props), scopeId: currentScopeId, children: null, component: null, suspense: null, dirs: null, transition: null, el: null, anchor: null, target: null, targetAnchor: null, staticCount: 0, shapeFlag, patchFlag, dynamicProps, dynamicChildren: null, appContext: null }
normalizeChildren(vnode, children)
// 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 标志存在表示节点需要更新,组件节点一直存在 patchFlag,因为即使不需要更新,它需要将实例持久化到下一个 vnode,以便以后可以正确卸载它 if ( shouldTrack > 0 && !isBlockNode && currentBlock && // 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 && (patchFlag > 0 || shapeFlag & ShapeFlags.SUSPENSE || shapeFlag & ShapeFlags.TELEPORT || shapeFlag & ShapeFlags.STATEFUL_COMPONENT || shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT) ) { // 压入 VNode 栈 currentBlock.push(vnode) }
return vnode } ```