Вложенные "двунаправленные" слоты во Vuejs

Я использую Vuejs. Я создал два компонента:First а также Second.

  1. First оказывает Second.
  2. Second имеет именованный слот.
  3. First содержит <template>, идти в Secondназванный слот.
  4. Внутри Firstс <template> - есть еще один именованный слот.
  5. Внутри Secondс <slot> - E сть <template>, идти в Firstс <template>названный слот.

Я получаю Firstс <template> оказано внутри Secondслот.

Это правильно, но я бы тоже хотел увидеть Secondс <template> оказано внутри <slot> из Firstс <template>. Но я этого не делаю.

Вот код:

var First = Vue.extend({
  template: `
    <div>
      In first<br/>
      <second>
        <template slot="slot1">
          In template of First
          <slot name="slot2">
          </slot>
        </template>
      </second>
    </div>
  `
})
Vue.component('first', First)

var Second = Vue.extend({
  template: `
    <div>
      In second<br/>
      <slot name="slot1">
        <template slot="slot2">
          In template of Second
        </template>
      </slot>
    </div>
  `
})
Vue.component('second', Second)

Вот результат:

In first
In second
In template of First

Вот jsfiddle: https://jsfiddle.net/obeobe/f98kr4ye/

Я бы хотел получить такой результат:

In first
In second
In template of First
In template of Second

Могу ли я добиться этого с помощью слотов? Если нет, можно ли этого добиться другим способом, но без создания третьего компонента?

РЕДАКТИРОВАТЬ: возможный реальный вариант использования: компонент List, который позволяет определять HTML-содержимое каждого элемента его хостом и может внедрять некоторый собственный контент в контент хоста в месте, указанном хостом.

Например, примерно так:

Компонент хоста:

<div class="myList">
    <list v-bind:items="usersArray">
        <template slot="itemSlot" slotScope="item">
            <div>{{ item.name }}</div>
            <div>{{ item.country }}</div>
            <div>{{ item.phone }}</div>
            <slot name="actions"> <--------- the spot for the List component to inject generic actions
            </slot>
            <div>{{ item.age }}</div>
        </template>
    </list>
</div>

Компонент "Список":

<div>
    <div v-for="(anItem, idx) in items">
        <div>{{ idx }}</div>
        <slot name="itemSlot" v-bind:item="anItem">
            <template slot="actions">
                <a v-on:click="duplicateItem(anItem)">Duplicate</a> <---------- the "duplicateItem" method would be implemented inside this List component
                <a>Edit</a>
                <a>Delete</a>
            </template>
        </slot>
    </div>
</div>

1 ответ

Решение

AFAIK, в Vue.js нет двунаправленных слотов

<div id="app">
  <first>
         ─────────────────────┐
  </first>                    │
</div>                        │
                              │
<div>                         │
  In first<br/>               │
  <second>                    │
    <template slot="slot1">  ─────┐
      In template of First    │   │
      <slot name="slot2">  <──┘ ┄┄│┄┄> This slot will replaced by slot2
      </slot>                     │    template child of first component.
    </template>                   │
  </second>                       │
</div>                            │
                                  │
<div>                             │
  In second<br/>                  │
  <slot name="slot1">  <──────────┘
    <template slot="slot2">  ┄┄┄┄┄┄┄┄> This is fallback content it will 
      In template of Second            shows up if no content provided.
    </template>                        But slot template is used so
                                       this will go to replace slot2
                                       inside slot.
  </slot>
</div>

Поскольку нет slot2 или любой слот определить внутри slot компонент, так что ваш In template of Second никогда бы не появился.

В вашем примере, на мой взгляд, этого нет. Альтернативный способ добиться этого - привязатьduplicateItem через слот.

<div class="myList">
  <list v-bind:items="usersArray">
    <template slot="itemSlot" slotScope="{ item, duplicateItem }">
      <div>{{ item.name }}</div>
      <div>{{ item.country }}</div>
      <div>{{ item.phone }}</div>
      <div>
        <a v-on:click="duplicateItem(item)">Duplicate</a>
        <a>Edit</a>
        <a>Delete</a>
      </div>
      <div>{{ item.age }}</div>
    </template>
  </list>
</div>

<div>
  <div v-for="(anItem, idx) in items">
    <div>{{ idx }}</div>
      <slot name="itemSlot"
        v-bind:item="anItem"
        v-bind:duplicateItem="duplicateItem">
      </slot>
    </div>
  </div>
</div>
Другие вопросы по тегам