mirror of https://github.com/vuejs/core.git
feat(runtime-vapor): fallback component (#232)
* feat(runtime-vapor): fallback component * fix
This commit is contained in:
parent
f85ac40f6c
commit
c91586528a
|
@ -134,7 +134,6 @@ describe('api: createVaporApp', () => {
|
|||
setup() {
|
||||
const FooBar = resolveComponent('foo-bar')
|
||||
const BarBaz = resolveComponent('bar-baz')
|
||||
// @ts-expect-error TODO support string
|
||||
return [createComponent(FooBar), createComponent(BarBaz)]
|
||||
},
|
||||
}).create()
|
||||
|
|
|
@ -5,17 +5,30 @@ import {
|
|||
currentInstance,
|
||||
} from './component'
|
||||
import { setupComponent } from './apiRender'
|
||||
import type { RawProps } from './componentProps'
|
||||
import type { RawSlots } from './componentSlots'
|
||||
import {
|
||||
type NormalizedRawProps,
|
||||
type RawProps,
|
||||
normalizeRawProps,
|
||||
walkRawProps,
|
||||
} from './componentProps'
|
||||
import { type RawSlots, isDynamicSlotFn } from './componentSlots'
|
||||
import { withAttrs } from './componentAttrs'
|
||||
import { isString } from '@vue/shared'
|
||||
import { renderEffect } from './renderEffect'
|
||||
import { normalizeBlock } from './dom/element'
|
||||
import { setDynamicProp } from './dom/prop'
|
||||
|
||||
export function createComponent(
|
||||
comp: Component,
|
||||
comp: Component | string,
|
||||
rawProps: RawProps | null = null,
|
||||
slots: RawSlots | null = null,
|
||||
singleRoot: boolean = false,
|
||||
once: boolean = false,
|
||||
): ComponentInternalInstance {
|
||||
): ComponentInternalInstance | HTMLElement {
|
||||
if (isString(comp)) {
|
||||
return fallbackComponent(comp, rawProps, slots)
|
||||
}
|
||||
|
||||
const current = currentInstance!
|
||||
const instance = createComponentInstance(
|
||||
comp,
|
||||
|
@ -30,3 +43,34 @@ export function createComponent(
|
|||
|
||||
return instance
|
||||
}
|
||||
|
||||
function fallbackComponent(
|
||||
comp: string,
|
||||
rawProps: RawProps | null,
|
||||
slots: RawSlots | null,
|
||||
): HTMLElement {
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
const el = document.createElement(comp)
|
||||
|
||||
if (rawProps) {
|
||||
rawProps = normalizeRawProps(rawProps)
|
||||
renderEffect(() => {
|
||||
walkRawProps(rawProps as NormalizedRawProps, (key, value, getter) => {
|
||||
setDynamicProp(el, key, getter ? value() : value)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (slots) {
|
||||
if (!Array.isArray(slots)) slots = [slots]
|
||||
for (let i = 0; i < slots.length; i++) {
|
||||
const slot = slots[i]
|
||||
if (!isDynamicSlotFn(slot) && slot.default) {
|
||||
const block = slot.default && slot.default()
|
||||
if (block) el.append(...normalizeBlock(block))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return el
|
||||
}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import { camelize, isArray, isFunction } from '@vue/shared'
|
||||
import { camelize, isArray } from '@vue/shared'
|
||||
import { type ComponentInternalInstance, currentInstance } from './component'
|
||||
import { isEmitListener } from './componentEmits'
|
||||
import { setDynamicProps } from './dom/prop'
|
||||
import type { RawProps } from './componentProps'
|
||||
import { type RawProps, walkRawProps } from './componentProps'
|
||||
import { renderEffect } from './renderEffect'
|
||||
|
||||
export function patchAttrs(instance: ComponentInternalInstance): void {
|
||||
|
@ -14,19 +14,8 @@ export function patchAttrs(instance: ComponentInternalInstance): void {
|
|||
|
||||
if (!rawProps.length) return
|
||||
const keys = new Set<string>()
|
||||
for (const props of Array.from(rawProps).reverse()) {
|
||||
if (isFunction(props)) {
|
||||
const resolved = props()
|
||||
for (const rawKey in resolved) {
|
||||
registerAttr(rawKey, resolved[rawKey])
|
||||
}
|
||||
} else {
|
||||
for (const rawKey in props) {
|
||||
registerAttr(rawKey, props[rawKey], true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
walkRawProps(rawProps, registerAttr)
|
||||
for (const key in attrs) {
|
||||
if (!keys.has(key)) {
|
||||
delete attrs[key]
|
||||
|
|
|
@ -83,10 +83,7 @@ export function initProps(
|
|||
isStateful: boolean,
|
||||
once: boolean,
|
||||
): void {
|
||||
if (!rawProps) rawProps = []
|
||||
else if (!isArray(rawProps)) rawProps = [rawProps]
|
||||
instance.rawProps = rawProps
|
||||
|
||||
instance.rawProps = rawProps = normalizeRawProps(rawProps)
|
||||
const props: Data = {}
|
||||
const attrs = (instance.attrs = shallowReactive<Data>({}))
|
||||
const [options] = instance.propsOptions
|
||||
|
@ -166,6 +163,30 @@ function registerProp(
|
|||
}
|
||||
}
|
||||
|
||||
export function normalizeRawProps(rawProps: RawProps): NormalizedRawProps {
|
||||
if (!rawProps) return []
|
||||
if (!isArray(rawProps)) return [rawProps]
|
||||
return rawProps
|
||||
}
|
||||
|
||||
export function walkRawProps(
|
||||
rawProps: NormalizedRawProps,
|
||||
cb: (key: string, value: any, getter?: boolean) => void,
|
||||
): void {
|
||||
for (const props of Array.from(rawProps).reverse()) {
|
||||
if (isFunction(props)) {
|
||||
const resolved = props()
|
||||
for (const rawKey in resolved) {
|
||||
cb(rawKey, resolved[rawKey])
|
||||
}
|
||||
} else {
|
||||
for (const rawKey in props) {
|
||||
cb(rawKey, props[rawKey], true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getRawKey(obj: Data, key: string) {
|
||||
return Object.keys(obj).find(k => camelize(k) === key)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue