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() {
|
setup() {
|
||||||
const FooBar = resolveComponent('foo-bar')
|
const FooBar = resolveComponent('foo-bar')
|
||||||
const BarBaz = resolveComponent('bar-baz')
|
const BarBaz = resolveComponent('bar-baz')
|
||||||
// @ts-expect-error TODO support string
|
|
||||||
return [createComponent(FooBar), createComponent(BarBaz)]
|
return [createComponent(FooBar), createComponent(BarBaz)]
|
||||||
},
|
},
|
||||||
}).create()
|
}).create()
|
||||||
|
|
|
@ -5,17 +5,30 @@ import {
|
||||||
currentInstance,
|
currentInstance,
|
||||||
} from './component'
|
} from './component'
|
||||||
import { setupComponent } from './apiRender'
|
import { setupComponent } from './apiRender'
|
||||||
import type { RawProps } from './componentProps'
|
import {
|
||||||
import type { RawSlots } from './componentSlots'
|
type NormalizedRawProps,
|
||||||
|
type RawProps,
|
||||||
|
normalizeRawProps,
|
||||||
|
walkRawProps,
|
||||||
|
} from './componentProps'
|
||||||
|
import { type RawSlots, isDynamicSlotFn } from './componentSlots'
|
||||||
import { withAttrs } from './componentAttrs'
|
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(
|
export function createComponent(
|
||||||
comp: Component,
|
comp: Component | string,
|
||||||
rawProps: RawProps | null = null,
|
rawProps: RawProps | null = null,
|
||||||
slots: RawSlots | null = null,
|
slots: RawSlots | null = null,
|
||||||
singleRoot: boolean = false,
|
singleRoot: boolean = false,
|
||||||
once: boolean = false,
|
once: boolean = false,
|
||||||
): ComponentInternalInstance {
|
): ComponentInternalInstance | HTMLElement {
|
||||||
|
if (isString(comp)) {
|
||||||
|
return fallbackComponent(comp, rawProps, slots)
|
||||||
|
}
|
||||||
|
|
||||||
const current = currentInstance!
|
const current = currentInstance!
|
||||||
const instance = createComponentInstance(
|
const instance = createComponentInstance(
|
||||||
comp,
|
comp,
|
||||||
|
@ -30,3 +43,34 @@ export function createComponent(
|
||||||
|
|
||||||
return instance
|
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 { type ComponentInternalInstance, currentInstance } from './component'
|
||||||
import { isEmitListener } from './componentEmits'
|
import { isEmitListener } from './componentEmits'
|
||||||
import { setDynamicProps } from './dom/prop'
|
import { setDynamicProps } from './dom/prop'
|
||||||
import type { RawProps } from './componentProps'
|
import { type RawProps, walkRawProps } from './componentProps'
|
||||||
import { renderEffect } from './renderEffect'
|
import { renderEffect } from './renderEffect'
|
||||||
|
|
||||||
export function patchAttrs(instance: ComponentInternalInstance): void {
|
export function patchAttrs(instance: ComponentInternalInstance): void {
|
||||||
|
@ -14,19 +14,8 @@ export function patchAttrs(instance: ComponentInternalInstance): void {
|
||||||
|
|
||||||
if (!rawProps.length) return
|
if (!rawProps.length) return
|
||||||
const keys = new Set<string>()
|
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) {
|
for (const key in attrs) {
|
||||||
if (!keys.has(key)) {
|
if (!keys.has(key)) {
|
||||||
delete attrs[key]
|
delete attrs[key]
|
||||||
|
|
|
@ -83,10 +83,7 @@ export function initProps(
|
||||||
isStateful: boolean,
|
isStateful: boolean,
|
||||||
once: boolean,
|
once: boolean,
|
||||||
): void {
|
): void {
|
||||||
if (!rawProps) rawProps = []
|
instance.rawProps = rawProps = normalizeRawProps(rawProps)
|
||||||
else if (!isArray(rawProps)) rawProps = [rawProps]
|
|
||||||
instance.rawProps = rawProps
|
|
||||||
|
|
||||||
const props: Data = {}
|
const props: Data = {}
|
||||||
const attrs = (instance.attrs = shallowReactive<Data>({}))
|
const attrs = (instance.attrs = shallowReactive<Data>({}))
|
||||||
const [options] = instance.propsOptions
|
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) {
|
function getRawKey(obj: Data, key: string) {
|
||||||
return Object.keys(obj).find(k => camelize(k) === key)
|
return Object.keys(obj).find(k => camelize(k) === key)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue