mirror of https://github.com/vuejs/core.git
fix(runtime-vapor): component emits vdom interop (#13498)
This commit is contained in:
parent
5ab938db50
commit
d95fc186c2
|
@ -26,7 +26,27 @@ describe('vdomInterop', () => {
|
|||
})
|
||||
})
|
||||
|
||||
describe.todo('emit', () => {})
|
||||
describe('emit', () => {
|
||||
test('emit from vapor child to vdom parent', () => {
|
||||
const VaporChild = defineVaporComponent({
|
||||
emits: ['click'],
|
||||
setup(_, { emit }) {
|
||||
emit('click')
|
||||
return []
|
||||
},
|
||||
})
|
||||
|
||||
const fn = vi.fn()
|
||||
define({
|
||||
setup() {
|
||||
return () => h(VaporChild as any, { onClick: fn })
|
||||
},
|
||||
}).render()
|
||||
|
||||
// fn should be called once
|
||||
expect(fn).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
describe('slots', () => {
|
||||
test('basic', () => {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { type ObjectEmitsOptions, baseEmit } from '@vue/runtime-dom'
|
||||
import type { VaporComponent, VaporComponentInstance } from './component'
|
||||
import { EMPTY_OBJ, hasOwn, isArray } from '@vue/shared'
|
||||
import { resolveSource } from './componentProps'
|
||||
import { type RawProps, resolveSource } from './componentProps'
|
||||
import { interopKey } from './vdomInterop'
|
||||
|
||||
/**
|
||||
* The logic from core isn't too reusable so it's better to duplicate here
|
||||
|
@ -40,13 +41,17 @@ export function emit(
|
|||
)
|
||||
}
|
||||
|
||||
function propGetter(rawProps: Record<string, any>, key: string) {
|
||||
function propGetter(rawProps: RawProps, key: string) {
|
||||
const dynamicSources = rawProps.$
|
||||
if (dynamicSources) {
|
||||
let i = dynamicSources.length
|
||||
while (i--) {
|
||||
const source = resolveSource(dynamicSources[i])
|
||||
if (hasOwn(source, key)) return resolveSource(source[key])
|
||||
if (hasOwn(source, key))
|
||||
// for props passed from VDOM component, no need to resolve
|
||||
return dynamicSources[interopKey]
|
||||
? source[key]
|
||||
: resolveSource(source[key])
|
||||
}
|
||||
}
|
||||
return rawProps[key] && resolveSource(rawProps[key])
|
||||
|
|
|
@ -23,10 +23,11 @@ import {
|
|||
import { ReactiveFlags } from '@vue/reactivity'
|
||||
import { normalizeEmitsOptions } from './componentEmits'
|
||||
import { renderEffect } from './renderEffect'
|
||||
import type { interopKey } from './vdomInterop'
|
||||
|
||||
export type RawProps = Record<string, () => unknown> & {
|
||||
// generated by compiler for :[key]="x" or v-bind="x"
|
||||
$?: DynamicPropsSource[]
|
||||
$?: DynamicPropsSource[] & { [interopKey]?: boolean }
|
||||
}
|
||||
|
||||
export type DynamicPropsSource =
|
||||
|
|
|
@ -37,6 +37,8 @@ import { renderEffect } from './renderEffect'
|
|||
import { createTextNode } from './dom/node'
|
||||
import { optimizePropertyLookup } from './dom/prop'
|
||||
|
||||
export const interopKey: unique symbol = Symbol(`interop`)
|
||||
|
||||
// mounting vapor components and slots in vdom
|
||||
const vaporInteropImpl: Omit<
|
||||
VaporInteropInterface,
|
||||
|
@ -51,11 +53,16 @@ const vaporInteropImpl: Omit<
|
|||
const propsRef = shallowRef(vnode.props)
|
||||
const slotsRef = shallowRef(vnode.children)
|
||||
|
||||
const dynamicPropSource: (() => any)[] & { [interopKey]?: boolean } = [
|
||||
() => propsRef.value,
|
||||
]
|
||||
// mark as interop props
|
||||
dynamicPropSource[interopKey] = true
|
||||
// @ts-expect-error
|
||||
const instance = (vnode.component = createComponent(
|
||||
vnode.type as any as VaporComponent,
|
||||
{
|
||||
$: [() => propsRef.value],
|
||||
$: dynamicPropSource,
|
||||
} as RawProps,
|
||||
{
|
||||
_: slotsRef, // pass the slots ref
|
||||
|
|
Loading…
Reference in New Issue