Давайте узнаем о слотах в Vue.

Vue.js

Vue 2.6Это было давно, и главное обновлениеslot(слот). Может быть, многие люди никогда не используют егоslot, может быть, вы недостаточно знаете об этом, когда вы действительно поймете это, вы поймете, насколько это прекрасно, когда вы инкапсулируете многоразовый плагин ~

Код выложен на Github. Вы можете скачать и практиковать.


Сначала рассмотрим простой пример:

<!--子组件-->
<template>
    <button class="custom-button">
        <slot></slot>
    </button>
</template>
<style>
.custom-button{
    color: #fff;
    background-color: #409eff;
    padding: 10px 20px;
    font-size: 14px;
    border-radius:6px;
    outline: none;
    border: 1px solid #dcdfe6;
}
</style>
<!--父组件-->
<template>
    <div class="button-list">
        <cus-bottom>确定</cus-bottom>
    </div>
</template>
<script>
import customButton from './customButton.vue'
export default{
    components:{
        'cus-bottom':customButton
    }
}
</script>

Окончательный рендер:

<div class="button-list">
    <button class="custom-button">
        确定
    </button>
</div>

Когда дочерний компонент визуализируется,<slot></slot>будет заменено на «ОК».slotОн не будет отображаться, он используется для получения содержимого, переданного родительским компонентом.

Давайте посмотрим на схему, я думаю, так проще понять концепцию слотов:

Игровая карта — это контент, передаваемый родительским компонентом, а сокет эквивалентен дочернему компоненту.slotТеги, когда они объединены, являются окончательным рендером.

Конечно выше самое простоеslotиспользовать, мы будем продолжать смотреть вниз.

Содержание слота

<slot></slot>Принимаются не только строки, но и шаблоны Html:

<!--父组件-->
<div class="button-list">
    <cus-bottom>
        <span>确定</span>
    </cus-bottom>
</div>

Окончательный рендер:

<div class="button-list">
    <button class="custom-button">
        <span>确定</span>
    </button>
</div>

Также можно получить другие компоненты:

<!--父组件-->
<div class="button-list">
    <cus-bottom> 
        <!-- cus-font 图标组件 -->
        <cus-font></cus-font>
        <span>确定</span>
    </cus-bottom>
</div>

область компиляции

Все в родительском шаблоне компилируется в родительской области, все в дочернем шаблоне компилируется в дочерней области.

Давайте на примере объясним, что называетсяобласть компиляции

<!--父组件-->
<template>
    <div class="button-list">
        <cus-bottom>{{buttonText}}</cus-bottom>
    </div>
</template>
<script>
import customButton from './customButton.vue'
export default{
    components:{
        'cus-bottom':customButton
    },
    data(){
        return{
            buttonText:'保存'
        }
    }
}
</script>

{{buttonText}}Он скомпилирован в родительском компоненте, поэтому дочерний компонент не может его получить.buttonTextПеременные, наоборот, переменные, скомпилированные в дочернем компоненте, не могут быть получены родительским компонентом.

контент по умолчанию

Официальный сайт называется резервным контентом. Я думаю, что это немного странно, здесь это называется контентом по умолчанию.

когда мыbuttonСодержимое по умолчанию «ОК»:

<button class="custom-button">
    <!--这里的确定就是默认内容-->
    <slot>确定</slot>
</button>

Теперь, когда я использую в родительском компоненте<cus-button>А когда кнопка еще и "ОК", можно ничего не предоставлять:

<div class="button-list">
    <cus-bottom></cus-bottom>
</div>

Конечно, если кнопка в нашем родительском компоненте "сохранить", мы можем написать и так

<div class="button-list">
    <!--这里的保存 会替换掉子组件的默认内容-->
    <cus-bottom>保存</cus-bottom>
</div>

Окончательный рендер:

<div class="button-list">
    <button class="custom-button">
        保存
    </button>
</div>

именованный слот

Слот с названием. Зачем эта штука? Мы в приведенном выше примереslotСуществует только один, поэтому содержимое, переданное из родительского компонента, уникально для дочернего компонента.slotполучено.但是很多时候我们需要有多个slotдля получения «множественного» контента от родительского компонента соответственно.

Здесь мы используем пример официального сайта со следующим содержанием<base-layout>Компоненты:

<div class="container">
  <header>
    <!-- 我们希望把头部内容放在这里 -->
  </header>
  <main>
    <!-- 我们希望把主要内容放在这里 -->
  </main>
  <footer>
    <!-- 我们希望把页脚放在这里 -->
  </footer>
</div>

теперь мне нужно триslot(слот), чтобы получить три содержимого, переданных родительским компонентом. Для такой ситуации,slotЭлементы имеют особое свойство: имя. Эту функцию можно использовать для определения дополнительных независимых слотов:

<div class="container">
  <header>
    <slot name="header"></slot>
  </header>
  <main>
    <slot></slot>
  </main>
  <footer>
    <slot name="footer"></slot>
  </footer>
</div>

Средний без имениslotСлот будет иметь неявное имя «по умолчанию». эквивалентно<slot name="default"></slot>. То есть теперь есть три названных подкомпонента:header default footerслот.

Итак, теперь родительский компонент использует<base-layout>Когда компоненту необходимо передать три содержимого (ни одно из них не требуется), «заголовок», «по умолчанию», «нижний колонтитул». В настоящее время требуется логотип, чтобы сообщить подкомпоненту, как три содержимого соответствуют трем слотам.

Предоставляя контент в именованные слоты, мы можем<template>использовать на элементахv-slotинструктаж и сv-slotукажите его имя в виде аргумента:

