Reputation: 742
I have a vue playground.
The container component needs to be able to control the CSS display property of an unknown number of children in the default slot.
I assume the child components will need to hold a property or have some way of identifying themselves to their container.
How can the container change the CSS display property of one of the components in the default slot?
Ideally, the technique used to manipulate the CSS display property could be used to manipulate other CSS properties.
Note, there is a related question at How can a container change the display of a child in the default slots? which handles showing / hiding the child components only without using CSS.
App.vue
<script setup>
import Container from './Container.vue'
import ChildA from './ChildA.vue'
import ChildB from './ChildB.vue'
</script>
<template>
<Container>
<ChildA />
<ChildB />
</Container>
</template>
Container.vue
<script setup>
import { useSlots, useAttrs, onMounted} from 'vue'
const slots = useSlots()
function logSlots(where) {
console.log( `${where} slots`, slots )
const children = slots.default()
console.log( `${where} slots children`, children.length, children )
}
logSlots("setup")
function changeDisplay(whichChild, show) {
console.log( "change display", whichChild, show)
// how can I know I am accessing child a?
// what goes here?
}
onMounted( () => {
logSlots("onMounted")
})
</script>
<template>
<button @click="logSlots('button')">log slots</button>
<button @click="changeDisplay('child a', false)">Hide Child A</button>
<button @click="changeDisplay('child a', true)">Show Child A</button>
<slot />
</template>
ChildA.vue
<script setup>
</script>
<template>
<div>
ChildA
</div>
</template>
ChildB.vue
<script setup>
</script>
<template>
<div>
ChildB
</div>
</template>
Upvotes: 0
Views: 51
Reputation: 22694
You can mutate your slot's children by added a class to them, using nested selector you can hide individual elements inside your slot components.
Note that the container should have a root HTML element like DIV in order :deep()
to work. Otherwise use a global style:
<script setup>
import { useSlots, reactive, cloneVNode} from 'vue';
const slots = useSlots();
const slotted = () => slots.default().map(vnode => cloneVNode(vnode, {class:{'hidden-child':hide.has(vnode.type.name)}}));
const hide = reactive(new Set);
function changeDisplay(whichChild) {
hide.has(whichChild) ? hide.delete(whichChild) : hide.add(whichChild);
}
</script>
<template>
<div>
<button @click="changeDisplay('ChildA')">Toggle Child A</button>
<button @click="changeDisplay('ChildB')">Toggle Child B</button>
<slotted />
</div>
</template>
<style scoped>
:deep(.hidden-child){
display: none;
}
</style>
Upvotes: -1