Объясните слот слота vue за один раз

Vue.js

слот vue слот

Введение

В официальном документе vue в разделе «Основы компонентов» упоминается, что компоненты могут распространять контент через слоты. Какой сценарий он решает?

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

Примечание. Весь приведенный ниже контент основан на vue версии 2.6.0 и выше.

2. Что такое слот

Давайте посмотрим на пример

Напишите родительский компонент: test.vue

<template>
    <div>
      <div>大家好我是父组件</div>
      <myslot>
        <p>测试一下吧内容写在这里了能否显示</p>
      </myslot>
    </div>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
  }
</script>

<style>
</style>

Напишите подкомпонент: myslot.vue

<template>
  <div>
      <div>我是子组件</div>
  </div>
</template>

<script>
</script>

<style>
</style>

Запустите код и обнаружите, что окончательный эффект рендеринга

大家好我是父组件
我是子组件

Что делать, если я хочу отобразить содержимое тега p в родительском компоненте

Измените подкомпонент: myslot.vue

<template>
  <div>
      <div>我是子组件</div>
      <p>现在测试一下slot</p>
      <slot></slot>
  </div>
</template>

<script>
</script>

<style>
</style>

Запустите код, вы увидите следующий эффект

大家好我是父组件
我是子组件
现在测试一下slot
测试一下吧内容写在这里了能否显示

Официальный документ описывает сценарий применения слота следующим образом:

Нам часто нужно передать контент компоненту

Vue custom.<slot>Элементы делают это очень легко

Просто добавьте слоты там, где это необходимо — это так просто!

Объединив приведенный выше пример, чтобы понять это:

1. Родительский компонент хочет передать содержимое шаблона дочернему компоненту при обращении к дочернему компоненту.<p>测试一下吧内容写在这里了能否显示</p>

2. Дочерний компонент позволяет отображать содержимое шаблона, переданное от родительского компонента, в его местоположении.

3. В дочерних компонентах<slot>Это слот, который может получать содержимое шаблона, переданное родительским компонентом.<slot>Сам элемент будет заменен

4.<myslot></myslot>Компонент не содержит<slot>элемент, любое содержимое между начальным и конечным тегами компонента будет удалено.

Во-вторых, роль слота

Позволяет пользователям расширять компоненты для более эффективного повторного использования и настройки компонентов.

3. Классификация слотов

1. Слот по умолчанию

в<submit-button>В компоненте:

<button type="submit">
  <slot></slot>
</button>

мы могли бы захотеть это<button>В большинстве случаев рендерится текст «Отправить», но иногда хочется отрендерить текст как что-то другое, так как же этого добиться?

У нас может быть «Отправить» в качестве запасного варианта, мы можем поместить его в<slot>Внутри этикетки:

<button type="submit">
  <slot>Submit</slot>
</button>

Теперь, когда я использую в родительском компоненте<submit-button>и когда содержимое слота не предоставлено:

<submit-button></submit-button>

Резервное содержимое «Отправить» будет отображаться:

<button type="submit">
  Submit
</button>

Но если мы предоставляем контент:

<submit-button>
  Save
</submit-button>

тогда предоставленный контент будет отображаться вместо резервного контента:

<button type="submit">
  Save
</button>

2. Именованный слот

Иногда мы пишем подсадку, мы надеемся

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

Для такой ситуации,<slot>Элементы имеют специальный атрибут:name. Этот атрибут можно использовать для определения дополнительных слотов:

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

один безnameиз<slot>Выход будет иметь неявное имя «по умолчанию».

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

<template>
  <myslot>
    <div>大家好我是父组件</div>
    <template v-slot:header>
      <h1>Here might be a page title</h1>
    </template>

    <p>A paragraph for the main content.</p>
    <p>And another one.</p>

    <template v-slot:footer>
      <p>Here's footer info</p>
    </template>
  </myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
  }
</script>
<style>
</style>

Окончательный результат рендеринга можно увидеть

Here might be a page title
大家好我是父组件
A paragraph for the main content.

And another one.

Here's footer info

Родительский компонент передаст соответствующее содержимое шаблона дочернему компоненту с именем, а содержимое шаблона без указанного имени будет передано дочернему компоненту безnameиз<slot>

Конечно, если родительский компонент

<template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
</template>

То же самое передается дочернему компоненту безnameиз<slot>

Уведомление:

v-slotможно добавить только в<template>начальство

Именованные слоты могут быть записаны с использованием сокращений,v-slotвместо этого используйте #