<base-layout>
  <template v-slot:header>
    <h1>这是header插槽的内容</h1>
  </template>

  <p>这里是default插槽的内容</p>
  <p>这里也是default插槽的内容</p>

  <template v-slot:footer>
    <p>这是footer插槽的内容</p>
  </template>
</base-layout>

v-slot: Последний является соответствующим подкомпонентомslotизname. Поскольку подкомпоненты в основном тегеslotнетname,По умолчаниюname = default, так что вы также можете написать

<base-layout>
  <template v-slot:header>
    <h1>这是header插槽的内容</h1>
  </template>

  <template v-slot:default>
    <p>这里是default插槽的内容</p>
    <p>这里也是default插槽的内容</p>
  </template>

  <template v-slot:footer>
    <p>这是footer插槽的内容</p>
  </template>
</base-layout>

Окончательный рендер:

<div class="container">
  <header>
    <h1>这是header插槽的内容</h1>
  </header>
  <main>
    <p>这里是default插槽的内容</p>
    <p>这里也是default插槽的内容</p>
  </main>
  <footer>
    <p>这是footer插槽的内容</p>
  </footer>
</div>

Аббревиатура названного слота

а такжеv-onа такжеv-bindТакой же,v-slotБывают и аббревиатуры, т.е. ставить все перед параметром (v-slot:) Заменены персонажи#. Напримерv-slot:headerможно переписать как#header:

<base-layout>
    <template #header>
        <h1>这是header插槽的内容</h1>
    </template>
    
    <template #default>
        <p>这里是default插槽的内容</p>
        <p>这里也是default插槽的内容</p>
    </template>
    
    <template #footer>
        <p>这是footer插槽的内容</p>
    </template>
</base-layout>

слот с прицелом

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

Например, представьте себе шаблон со следующим<current-user>Компоненты:

<template>
    <span>
        <slot>{{ userInfo.name }}</slot>
    </span>
</template>

<script>
export default{
    data(){
        return{
            userInfo:{
                name:'erdong',
                sex:'boy',
                age:'26'
            }
        }
    }
}
</script>

Включить всю информацию о текущем пользователе. Содержимое слота по умолчанию — имя. когда мы используем<current-user>Когда компоненты:

Родительский компонент:

<current-user></current-user>

Окончательный рендер:

<span>
    erdong
</span>

Но я хочу показать это в родительском компонентеsexЧто мы можем сделать по этому поводу? Очень просто, измените содержимое слота дочернего компонента по умолчанию:

<span>
    <slot>{{ userInfo.sex }}</slot>
</span>

Но это не соответствует характеристикам наших упакованных компонентов: возможности повторного использования.

Если родительский компонент может получить дочерний компонентinfoDataзначение, то мы можем написать:

<!--父组件-->
<current-user>
    {{infoData.sex}}
</current-user>

Это переопределит содержимое по умолчанию в дочернем компоненте. Но мы упоминали вышеобласть компиляцииРодительский компонент не может получить переменные дочернего компонента.

хотите получить родительский компонентinfoDataЧто мы можем сделать по этому поводу?

На этом этапе нам нужно изменить дочерний компонент:

<!--子组件-->
<span>
    <slot v-bind:userInfo="userInfo" name='user'>{{ userInfo.sex }}</slot>
</span>

Родительский компонент:

<current-user>
    <template v-slot:user="infoData">
        {{infoData.userInfo.sex}}
    </template>
</current-user>

Окончательный рендер:

<span>
    boy
</span>

Подсборкаv-bind:userInfo="userInfo" name='user'ПервыйuserInfoимя переменной, переданное родительскому компоненту, второйuserInfoэто значение, переданное родительскому компоненту.nameэтоslotИмя

родительский компонентv-slot:user="infoData" userявляется соответствующим подкомпонентомslotизname,infoDataсостоит в том, чтобы получитьslotИмя переменной набора переданных значений. Почему это называется коллекцией? Потому что подкомпонент может передавать в слот несколько значений:

<!--子组件-->
<template>
   <span>
       <slot v-bind:userInfo="userInfo" v-bind:address='address' name='user'>{{ userInfo.name }}</slot>
   </span>
</template>

<script>
export default{
   data(){
       return{
           userInfo:{
               name:'erdong',
               sex:'boy',
               age:'26'
           },
           address:{
               city:'上海市',
           }
       }
   }
}
</script>
<!--父组件-->
<current-user>
    <template v-slot:user="infoData">
        {{infoData.userInfo.sex}}{{infoData.address.city}}
    </template>
</current-user>

Окончательный рендер:

<span>
    boy上海市
</span>

Разрушение слота Prop

<!--父组件-->
<current-user>
    <template v-slot:user="infoData">
        {{infoData.userInfo.sex}}{{infoData.address.city}}
    </template>
</current-user>

упомянутый вышеinfoDataимя подкомпонентаuserСлоты подходят для достойной коллекции. который:

infoData = {
    userInfo:{
        name:'erdong',
        sex:'boy',
        age:'26'
    },
    address:{
        city:'上海市',
    }
}

Таким образом, мы можем разобрать его, используя синтаксис ES6:

<!--父组件-->
<current-user>
    <template v-slot:user="{userInfo,address}">
        {{userInfo.sex}}{{address.city}}
    </template>
</current-user>

Суммировать

Здесь мы в основном ставимVueизslot(Слоты) снова использовали, есть некоторые не упомянутые, но если вы узнаете все это, вы можете сказать, что вы освоилиslotиспользование. Если вы получили сообщение об ошибке, проверьте, не является ли ваша версия Vue.js 2.6.x.

домашнее задание после уроков

Выше мы используем пример инкапсуляции кнопки для описания основного использования слота. Заинтересованные студенты могут улучшить его. заключает в себеelement UIизbuttonкомпоненты. Вы можете сохранить его для своих собственных проектов.