Vue 3 如何获取有关 $children 的信息
Posted
技术标签:
【中文标题】Vue 3 如何获取有关 $children 的信息【英文标题】:Vue 3 how to get information about $children 【发布时间】:2021-01-17 02:16:58 【问题描述】:这是我在标签组件中使用 VUE 2 的旧代码:
created()
this.tabs = this.$children;
标签:
<Tabs>
<Tab title="tab title">
....
</Tab>
<Tab title="tab title">
....
</Tab>
</Tabs>
VUE 3: 如何使用组合 API 在 Tabs 组件中获取有关子项的一些信息?获取长度,迭代它们,并创建选项卡标题,......等等?有任何想法吗? (使用组合 API)
【问题讨论】:
【参考方案1】:根据Vue documentation,假设您在Tabs
组件下有一个默认插槽,您可以直接在模板中访问该插槽的子项,如下所示:
// Tabs component
<template>
<div v-if="$slots && $slots.default && $slots.default()[0]" class="tabs-container">
<button
v-for="(tab, index) in getTabs($slots.default()[0].children)"
:key="index"
:class=" active: modelValue === index "
@click="$emit('update:model-value', index)"
>
<span>
tab.props.title
</span>
</button>
</div>
<slot></slot>
</template>
<script setup>
defineProps( modelValue: Number )
defineEmits(['update:model-value'])
const getTabs = tabs =>
if (Array.isArray(tabs))
return tabs.filter(tab => tab.type.name === 'Tab')
else
return []
</script>
<style>
...
</style>
Tab
组件可能类似于:
// Tab component
<template>
<div v-show="active">
<slot></slot>
</div>
</template>
<script>
export default name: 'Tab'
</script>
<script setup>
defineProps(
active: Boolean,
title: String
)
</script>
实现应该类似于以下内容(考虑一个对象数组,每个部分一个,带有title
和component
):
...
<tabs v-model="active">
<tab
v-for="(section, index) in sections"
:key="index"
:title="section.title"
:active="index === active"
>
<component
:is="section.component"
></component>
</app-tab>
</app-tabs>
...
<script setup>
import ref from 'vue'
const active = ref(0)
</script>
另一种方法是使用 useSlots
,如 Vue 文档中所述(上面的链接)。
【讨论】:
【参考方案2】:哦,伙计们,我解决了:
this.$slots.default().filter(child => child.type.name === 'Tab')
【讨论】:
你从哪里得到那个“插槽”? 改用this.$slots.default()
@Katinka -> 在组合 API 设置方法中 => setup(_, slots)
不确定他们为什么不推荐使用 $children 属性 :( 此方法有效,但需要像在模板中一样将任何数据传递给插槽 this.$slots.default(....)
【参考方案3】:
我遇到了同样的问题,经过大量研究并问自己为什么他们删除了$children
,我发现他们创造了一个更好、更优雅的替代方案。
这是关于动态组件的。 (<component: is =" currentTabComponent "> </component>
)。
我在这里找到的信息:
https://v3.vuejs.org/guide/component-basics.html#dynamic-components
希望对大家有用,大家好!!
【讨论】:
动态组件早在几年前就已经在 Vue 2 中可用了。不确定它们与访问子组件有什么关系【参考方案4】:在 3.x 中,$children 属性已被移除且不再受支持。相反,如果您需要访问子组件实例,他们建议使用 $refs。作为一个数组
https://v3.vuejs.org/guide/migration/children.html#_2-x-syntax
【讨论】:
【参考方案5】:我对 Ingrid Oberbüchler 的组件进行了小幅改进,因为它不支持热重载/动态选项卡。
在 Tab.vue 中:
onBeforeMount(() =>
// ...
)
onBeforeUnmount(() =>
tabs.count--
)
在 Tabs.vue 中:
const selectTab = // ...
// ...
watch(
() => state.count,
() =>
if (slots.default)
state.tabs = slots.default().filter((child) => child.type.name === "Tab")
)
【讨论】:
【参考方案6】:这是我现在的 Vue 3 组件。我使用提供来获取子Tab
组件中的信息。
<template>
<div class="tabs">
<div class="tabs-header">
<div
v-for="(tab, index) in tabs"
:key="index"
@click="selectTab(index)"
:class="'tab-selected': index === selectedIndex"
class="tab"
>
tab.props.title
</div>
</div>
<slot></slot>
</div>
</template>
<script lang="ts">
import defineComponent, reactive, provide, onMounted, onBeforeMount, toRefs, VNode from "vue";
interface TabProps
title: string;
export default defineComponent(
name: "Tabs",
setup(_, slots)
const state = reactive(
selectedIndex: 0,
tabs: [] as VNode<TabProps>[],
count: 0
);
provide("TabsProvider", state);
const selectTab = (i: number) =>
state.selectedIndex = i;
;
onBeforeMount(() =>
if (slots.default)
state.tabs = slots.default().filter((child) => child.type.name === "Tab");
);
onMounted(() =>
selectTab(0);
);
return ...toRefs(state), selectTab;
);
</script>
标签组件:
export default defineComponent(
name: "Tab",
setup()
const index = ref(0);
const isActive = ref(false);
const tabs = inject("TabsProvider");
watch(
() => tabs.selectedIndex,
() =>
isActive.value = index.value === tabs.selectedIndex;
);
onBeforeMount(() =>
index.value = tabs.count;
tabs.count++;
isActive.value = index.value === tabs.selectedIndex;
);
return index, isActive;
);
<div class="tab" v-show="isActive">
<slot></slot>
</div>
【讨论】:
目前还不清楚,如何使标签处于活动状态。使用 $children 我有组件实例并且可以编写“tab.active = true”。但现在选项卡是 VNode。您存储 selectedIndex,但如何在子选项卡中使用它?【参考方案7】:致想要完整代码的人:
标签.vue
<template>
<div>
<div class="tabs">
<ul>
<li v-for="tab in tabs" :class=" 'is-active': tab.isActive ">
<a :href="tab.href" @click="selectTab(tab)"> tab.name </a>
</li>
</ul>
</div>
<div class="tabs-details">
<slot></slot>
</div>
</div>
</template>
<script>
export default
name: "Tabs",
data()
return tabs: [] ;
,
created()
,
methods:
selectTab(selectedTab)
this.tabs.forEach(tab =>
tab.isActive = (tab.name == selectedTab.name);
);
</script>
<style scoped>
</style>
Tab.vue
<template>
<div v-show="isActive"><slot></slot></div>
</template>
<script>
export default
name: "Tab",
props:
name: required: true ,
selected: default: false
,
data()
return
isActive: false
;
,
computed:
href()
return '#' + this.name.toLowerCase().replace(/ /g, '-');
,
mounted()
this.isActive = this.selected;
,
created()
this.$parent.tabs.push(this);
,
</script>
<style scoped>
</style>
App.js
<template>
<Tabs>
<Tab :selected="true"
:name="'a'">
aa
</Tab>
<Tab :name="'b'">
bb
</Tab>
<Tab :name="'c'">
cc
</Tab>
</Tabs>
<template/>
【讨论】:
谢谢,但这不是 Vue 3 + 组合 API 的解决方案。我在设置方法'setup(_,slots)'中解决它【参考方案8】:如果你复制粘贴的代码跟我一样
然后只需将创建的方法添加到“选项卡”组件中,该方法会将自身添加到其父项的选项卡数组中
created()
this.$parent.tabs.push(this);
,
【讨论】:
以上是关于Vue 3 如何获取有关 $children 的信息的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Vue 3 中访问 $children 以创建选项卡组件?
vue2升级vue3: TSX Vue 3 Composition API Refs
vue 自定义组件(二) $parent、$children、ref、refs