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 { nextTick, ref } from 'vue'
|
||||||
import { describe, expect, test } from 'vitest'
|
import { describe, expect, test } from 'vitest'
|
||||||
import { makeRender } from '../_utils'
|
import { makeRender } from '../_utils'
|
||||||
|
@ -43,4 +50,40 @@ describe('directive: v-show', () => {
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(h1?.style.display).toBe('')
|
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 { 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 { pauseTracking, resetTracking, traverse } from '@vue/reactivity'
|
||||||
import { VaporErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
|
import { VaporErrorCodes, callWithAsyncErrorHandling } from './errorHandling'
|
||||||
import { renderEffect } from './renderEffect'
|
import { renderEffect } from './renderEffect'
|
||||||
|
import { warn } from './warning'
|
||||||
|
import { normalizeBlock } from './dom/element'
|
||||||
|
|
||||||
export type DirectiveModifiers<M extends string = string> = Record<M, boolean>
|
export type DirectiveModifiers<M extends string = string> = Record<M, boolean>
|
||||||
|
|
||||||
|
@ -62,13 +68,22 @@ export type DirectiveArguments = Array<
|
||||||
]
|
]
|
||||||
>
|
>
|
||||||
|
|
||||||
export function withDirectives<T extends Node>(
|
export function withDirectives<T extends ComponentInternalInstance | Node>(
|
||||||
node: T,
|
nodeOrComponent: T,
|
||||||
directives: DirectiveArguments,
|
directives: DirectiveArguments,
|
||||||
): T {
|
): T {
|
||||||
if (!currentInstance) {
|
if (!currentInstance) {
|
||||||
// TODO warning
|
__DEV__ && warn(`withDirectives can only be used inside render functions.`)
|
||||||
return node
|
return nodeOrComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
let node: Node
|
||||||
|
if (isVaporComponent(nodeOrComponent)) {
|
||||||
|
const root = getComponentNode(nodeOrComponent)
|
||||||
|
if (!root) return nodeOrComponent
|
||||||
|
node = root
|
||||||
|
} else {
|
||||||
|
node = nodeOrComponent
|
||||||
}
|
}
|
||||||
|
|
||||||
const instance = currentInstance
|
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(
|
export function invokeDirectiveHook(
|
||||||
|
|
Loading…
Reference in New Issue