feat(core): support dynamic component via <component :is> (#320)

This commit is contained in:
宋铄运
2019-10-19 00:09:04 +08:00
committed by Evan You
parent d179918001
commit 7f23eaf661
6 changed files with 133 additions and 22 deletions

View File

@@ -7,6 +7,9 @@ export const OPEN_BLOCK = Symbol(__DEV__ ? `openBlock` : ``)
export const CREATE_BLOCK = Symbol(__DEV__ ? `createBlock` : ``)
export const CREATE_VNODE = Symbol(__DEV__ ? `createVNode` : ``)
export const RESOLVE_COMPONENT = Symbol(__DEV__ ? `resolveComponent` : ``)
export const RESOLVE_DYNAMIC_COMPONENT = Symbol(
__DEV__ ? `resolveDynamicComponent` : ``
)
export const RESOLVE_DIRECTIVE = Symbol(__DEV__ ? `resolveDirective` : ``)
export const APPLY_DIRECTIVES = Symbol(__DEV__ ? `applyDirectives` : ``)
export const RENDER_LIST = Symbol(__DEV__ ? `renderList` : ``)
@@ -30,6 +33,7 @@ export const helperNameMap: any = {
[CREATE_BLOCK]: `createBlock`,
[CREATE_VNODE]: `createVNode`,
[RESOLVE_COMPONENT]: `resolveComponent`,
[RESOLVE_DYNAMIC_COMPONENT]: `resolveDynamicComponent`,
[RESOLVE_DIRECTIVE]: `resolveDirective`,
[APPLY_DIRECTIVES]: `applyDirectives`,
[RENDER_LIST]: `renderList`,

View File

@@ -22,12 +22,13 @@ import {
APPLY_DIRECTIVES,
RESOLVE_DIRECTIVE,
RESOLVE_COMPONENT,
RESOLVE_DYNAMIC_COMPONENT,
MERGE_PROPS,
TO_HANDLERS,
PORTAL,
SUSPENSE
} from '../runtimeHelpers'
import { getInnerRange, isVSlot, toValidAssetId } from '../utils'
import { getInnerRange, isVSlot, toValidAssetId, findProp } from '../utils'
import { buildSlots } from './vSlot'
import { isStaticNode } from './hoistStatic'
@@ -55,24 +56,55 @@ export const transformElement: NodeTransform = (node, context) => {
let patchFlag: number = 0
let runtimeDirectives: DirectiveNode[] | undefined
let dynamicPropNames: string[] | undefined
let dynamicComponent: string | CallExpression | undefined
if (isComponent) {
// handle dynamic component
const isProp = findProp(node, 'is')
if (node.tag === 'component') {
if (isProp) {
// static <component is="foo" />
if (isProp.type === NodeTypes.ATTRIBUTE) {
const tag = isProp.value && isProp.value.content
if (tag) {
context.helper(RESOLVE_COMPONENT)
context.components.add(tag)
dynamicComponent = toValidAssetId(tag, `component`)
}
}
// dynamic <component :is="asdf" />
else if (isProp.exp) {
dynamicComponent = createCallExpression(
context.helper(RESOLVE_DYNAMIC_COMPONENT),
[isProp.exp]
)
}
}
}
if (isComponent && !dynamicComponent) {
context.helper(RESOLVE_COMPONENT)
context.components.add(node.tag)
}
const args: CallExpression['arguments'] = [
isComponent
? toValidAssetId(node.tag, `component`)
: node.tagType === ElementTypes.PORTAL
? context.helper(PORTAL)
: node.tagType === ElementTypes.SUSPENSE
? context.helper(SUSPENSE)
: `"${node.tag}"`
dynamicComponent
? dynamicComponent
: isComponent
? toValidAssetId(node.tag, `component`)
: node.tagType === ElementTypes.PORTAL
? context.helper(PORTAL)
: node.tagType === ElementTypes.SUSPENSE
? context.helper(SUSPENSE)
: `"${node.tag}"`
]
// props
if (hasProps) {
const propsBuildResult = buildProps(node, context)
const propsBuildResult = buildProps(
node,
context,
// skip reserved "is" prop <component is>
node.props.filter(p => p !== isProp)
)
patchFlag = propsBuildResult.patchFlag
dynamicPropNames = propsBuildResult.dynamicPropNames
runtimeDirectives = propsBuildResult.directives