feat(runtime): 添加 h 函数和虚拟节点系统
- 实现了 h 函数用于创建虚拟节点 - 添加了 VNode 接口定义和创建逻辑 - 引入了 ShapeFlags 枚举来标记节点类型 - 实现了虚拟节点子元素标准化功能 - 在 runtime-core 中导出 h 函数 - 添加了 h 函数使用示例页面
This commit is contained in:
25
packages/runtime-core/src/h.ts
Normal file
25
packages/runtime-core/src/h.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { createVNode, isVNode, VNode } from './vnode'
|
||||
import { isObject } from '@vue/shared'
|
||||
|
||||
export function h(type: any, propsOrChildren?: any, children?: any): VNode {
|
||||
const l = arguments.length
|
||||
if (l === 2) {
|
||||
//是对象
|
||||
if (isObject(propsOrChildren) && !Array.isArray(propsOrChildren)) {
|
||||
if (isVNode(propsOrChildren)) {
|
||||
return createVNode(type, null, [propsOrChildren])
|
||||
}
|
||||
return createVNode(type, propsOrChildren, [])
|
||||
} else {
|
||||
//是数组
|
||||
return createVNode(type, null, propsOrChildren)
|
||||
}
|
||||
} else {
|
||||
if (l > 3) {
|
||||
children = Array.prototype.slice.call(arguments, 2) //生成新的children
|
||||
} else if (l === 3 && isVNode(children)) {
|
||||
children = [children]
|
||||
}
|
||||
return createVNode(type, propsOrChildren, children)
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
export { queuePreFlushCb } from './scheduler'
|
||||
export { watch } from './apiWatch'
|
||||
export { h } from './h'
|
||||
|
||||
43
packages/runtime-core/src/vnode.ts
Normal file
43
packages/runtime-core/src/vnode.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { isArray, isFunction, isString, ShapeFlags } from '@vue/shared'
|
||||
|
||||
export interface VNode {
|
||||
__v_isVNode: true
|
||||
type: any
|
||||
props: any
|
||||
children: any
|
||||
shapeFlag: number
|
||||
}
|
||||
export function isVNode(value): value is VNode {
|
||||
return value ? value.__v_isVNode === true : false
|
||||
}
|
||||
export function createVNode(type, props, children): VNode {
|
||||
const shapeFlag = isString(type) ? ShapeFlags.ELEMENT : 0
|
||||
return createBaseVNode(type, props, children, shapeFlag)
|
||||
}
|
||||
|
||||
function createBaseVNode(type, props, children, shapeFlag) {
|
||||
const vnode = {
|
||||
__v_isVNode: true,
|
||||
type,
|
||||
props,
|
||||
shapeFlag
|
||||
} as VNode
|
||||
//解析/标准化当前vnode下的children
|
||||
normalizeChildren(vnode, children)
|
||||
return vnode
|
||||
}
|
||||
export function normalizeChildren(vnode: VNode, children: unknown) {
|
||||
let type = 0
|
||||
const { shapeFlag } = vnode
|
||||
if (children == null) {
|
||||
children = null
|
||||
} else if (isArray(children)) {
|
||||
} else if (typeof children === 'object') {
|
||||
} else if (isFunction(children)) {
|
||||
} else {
|
||||
children = String(children)
|
||||
type = ShapeFlags.TEXT_CHILDREN
|
||||
}
|
||||
vnode.children = children
|
||||
vnode.shapeFlag |= type
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export { ShapeFlags } from './shapeFlags'
|
||||
//判断是否为一个数组
|
||||
export const isArray = Array.isArray
|
||||
|
||||
@@ -14,6 +15,10 @@ export const isFunction = (val: unknown): val is Function => {
|
||||
return typeof val === 'function'
|
||||
}
|
||||
|
||||
export const isString = (val: unknown): val is string => {
|
||||
return typeof val === 'string'
|
||||
}
|
||||
|
||||
export const extend = Object.assign
|
||||
|
||||
export const EMPTY_OBJ: { readonly [key: string]: any } = {}
|
||||
|
||||
30
packages/shared/src/shapeFlags.ts
Normal file
30
packages/shared/src/shapeFlags.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
export const enum ShapeFlags {
|
||||
/**
|
||||
* type=Element
|
||||
*/
|
||||
ELEMENT = 1,
|
||||
/**
|
||||
* 函数组件
|
||||
*/
|
||||
FUNCTIONAL_COMPONENT = 1 << 1,
|
||||
/**
|
||||
* 有状态(响应数据)组件
|
||||
*/
|
||||
STATEFUL_COMPONENT = 1 << 2,
|
||||
/**
|
||||
* children=Text
|
||||
*/
|
||||
TEXT_CHILDREN = 1 << 3,
|
||||
/**
|
||||
* children=Array
|
||||
*/
|
||||
ARRAY_CHILDREN = 1 << 4,
|
||||
/**
|
||||
* children=slot
|
||||
*/
|
||||
SLOTS__CHILDREN = 1 << 5,
|
||||
/**
|
||||
* 组件: 有状态(响应数据)组件 | 函数组件
|
||||
*/
|
||||
COMPONENT = ShapeFlags.STATEFUL_COMPONENT | ShapeFlags.FUNCTIONAL_COMPONENT
|
||||
}
|
||||
18
packages/vue/examples/runtime/h-element.html
Normal file
18
packages/vue/examples/runtime/h-element.html
Normal file
@@ -0,0 +1,18 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Document</title>
|
||||
<script src="../../dist/vue.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
</body>
|
||||
<script>
|
||||
const {h} =Vue
|
||||
const vnode=h('div',{
|
||||
class:'test'
|
||||
},'hello render')
|
||||
console.log(vnode)
|
||||
</script>
|
||||
</html>
|
||||
@@ -1,2 +1,2 @@
|
||||
export { reactive, effect, ref, computed } from '@vue/reactivity'
|
||||
export { queuePreFlushCb, watch } from '@vue/runtime-core'
|
||||
export { queuePreFlushCb, watch, h } from '@vue/runtime-core'
|
||||
|
||||
Reference in New Issue
Block a user