访问 Vue 中的任意槽

dmc*_*lue 3 typescript vuejs2

假设我想创建一个多层组件以供重用,例如“Tab”Ui

因此使用的开发人员可以这样写:

<tabs>
  <tab label="My First Tab">
    Content for first tab which could contain components, html, etc.
  </tab>
  <tab label="My Second Tab">
    More Content
  </tab>
</tabs>
Run Code Online (Sandbox Code Playgroud)

基本上,他们使用选项卡和选项卡组件的方式使我不知道开发人员将在选项卡中使用多少个选项卡组件。例如,如何访问选项卡组件以按选项卡 UI 功能显示和隐藏它们?

我尝试过使用this.$childrenandthis.slots.default但实际上无法访问选项卡数据来显示和隐藏它。公平地说,我是用 Typescript 编写的,因此问题可能会更加困难。

就像是:

<template>
    <div class="tabs">
        <slot /> <!-- Location of the Tab's -->
    </div>
</template>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";

@Component({
    ...
})
export default class Tabs extends Vue {
    public tabs: any[] = [];
        
    public created() {
        this.tabs = this.$slots.default;
        // this.tabs is a set of VNode's, 
        //    I can't figure out how to access the components
        //    I see a prop 'componentInstance' but when I try to
        //    access it, it says undefined
        // this.select(0);
        let tab = this.tabs.find((obj: any, index: number) => {
            return index === 0;
        }); // tab is undefined :(
    }

    public select(index: number) {
        (this.$slots.default[index] as any).show = true;
        // Accessing Vnode instead of Component :(
        // this.$children[0]["show"] = true; // Read only :(
        // this.tabs[index].show = true; // blerrggg :(

        // Vue.nextTick();
    }
}
</script>
Run Code Online (Sandbox Code Playgroud)

我查看了 Vue 中选项卡的一些 GitHub 库,逻辑看起来非常复杂。我假设从插槽/子组件的存在来看,有一种更直接的方法来访问子组件。也许对我来说这太有希望了。

Anyone know how to access, pass or change data in a child slot if you don't know how many children will be there (ie you didn't explicitly write them in the parent Component)?

Tom*_*hah 5

如果问题是您必须等到选项卡组件安装完毕,则已安装的生命周期挂钩就可以解决此类问题。不过,使用该属性存在一个潜在的问题,如Vue 文档$children中所述:

\n
\n

请注意,\xe2\x80\x99s 没有 $children 的顺序保证,并且它不是反应性的。如果您发现自己尝试使用 $children 进行数据绑定,请考虑使用数组和 v-for 来生成子组件,并使用数组作为事实来源。

\n
\n

由于无法保证订单,this.$children[index]因此不保证给您带来您期望的标签。

\n

如果您采用建议的方法,使用v-for数组,它可能看起来像这样:

\n
<template>\n    <div class="tabs">\n        <tab v-for="(tabName, index) in tabs" :key="tabName" :label="tabName" :ref="`tab-${index}`">\n            <slot :name="tabName"></slot>\n        </tab>\n    </div>\n</template>\n\n<script lang="ts">\nimport { Component, Prop, Vue } from "vue-property-decorator";\n\n@Component({\n    ...\n})\nexport default class Tabs extends Vue {\n    @Prop(Array) tabs: string[];\n\n    public mounted() {\n        this.select(0);\n    }\n\n    public select(index: number) {\n        this.$refs[`tab-${index}`].show = true;\n    }\n}\n</script>\n
Run Code Online (Sandbox Code Playgroud)\n

我将插槽放在选项卡中,以便您知道所有子组件都将包装在选项卡组件中,这意味着所有tabs子组件都保证是tab组件,并且您$refs将都具有预期的tab属性。你可以像这样使用它:

\n
<tabs :tabs="[\'My First Tab\', \'My Second Tab\']">\n    <template slot="My First Tab">\n        Content for first tab which could contain components, html, etc.\n    </template>\n    <template slot="My Second Tab">\n        More content\n    </template>\n</tabs>\n
Run Code Online (Sandbox Code Playgroud)\n

  • 欢迎来到 stackoverflow。这是一个很棒的答案。 (2认同)