element-plus/packages/utils/vnode.ts

131 lines
2.9 KiB
TypeScript
Raw Normal View History

import {
Fragment,
Text,
Comment,
createBlock,
openBlock,
createCommentVNode,
isVNode,
camelize,
} from 'vue'
2020-09-14 10:03:33 +08:00
import { hasOwn } from '@vue/shared'
import { debugWarn } from './error'
import type { VNode, VNodeTypes, VNodeChild } from 'vue'
2020-09-15 21:58:36 +08:00
type Children = VNodeTypes[] | VNodeTypes
2020-09-15 21:58:36 +08:00
const TEMPLATE = 'template'
export const SCOPE = 'VNode'
2020-09-21 15:39:53 +08:00
export enum PatchFlags {
2020-09-15 21:58:36 +08:00
TEXT = 1,
CLASS = 2,
STYLE = 4,
PROPS = 8,
FULL_PROPS = 16,
HYDRATE_EVENTS = 32,
STABLE_FRAGMENT = 64,
KEYED_FRAGMENT = 128,
UNKEYED_FRAGMENT = 256,
NEED_PATCH = 512,
DYNAMIC_SLOTS = 1024,
HOISTED = -1,
BAIL = -2,
}
2020-09-14 10:03:33 +08:00
export const isFragment = (node: unknown): node is VNode =>
isVNode(node) && node.type === Fragment
2020-09-14 10:03:33 +08:00
export const isText = (node: VNodeChild) => (node as VNode).type === Text
2020-09-14 10:03:33 +08:00
export const isComment = (node: VNodeChild) => (node as VNode).type === Comment
2020-09-14 10:03:33 +08:00
export const isTemplate = (node: VNodeChild) =>
(node as VNode).type === TEMPLATE
2020-09-15 21:58:36 +08:00
/**
* get a valid child node (not fragment nor comment)
* @param node {VNode} node to be searched
* @param depth {number} depth to be searched
*/
function getChildren(node: VNode, depth: number): undefined | VNode {
if (isComment(node)) return
if (isFragment(node) || isTemplate(node)) {
return depth > 0
? getFirstValidNode(node.children as VNodeChild, depth - 1)
: undefined
}
return node
}
2020-09-14 10:03:33 +08:00
/**
* determine if the element is a valid element type rather than fragments and comment e.g. <template> v-if
* @param node {VNode} node to be tested
*/
export const isValidElementNode = (node: unknown): node is VNode =>
isVNode(node) && !isFragment(node) && !isComment(node)
2020-09-14 10:03:33 +08:00
2020-09-15 21:58:36 +08:00
export const getFirstValidNode = (
nodes: VNodeChild,
maxDepth = 3
2020-09-15 21:58:36 +08:00
): ReturnType<typeof getChildren> => {
if (Array.isArray(nodes)) {
return getChildren(nodes[0] as VNode, maxDepth)
2020-09-15 21:58:36 +08:00
} else {
return getChildren(nodes as VNode, maxDepth)
2020-09-14 10:03:33 +08:00
}
}
2020-09-15 21:58:36 +08:00
export function renderIf(
condition: boolean,
node: VNodeTypes,
props: any,
children?: Children,
2020-09-15 21:58:36 +08:00
patchFlag?: number,
patchProps?: string[]
2020-09-15 21:58:36 +08:00
) {
return condition
? renderBlock(node, props, children, patchFlag, patchProps)
: createCommentVNode('v-if', true)
2020-09-15 21:58:36 +08:00
}
export function renderBlock(
node: VNodeTypes,
props: any,
children?: Children,
2020-09-15 21:58:36 +08:00
patchFlag?: number,
patchProps?: string[]
2020-09-15 21:58:36 +08:00
) {
return openBlock(), createBlock(node, props, children, patchFlag, patchProps)
2020-09-15 21:58:36 +08:00
}
/**
* todo
* get normalized props from VNode
* @param node
*/
export const getNormalizedProps = (node: VNode) => {
if (!isVNode(node)) {
debugWarn(SCOPE, 'value must be a VNode')
return
}
const raw = node.props || {}
const type = (node.type as any).props || {}
const props = {} as any
Object.keys(type).forEach((key) => {
if (hasOwn(type[key], 'default')) {
props[key] = type[key].default
}
})
Object.keys(raw).forEach((key) => {
props[camelize(key)] = raw[key]
})
return props
}