在使用 <slot/> 创建 re-usable 和动态选项卡菜单的组件内部使用 v-for
Using v-for inside component that uses <slot/> to create re-usable and dynamic Tab menu
所以我正在尝试使用 Vue 3 和插槽创建一个动态选项卡菜单。我让选项卡工作,我有 BaseTabsWrapper 和 BaseTab 组件。我需要能够 v-for 在 BaseTabsWrapper 组件中使用 BaseTab 组件。像这样:
<section
id="content"
class="w-full mx-2 pr-2"
v-if="incomingChatSessions && incomingChatSessions.length"
>
<BaseTabsWrapper>
<BaseTab
v-for="chatSession in incomingChatSessions"
:key="chatSession.id"
:title="chatSession.endUser.name"
>
<p>{{ chatSession }}</p>
</BaseTab>
</BaseTabsWrapper>
</section>
我发现的答案中的一个重要警告是 incomingChatSessions object 是异步的并且来自 websocket(我已经测试过这个 object 工作正常并带来所有数据正确地又名永远不会是空的 object).
BaseTabsWrapper 模板内部。重要部分:
<template>
<div>
<ul
class="tag-menu flex space-x-2"
:class="defaultTagMenu ? 'default' : 'historic'"
role="tablist"
aria-label="Tabs Menu"
v-if="tabTitles && tabTitles.length"
>
<li
@click.stop.prevent="selectedTitle = title"
v-for="title in tabTitles"
:key="title"
:title="title"
role="presentation"
:class="{ selected: title === selectedTitle }"
>
<a href="#" role="tab">
{{ title }}
</a>
</li>
</ul>
<slot />
</div>
</template>
和脚本:
<script>
import { ref, useSlots, provide } from 'vue'
export default {
props: {
defaultTagMenu: {
type: Boolean,
default: true,
},
},
setup(props) {
const slots = useSlots()
const tabTitles = ref(
slots.default()[0].children.map((tab) => tab.props.title)
)
const selectedTitle = ref(tabTitles.value[0])
provide('selectedTitle', selectedTitle)
provide('tabTitles', tabTitles)
return {
tabTitles,
selectedTitle,
}
},
}
</script>
这是Tab组件模板:
<template>
<div v-show="title === selectedTitle" class="mt-4">
<slot />
</div>
</template>
<script>
import { inject } from 'vue'
export default {
props: {
title: {
type: String,
default: 'Tab Title',
},
},
setup() {
const selectedTitle = inject('selectedTitle')
return {
selectedTitle,
}
},
}
</script>
我脚本中最重要的部分也是给我带来很多麻烦的部分是:
const tabTitles = ref(
slots.default()[0].children.map((tab) => tab.props.title)
)
我在这里做的是根据每个插槽的 属性“标题”创建一组标签标题,但是当我加载页面时,这个数组总是只有一个标题,即使我' m 从 API 获取更多标题元素。我注意到的一件事是,如果我从我的代码中强制使用页面的 re-render,那么 tabTitles 数组具有正确数量的元素,并且我在菜单上获得了所有正确数量的选项卡。我已经测试过,我使用来自 websocket 的数据控制异步性以隐藏“incomingChatSessions”数组的方式一切正常,但无论我如何尝试,tabTiles 总是只获取一个元素。
我会做类似的事情:
computed(
() => slots.default()[0].children.map((tab) => tab.props.title)
)
它应该在更新组件时更新计算的 属性(例如插槽更改)
所以我正在尝试使用 Vue 3 和插槽创建一个动态选项卡菜单。我让选项卡工作,我有 BaseTabsWrapper 和 BaseTab 组件。我需要能够 v-for 在 BaseTabsWrapper 组件中使用 BaseTab 组件。像这样:
<section
id="content"
class="w-full mx-2 pr-2"
v-if="incomingChatSessions && incomingChatSessions.length"
>
<BaseTabsWrapper>
<BaseTab
v-for="chatSession in incomingChatSessions"
:key="chatSession.id"
:title="chatSession.endUser.name"
>
<p>{{ chatSession }}</p>
</BaseTab>
</BaseTabsWrapper>
</section>
我发现的答案中的一个重要警告是 incomingChatSessions object 是异步的并且来自 websocket(我已经测试过这个 object 工作正常并带来所有数据正确地又名永远不会是空的 object).
BaseTabsWrapper 模板内部。重要部分:
<template>
<div>
<ul
class="tag-menu flex space-x-2"
:class="defaultTagMenu ? 'default' : 'historic'"
role="tablist"
aria-label="Tabs Menu"
v-if="tabTitles && tabTitles.length"
>
<li
@click.stop.prevent="selectedTitle = title"
v-for="title in tabTitles"
:key="title"
:title="title"
role="presentation"
:class="{ selected: title === selectedTitle }"
>
<a href="#" role="tab">
{{ title }}
</a>
</li>
</ul>
<slot />
</div>
</template>
和脚本:
<script>
import { ref, useSlots, provide } from 'vue'
export default {
props: {
defaultTagMenu: {
type: Boolean,
default: true,
},
},
setup(props) {
const slots = useSlots()
const tabTitles = ref(
slots.default()[0].children.map((tab) => tab.props.title)
)
const selectedTitle = ref(tabTitles.value[0])
provide('selectedTitle', selectedTitle)
provide('tabTitles', tabTitles)
return {
tabTitles,
selectedTitle,
}
},
}
</script>
这是Tab组件模板:
<template>
<div v-show="title === selectedTitle" class="mt-4">
<slot />
</div>
</template>
<script>
import { inject } from 'vue'
export default {
props: {
title: {
type: String,
default: 'Tab Title',
},
},
setup() {
const selectedTitle = inject('selectedTitle')
return {
selectedTitle,
}
},
}
</script>
我脚本中最重要的部分也是给我带来很多麻烦的部分是:
const tabTitles = ref(
slots.default()[0].children.map((tab) => tab.props.title)
)
我在这里做的是根据每个插槽的 属性“标题”创建一组标签标题,但是当我加载页面时,这个数组总是只有一个标题,即使我' m 从 API 获取更多标题元素。我注意到的一件事是,如果我从我的代码中强制使用页面的 re-render,那么 tabTitles 数组具有正确数量的元素,并且我在菜单上获得了所有正确数量的选项卡。我已经测试过,我使用来自 websocket 的数据控制异步性以隐藏“incomingChatSessions”数组的方式一切正常,但无论我如何尝试,tabTiles 总是只获取一个元素。
我会做类似的事情:
computed(
() => slots.default()[0].children.map((tab) => tab.props.title)
)
它应该在更新组件时更新计算的 属性(例如插槽更改)