Доступ к произвольным слотам в Vue - PullRequest
0 голосов
/ 15 сентября 2018

Допустим, я хочу создать многослойный компонент для повторного использования, например '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>

По сути, они будут использовать компоненты Tabs и Tab таким образом, что я понятия не имею, сколько компонентов Tab будет использовать dev во вкладках. Как получить доступ к компонентам вкладок, чтобы, например, отображать и скрывать их для каждого пользовательского интерфейса вкладки?

Я пытался использовать this.$children и this.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>

Я посмотрел некоторые библиотеки GitHub для Tabs в Vue, и логика кажется очень сложной. Я предполагаю, что из наличия слотов / потомков существует более простой подход к доступу к дочерним компонентам. Может быть, это слишком обнадеживает с моей стороны.

Кто-нибудь знает, как получить доступ, передать или изменить данные в дочернем слоте, если вы не знаете, сколько там будет детей (то есть вы явно не записали их в родительский компонент)?

Ответы [ 2 ]

0 голосов
/ 16 сентября 2018

Если проблема заключается в том, что вам нужно подождать, пока компоненты вкладки смонтированы, для такого рода вещей существует установленный хук жизненного цикла.Однако существует потенциальная проблема с использованием свойства $children, как указано в Vue docs :

Обратите внимание, что нет гарантии заказа для $ children, и она не реагирует,Если вы пытаетесь использовать $ children для привязки данных, рассмотрите возможность использования Array и v-for для генерации дочерних компонентов и используйте Array в качестве источника истины.

Так как порядок негарантировано, this.$children[index] не гарантирует, что вы получите ожидаемую вкладку.

Если бы вы следовали предложенному подходу, используя v-for и массив, он мог бы выглядеть примерно так:

<template>
    <div class="tabs">
        <tab v-for="(tabName, index) in tabs" :key="tabName" :label="tabName" :ref="`tab-${index}`">
            <slot :name="tabName"></slot>
        </tab>
    </div>
</template>

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

@Component({
    ...
})
export default class Tabs extends Vue {
    @Prop(Array) tabs: string[];

    public mounted() {
        this.select(0);
    }

    public select(index: number) {
        this.$refs[`tab-${index}`].show = true;
    }
}
</script>

Я поместил слот внутрь вкладки, чтобы вы знали, что все дочерние компоненты будут обернуты в компонент вкладки, а это означает, что все tabs дочерние элементы гарантированно будут tab компонентами, а ваши *Все 1021 * будут иметь ожидаемые свойства tab.Вы бы использовали это так:

<tabs :tabs="['My First Tab', 'My Second Tab']">
    <template slot="My First Tab">
        Content for first tab which could contain components, html, etc.
    </template>
    <template slot="My Second Tab">
        More content
    </template>
</tabs>
0 голосов
/ 16 сентября 2018

Часть моей проблемы (кажется) заключается в том, что функция created() для вкладок срабатывает до того, как компоненты вкладок смонтированы, поэтому они могут существовать или не существовать.Вызвав начальный выбор с помощью Timeout, я смог использовать

(this.$children[index] as any)["show"] = true;

Кто-нибудь знает, как проверить, когда (непосредственные) дочерние компоненты смонтированы?Я немного искал и не смог найти правильный ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...