mirror of https://github.com/vuejs/core.git
feat(runtime-vapor): `v-show` for component (#188)
Co-authored-by: 三咲智子 Kevin Deng <sxzz@sxzz.moe>
This commit is contained in:
parent
464b498f13
commit
cd582949f2
|
@ -1,4 +1,11 @@
|
|||
import { children, on, template, vShow, withDirectives } from '../../src'
|
||||
import {
|
||||
children,
|
||||
createComponent,
|
||||
on,
|
||||
template,
|
||||
vShow,
|
||||
withDirectives,
|
||||
} from '../../src'
|
||||
import { nextTick, ref } from 'vue'
|
||||
import { describe, expect, test } from 'vitest'
|
||||
import { makeRender } from '../_utils'
|
||||
|
@ -43,4 +50,40 @@ describe('directive: v-show', () => {
|
|||
await nextTick()
|
||||
expect(h1?.style.display).toBe('')
|
||||
})
|
||||
|
||||
test('should work on component', async () => {
|
||||
const t0 = template('<div>child</div>')
|
||||
const t1 = template('<button>toggle</button>')
|
||||
const n0 = t0()
|
||||
const visible = ref(true)
|
||||
|
||||
function handleClick() {
|
||||
visible.value = !visible.value
|
||||
}
|
||||
const { component: Child } = define({
|
||||
render() {
|
||||
return n0
|
||||
},
|
||||
})
|
||||
|
||||
const { instance, host } = define({
|
||||
render() {
|
||||
const n1 = t1()
|
||||
const n2 = createComponent(Child, [], null, null, true)
|
||||
withDirectives(n2, [[vShow, () => visible.value]])
|
||||
on(n1 as HTMLElement, 'click', () => handleClick)
|
||||
return [n1, n2]
|
||||
},
|
||||
}).render()
|
||||
|
||||
expect(host.innerHTML).toBe('<button>toggle</button><div>child</div>')
|
||||
expect(instance.dirs.get(n0)![0].dir).toBe(vShow)
|
||||
|
||||
const btn = host.querySelector('button')
|
||||
btn?.click()
|
||||
await nextTick()
|
||||
expect(host.innerHTML).toBe(
|
||||
'<button>toggle</button><div style="display: none;">child</div>',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,8 +1,14 @@
|
|||
import { isFunction } from '@vue/shared'
|
||||
import { type ComponentInternalInstance, currentInstance } from './component'
|
||||
import {
|
||||
type ComponentInternalInstance,
|
||||
currentInstance,
|
||||
isVaporComponent,
|
||||
} from './component'
|
||||
import { pauseTracking, resetTracking, traverse } from '@vue/reactivity'
|
||||
import { VaporErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
|
||||
import { renderEffect } from './renderEffect'
|
||||
import { warn } from './warning'
|
||||
import { normalizeBlock } from './dom/element'
|
||||
|
||||
export type DirectiveModifiers<M extends string = string> = Record<M, boolean>
|
||||
|
||||
|
@ -62,13 +68,22 @@ export type DirectiveArguments = Array<
|
|||
]
|
||||
>
|
||||
|
||||
export function withDirectives<T extends Node>(
|
||||
node: T,
|
||||
export function withDirectives<T extends ComponentInternalInstance | Node>(
|
||||
nodeOrComponent: T,
|
||||
directives: DirectiveArguments,
|
||||
): T {
|
||||
if (!currentInstance) {
|
||||
// TODO warning
|
||||
return node
|
||||
__DEV__ && warn(`withDirectives can only be used inside render functions.`)
|
||||
return nodeOrComponent
|
||||
}
|
||||
|
||||
let node: Node
|
||||
if (isVaporComponent(nodeOrComponent)) {
|
||||
const root = getComponentNode(nodeOrComponent)
|
||||
if (!root) return nodeOrComponent
|
||||
node = root
|
||||
} else {
|
||||
node = nodeOrComponent
|
||||
}
|
||||
|
||||
const instance = currentInstance
|
||||
|
@ -109,7 +124,22 @@ export function withDirectives<T extends Node>(
|
|||
}
|
||||
}
|
||||
|
||||
return node
|
||||
return nodeOrComponent
|
||||
}
|
||||
|
||||
function getComponentNode(component: ComponentInternalInstance) {
|
||||
if (!component.block) return
|
||||
|
||||
const nodes = normalizeBlock(component.block)
|
||||
if (nodes.length !== 1) {
|
||||
warn(
|
||||
`Runtime directive used on component with non-element root node. ` +
|
||||
`The directives will not function as intended.`,
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
return nodes[0]
|
||||
}
|
||||
|
||||
export function invokeDirectiveHook(
|
||||
|
|
Loading…
Reference in New Issue