<template>
  <myslot>
    <div>大家好我是父组件</div>
    <template #header>
      <h1>Here might be a page title</h1>
    </template>

    <p>A paragraph for the main content.</p>
    <p>And another one.</p>

    <template #footer>
      <p>Here's footer info</p>
    </template>
  </myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
  }
</script>

<style>
</style>

3. Слоты прицела

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

Помните слот по умолчанию? Если дочерний компонент написан на<slot>Резервное содержимое внутри тега двусторонне связано со свойством данных компонента.

<template>
  <div>
    <span>
      <slot>{{user.firstName}}</slot>
    </span>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        user:{
          firstName:'gerace',
          lastName:'haLi'
        }
      }
    }
  }
</script>
<style>
</style>

Когда родительский компонент ссылается на дочерний компонент, он хочет иметь возможность заменить альтернативный контент

<template>
  <myslot>{{ user.firstName }}</myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
  }
</script>
<style>
</style>

Когда вы запустите код, вы найдете сообщение об ошибке

Property or method "user" is not defined on the instance but referenced during render.
TypeError: Cannot read property 'firstName' of undefined

Почему здесь? Официальная документация Vue дает ответ

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

Так как же решить эту проблему?

чтобыuserДоступный в родительском слоте контент, мы можем поставитьuserтак как<slot>Атрибут элемента привязан к:

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

связаны в<slot>Атрибуты элементов называются реквизитами слота. Теперь в родительской области мы можем использовать значениеv-slotчтобы определить имя реквизита слота, который мы предоставили:

<template>
  <myslot>
      <template v-slot:default="slotProps">
      {{ slotProps.user.firstName }}
      </template>
  </myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
</script>
<style>
</style>

В приведенном выше примере мы решили назвать объект, содержащий все реквизиты слота, какslotProps, но вы можете использовать любое имя, которое вам нравится.

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

<template>
  <myslot v-slot:default="slotProps">
     {{ slotProps.user.firstName }}
  </myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
</script>
<style>
</style>

Приведенный выше код также можно изменить непосредственно на

<template>
  <myslot v-slot="slotProps">
     {{ slotProps.user.firstName }}
  </myslot>
</template>

Уведомление:

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

<template>
  <myslot v-slot="slotProps">
     {{ slotProps.user.firstName }}
     <template v-slot:other="otherSlotProps">
   		slotProps is NOT available here
     </template>
  </myslot>
</template>

Рассмотрим ситуацию с несколькими слотами.

Подсборка

<template>
  <div>
    <span>
      <slot v-bind:userData="user" name="header">
        {{ user.msg }}
      </slot>
      <slot v-bind:hobbyData="hobby" name="footer">
        {{ hobby.fruit }}
      </slot>
    </span>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        user:{
          firstName: 'gerace',
          lastName: 'haLi',
        },
        hobby:{
          fruit: "apple",
          color: "blue"
        }
      }
    }
  }
</script>
<style>
</style>

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

<template>
  <myslot>
      <template v-slot:header="slotProps">
        {{ slotProps.userData.firstName }}
      </template>
      <template v-slot:footer="slotProps">
        {{ slotProps.hobbyData.fruit }}
      </template>
  </myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
</script>
<style>
</style>

В случае нескольких слотов реквизит слота может быть деконструирован в методе записи.Родительский компонент записывается следующим образом

<template>
  <myslot>
      <template v-slot:header="{userData}">
        {{ userData.firstName }}
      </template>
      <template v-slot:footer="{hobbyData}">
        {{ hobbyData.fruit }}
      </template>
  </myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
  }
</script>
<style>
</style>

Как упоминалось во введении к именованным слотам, именованные слоты могут использовать аббревиатуры,v-slotВместо этого вы можете использовать #, поэтому приведенный выше код можно записать как:

<template>
  <myslot>
      <template #header="{userData}">
        {{ userData.firstName }}
      </template>
      <template #footer="{hobbyData}">
        {{ hobbyData.fruit }}
      </template>
  </myslot>
</template>

<script>
  import myslot from './myslot';
  export default {
    components: {
      myslot
    }
  }
</script>
<style>
</style>

Обратите внимание, однако, что эта аббревиатура доступна только в том случае, если у нее есть аргумент. Это означает, что следующий синтаксис недопустим:

<!-- 这样会触发警告 -->
<template>
  <myslot>
      <template #="{userData}">
        {{ userData.firstName }}
      </template>
      <template #="{hobbyData}">
        {{ hobbyData.fruit }}
      </template>
  </myslot>
</template>