слот 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>