mirror of https://github.com/vuejs/core.git
wip(vapor): createDynamicComponent
This commit is contained in:
parent
cad7f0e583
commit
9f1025d854
|
@ -270,19 +270,19 @@ export function render(_ctx) {
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: element transform > dynamic component > dynamic binding 1`] = `
|
exports[`compiler: element transform > dynamic component > dynamic binding 1`] = `
|
||||||
"import { resolveDynamicComponent as _resolveDynamicComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
"import { createDynamicComponent as _createDynamicComponent } from 'vue';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
const n0 = _createComponentWithFallback(_resolveDynamicComponent(_ctx.foo), null, null, true)
|
const n0 = _createDynamicComponent(() => (_ctx.foo), null, null, true)
|
||||||
return n0
|
return n0
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: element transform > dynamic component > dynamic binding shorthand 1`] = `
|
exports[`compiler: element transform > dynamic component > dynamic binding shorthand 1`] = `
|
||||||
"import { resolveDynamicComponent as _resolveDynamicComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
|
"import { createDynamicComponent as _createDynamicComponent } from 'vue';
|
||||||
|
|
||||||
export function render(_ctx) {
|
export function render(_ctx) {
|
||||||
const n0 = _createComponentWithFallback(_resolveDynamicComponent(_ctx.is), null, null, true)
|
const n0 = _createDynamicComponent(() => (_ctx.is), null, null, true)
|
||||||
return n0
|
return n0
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -525,7 +525,7 @@ describe('compiler: element transform', () => {
|
||||||
`<component :is="foo" />`,
|
`<component :is="foo" />`,
|
||||||
)
|
)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
expect(helpers).toContain('resolveDynamicComponent')
|
expect(helpers).toContain('createDynamicComponent')
|
||||||
expect(ir.block.operation).toMatchObject([
|
expect(ir.block.operation).toMatchObject([
|
||||||
{
|
{
|
||||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||||
|
@ -546,7 +546,7 @@ describe('compiler: element transform', () => {
|
||||||
const { code, ir, helpers } =
|
const { code, ir, helpers } =
|
||||||
compileWithElementTransform(`<component :is />`)
|
compileWithElementTransform(`<component :is />`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
expect(helpers).toContain('resolveDynamicComponent')
|
expect(helpers).toContain('createDynamicComponent')
|
||||||
expect(ir.block.operation).toMatchObject([
|
expect(ir.block.operation).toMatchObject([
|
||||||
{
|
{
|
||||||
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
type: IRNodeTypes.CREATE_COMPONENT_NODE,
|
||||||
|
|
|
@ -64,9 +64,11 @@ export function genCreateComponent(
|
||||||
...inlineHandlers,
|
...inlineHandlers,
|
||||||
`const n${operation.id} = `,
|
`const n${operation.id} = `,
|
||||||
...genCall(
|
...genCall(
|
||||||
operation.asset
|
operation.dynamic && !operation.dynamic.isStatic
|
||||||
? helper('createComponentWithFallback')
|
? helper('createDynamicComponent')
|
||||||
: helper('createComponent'),
|
: operation.asset
|
||||||
|
? helper('createComponentWithFallback')
|
||||||
|
: helper('createComponent'),
|
||||||
tag,
|
tag,
|
||||||
rawProps,
|
rawProps,
|
||||||
rawSlots,
|
rawSlots,
|
||||||
|
@ -78,10 +80,14 @@ export function genCreateComponent(
|
||||||
|
|
||||||
function genTag() {
|
function genTag() {
|
||||||
if (operation.dynamic) {
|
if (operation.dynamic) {
|
||||||
return genCall(
|
if (operation.dynamic.isStatic) {
|
||||||
helper('resolveDynamicComponent'),
|
return genCall(
|
||||||
genExpression(operation.dynamic, context),
|
helper('resolveDynamicComponent'),
|
||||||
)
|
genExpression(operation.dynamic, context),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return ['() => (', ...genExpression(operation.dynamic, context), ')']
|
||||||
|
}
|
||||||
} else if (operation.asset) {
|
} else if (operation.asset) {
|
||||||
return toValidAssetId(operation.tag, 'component')
|
return toValidAssetId(operation.tag, 'component')
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { shallowRef } from '@vue/reactivity'
|
||||||
|
import { nextTick } from '@vue/runtime-dom'
|
||||||
|
import { createDynamicComponent } from '../src'
|
||||||
|
import { makeRender } from './_utils'
|
||||||
|
|
||||||
|
const define = makeRender()
|
||||||
|
|
||||||
|
describe('api: createDynamicComponent', () => {
|
||||||
|
const A = () => document.createTextNode('AAA')
|
||||||
|
const B = () => document.createTextNode('BBB')
|
||||||
|
|
||||||
|
test('direct value', async () => {
|
||||||
|
const val = shallowRef<any>(A)
|
||||||
|
|
||||||
|
const { html } = define({
|
||||||
|
setup() {
|
||||||
|
return createDynamicComponent(() => val.value)
|
||||||
|
},
|
||||||
|
}).render()
|
||||||
|
|
||||||
|
expect(html()).toBe('AAA<!--dynamic-component-->')
|
||||||
|
|
||||||
|
val.value = B
|
||||||
|
await nextTick()
|
||||||
|
expect(html()).toBe('BBB<!--dynamic-component-->')
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
val.value = 'foo'
|
||||||
|
await nextTick()
|
||||||
|
expect(html()).toBe('<foo></foo><!--dynamic-component-->')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('global registration', async () => {
|
||||||
|
const val = shallowRef('foo')
|
||||||
|
|
||||||
|
const { app, html, mount } = define({
|
||||||
|
setup() {
|
||||||
|
return createDynamicComponent(() => val.value)
|
||||||
|
},
|
||||||
|
}).create()
|
||||||
|
|
||||||
|
app.component('foo', A)
|
||||||
|
app.component('bar', B)
|
||||||
|
|
||||||
|
mount()
|
||||||
|
expect(html()).toBe('AAA<!--dynamic-component-->')
|
||||||
|
|
||||||
|
val.value = 'bar'
|
||||||
|
await nextTick()
|
||||||
|
expect(html()).toBe('BBB<!--dynamic-component-->')
|
||||||
|
|
||||||
|
// fallback
|
||||||
|
val.value = 'baz'
|
||||||
|
await nextTick()
|
||||||
|
expect(html()).toBe('<baz></baz><!--dynamic-component-->')
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { resolveDynamicComponent } from '@vue/runtime-dom'
|
||||||
|
import { DynamicFragment, type Fragment } from './block'
|
||||||
|
import { createComponentWithFallback } from './component'
|
||||||
|
import { renderEffect } from './renderEffect'
|
||||||
|
import type { RawProps } from './componentProps'
|
||||||
|
import type { RawSlots } from './componentSlots'
|
||||||
|
|
||||||
|
export function createDynamicComponent(
|
||||||
|
getter: () => any,
|
||||||
|
rawProps?: RawProps | null,
|
||||||
|
rawSlots?: RawSlots | null,
|
||||||
|
isSingleRoot?: boolean,
|
||||||
|
): Fragment {
|
||||||
|
const frag = __DEV__
|
||||||
|
? new DynamicFragment('dynamic-component')
|
||||||
|
: new DynamicFragment()
|
||||||
|
renderEffect(() => {
|
||||||
|
const value = getter()
|
||||||
|
frag.update(
|
||||||
|
() =>
|
||||||
|
createComponentWithFallback(
|
||||||
|
resolveDynamicComponent(value) as any,
|
||||||
|
rawProps,
|
||||||
|
rawSlots,
|
||||||
|
isSingleRoot,
|
||||||
|
),
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
return frag
|
||||||
|
}
|
|
@ -41,11 +41,11 @@ export class DynamicFragment extends Fragment {
|
||||||
document.createTextNode('')
|
document.createTextNode('')
|
||||||
}
|
}
|
||||||
|
|
||||||
update(render?: BlockFn): void {
|
update(render?: BlockFn, key: any = render): void {
|
||||||
if (render === this.current) {
|
if (key === this.current) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.current = render
|
this.current = key
|
||||||
|
|
||||||
pauseTracking()
|
pauseTracking()
|
||||||
const parent = this.anchor.parentNode
|
const parent = this.anchor.parentNode
|
||||||
|
|
|
@ -444,8 +444,8 @@ export function isVaporComponent(
|
||||||
*/
|
*/
|
||||||
export function createComponentWithFallback(
|
export function createComponentWithFallback(
|
||||||
comp: VaporComponent | string,
|
comp: VaporComponent | string,
|
||||||
rawProps: RawProps | null | undefined,
|
rawProps?: RawProps | null,
|
||||||
rawSlots: RawSlots | null | undefined,
|
rawSlots?: RawSlots | null,
|
||||||
isSingleRoot?: boolean,
|
isSingleRoot?: boolean,
|
||||||
): HTMLElement | VaporComponentInstance {
|
): HTMLElement | VaporComponentInstance {
|
||||||
if (!isString(comp)) {
|
if (!isString(comp)) {
|
||||||
|
|
|
@ -29,3 +29,4 @@ export {
|
||||||
getDefaultValue,
|
getDefaultValue,
|
||||||
} from './apiCreateFor'
|
} from './apiCreateFor'
|
||||||
export { createTemplateRefSetter } from './apiTemplateRef'
|
export { createTemplateRefSetter } from './apiTemplateRef'
|
||||||
|
export { createDynamicComponent } from './apiCreateDynamicComponent'
|
||||||
|
|
Loading…
Reference in New Issue