Хотите вложить компоненты друг в друга с родительского уровня? Интересно, как вы делаете то, что делает React с props.children? Слоты могут быть тем, что вы ищете.

Начиная

Я собираюсь начать с базовой настройки, которую Vue.js дает нам при использовании командной строки, но сначала я удалю некоторые вещи, которые нам действительно не нужны в шаблонах. Итак, теперь у нас остался компонент HelloWorld, который отображает свойство сообщения, переданное из App.vue.

// App.vue
<template>
  <div id="app">
    <HelloWorld msg="Welcome to your Vue.js App">
  </div>
</template>
// HelloWorld.vue
<template>
  <div class="hello">
    <h1>{{ msg }}</h1>
  </div>
</template>

Основное использование

Итак, допустим, что вместо передачи свойства «msg» мы просто хотим написать наше сообщение между двумя тегами элементов HelloWorld, а затем отобразить этот рендеринг на странице. Что мы сделаем:

// AppV.vue
<template>
  <div id="app">
    <HelloWorld> 
      <h1>Welcome to your Vue.js App</h1> 
    </HelloWorld>
  </div>
</template>
// HelloWorld.vue
<template>
  <div class="hello">
    <slot> </slot>
  </div>
</template>
<script>
export default {
  name: 'HelloWorld', 
  p̶r̶o̶p̶s̶:̶ ̶{̶m̶s̶g̶:̶ ̶s̶t̶r̶i̶n̶g̶}̶,̶
}
</script>

Как вы можете видеть в приведенном выше примере, мы переместили наше сообщение ‹h1› в App.vue и поместили его между парой тегов HelloWorld. Это означает, что мы можем избавиться от реквизитов в нашем компоненте HelloWorld, поскольку мы не передаем ему никаких реквизитов. И теперь наше сообщение отображается с использованием <slot/>.

Пользовательская кнопка

Приведенный выше пример не имеет особого смысла для использования. с таким же успехом можно использовать реквизиты и писать меньше кода в родительском элементе. но эту логику можно применить ко многому. Возьмем, к примеру, кнопку:

// CustomButton.vue
<template>
  <button> <slot></slot> </button>
</template>
// App.vue
<template>
  <div id="app">
    <HelloWorld> <h1> Hello World</h1> </HelloWorld> 
    <CustomButton type="submit"> SAVE! </CustomButton>
  </div>
</template>

В этом примере мы можем написать нашу настраиваемую кнопку, как обычную кнопку HTML, передавая текстовое значение между тегами кнопок. и здесь я также передал свойство типа, так как мы могли бы использовать его, если бы кнопка работала.

Но подождите, есть еще кое-что ...

Слоты могут иметь имена и отображать другие компоненты, а не только несуществующий текст.

Имена слотов

Допустим, у вас есть модальное окно, в котором вы хотите отображать верхний, основной и нижний колонтитулы. Это может меняться каждый раз, когда вы используете модальное окно, поэтому вы не хотите жестко закодировать внешний вид / значения в самом модальном окне.

// Modal.vue
<template>
  <div class="modal">
    <slot name="header">  </slot> 
    <slot>                </slot>
    <slot name="footer">  </slot>
  </div>
</template>

В этом примере мы установили три слота и дали им имена, чтобы позже мы могли убедиться, что наши данные отображаются там, где мы хотим.

Если не присвоить слоту имя, оно станет слотом по умолчанию.

Чтобы затем убедиться, что мы правильно рендерим в модальном окне, в родительском компоненте мы сделаем следующее:

// App.vue
<template>
  <Modal>
    <template v-slot:header>
      <h1>Modal Header Text</h1> 
    </template>
    <h2>Modal Body</h2> 
    <p>Some more text to render</p>
    <template v-slot:footer>
      <p>Footer Text</p>
      <button>Close</button>
    </template>
  </Modal>
</template>

Здесь важно отметить, что когда вы даете слоту имя, в родительском компоненте вам нужно будет использовать <template v-slot:name> slot stuff </template>

Слоты с компонентами

Здесь все становится лучше. Если вы спросите меня, допустим, мы создали специальный компонент тела, который отображает как карту и некоторые данные с ней. Мы можем легко сделать этот рендер в слоте нашего модального окна.

// App.vue
<template>
  <Modal>
    <template v-slot:header>...</template>
    <ModalMapComp 
      place="placeProperty"
      mapInfo="map"
    />
    <template v-slot:footer>...</template>
  </Modal>
</template>

Здесь я только что передал компонент ModalMap, этот компонент занимает место и свойство mapInfo. Я не хочу, чтобы каждый модальный, который у меня был, использовал карту, и меня не интересует, чтобы модальное окно принимало кучу информации только для того, чтобы выяснить, нужно ли ему отображать карту, профиль или что-то еще.

Вот почему я бы предпочел использовать здесь слот, позволяя родителю решать, что загружается, и просто использовать модальное окно как «тупой», как и должно быть.

Я пишу эти сообщения в блоге, чтобы помочь мне лучше понять вещи, а затем, надеюсь, помочь кому-то другому. При этом: дайте мне знать, как вы это используете, или, если я сказал что-то глупое, я здесь, чтобы научиться. :)

Слоты на Vue.js