нужно
Давайте сначала предположим, что нам нужно добиться следующих эффектов и инкапсулировать его в компонент.Конечно, цель состоит не в том, чтобы действительно инкапсулировать компонент, а в том, чтобы учиться в процессеслотИдеи использования и оптимизации Ha:
<template>
<div>
<div>{{ title }}</div>
<hr>
<div>
<div v-for="(item, i) in List" :key="i">{{ item }}</div>
</div>
</div>
</template>
Затем назовите это так в родительском компонентеokсейчас:
<template>
<custom-list :title="title" :List="books" />
</template>
<script>
import CustomList from './custom-list.js';
export default {
components: { CustomList },
data() {
return {
title: '书籍列表',
books: ['Dom编程艺术', '你不知道的Javascript', 'CSS世界', 'HTML入门教程'],
};
},
};
</script>
Эммм. . На первый взгляд вроде бы ничего страшного, и даже изменения данных могут соответствовать требованиям.
Однако достаточно ли этого? Потребности всегда непостоянны, например, в один прекрасный день, чтобы удовлетворить следующие эффекты?
слот
это наше времяслотпоявился. Слоты позволяют нам распределять контент от дочернего компонента к родительскому компоненту, который определяет, что дочерний компонент будет отображать.
нормальный слот
Все еще взяв в качестве примера вышеупомянутые компоненты, нам нужно поместить подкомпоненты вtitleКонтент распространяется, и контент передается родительским компонентом. На этом этапе мы можем изменить дочерний компонент следующим образом:
<template>
<div>
<div>
<slot></slot>
</div>
<hr>
<div>
<div v-for="(item, i) in List" :key="i">{{ item }}</div>
</div>
</div>
</template>
Затем в вызове родительского компонента:
<template>
<custom-list :List="books">
<span><icon type="waves"> 书籍列表</span>
</custom-list>
</template>
<script>
import CustomList from './custom-list.js';
export default {
components: { CustomList },
data() {
return {
title: '书籍列表',
books: ['Dom编程艺术', '你不知道的Javascript', 'CSS世界', 'HTML入门教程'],
};
},
};
</script>
В этом случае содержимое, обернутое в родительский компонент, заменит<slot>label, поэтому окончательный результат рендеринга выглядит так:
<template>
<div>
<div>
<span><icon type="waves"> 书籍列表</span>
</div>
<hr>
<div>
<div v-for="(item, i) in List" :key="i">{{ item }}</div>
</div>
</div>
</template>
Кстати рот: в<slot>На этикетке также может быть размещено содержимое, например:<slot> 标题 </slot>, Представляет содержимое слота по умолчанию, которое будет отображаться только в том случае, если родительский компонент не передает содержимое через слот.
Точно так же нашиcontentКонтент тоже нужно распространять, поэтому модифицируем его снова:
<template>
<div>
<div>
<slot></slot>
</div>
<hr>
<slot></slot>
</div>
</template>
Таким образом, есть еще одна проблема: мы определяем два Как отличить их содержание, нельзя полагаться на порядок написания? Это явно ненадежно. Итак, естьименованный слот.
именованный слот
Как следует из названия, это слот с именем, по которому легко отличить несколько слотов. Затем продолжаем модифицировать:
<template>
<div>
<div>
<slot name="title"></slot>
</div>
<hr>
<slot name="content"></slot>
</div>
</template>
определить по одному для каждого слотаnameатрибут, а затем подводим соответствующий слот, когда родительский компонент передает значениеnameВот и все.
<template>
<custom-list>
<template v-slot:title>
<span><icon type="waves"> 书籍列表</span>
<template>
<template v-slot:content>
<div>
<div v-for="(item, i) in book" :key="i">
<icon :type="item.icon">{{ item.name }}
</div>
</div>
</template>
</custom-list>
</template>
<script>
import CustomList from './custom-list.js';
export default {
components: { CustomList },
data() {
return {
title: '书籍列表',
books: [
{ name: 'Dom编程艺术',icon: 'face' },
{ name: '你不知道的Javascript', icon: 'favorite' },
{ name: 'CSS世界', icon: 'av_timer'},
{ name: 'HTML入门教程', icon: 'star_half' },
],
};
},
};
</script>
Предоставляя контент в именованные слоты, мы можем
<template>использовать на элементахv-slotинструктаж и сv-slotукажите его имя в виде аргумента.
Теперь все хорошо, вам даже не нужно передавать данные,ListДочерний компонент вообще не используется, данные рендерятся непосредственно в родительском компоненте, и их приходится записывать каждый раз, когда компонент используетсяv-for, то почему бы не поставитьv-forКак насчет записи в дочерних компонентах? Это нужно написать только один раз.
Затем снова изменим подкомпонент:
<template>
<div>
<div>
<slot name="title"></slot>
</div>
<hr>
<div>
<div v-for="(item, i) in List">
<slot name="item"></slot>
</div>
</div>
</div>
</template>
Это еще одна проблема: я хочу отобразитьitemноitemэто данные в дочернем компоненте, когда родительский компонент проходитv-slotДоставка поступающего контента,<slot>{{ item }}</slot>Контент будет заменен входящим контентом. Что тут происходит? Подумайте об этом, если мы отдадим данные родительскому компоненту, разве это не будет решено путем отображения их в родительском компоненте? Тогда пришло время作用域插槽появился.
слот с прицелом
Слоты с ограниченной областью позволяют нам передавать данные от дочерних компонентов к родительским компонентам, разве это не решает вышеуказанную проблему? Далее мы настраиваем подкомпоненты
<template>
<div>
<div>
<slot name="title"></slot>
</div>
<hr>
<div>
<div v-for="(item, i) in List">
<slot name="item" :row="item"></slot>
</div>
</div>
</div>
</template>
В этот момент мы будем каждыйitemзначение черезrowатрибут передан<slot>, а затем получаем это значение в родительском компоненте:
<template>
<custom-list>
<template v-slot:title>
<span><icon type="waves"> 书籍列表</span>
<template>
<!--实际传的数据格式为: { row:{ name: xx, icon: xx } },所以这里可以使用结构赋值-->
<template v-slot:item="{ row }">
<icon :type="row.icon">{{ row.name }}
</template>
</custom-list>
</template>
Это завершает наш компонент, который не только более гибкий, но и более надежный для кода. В общем, сокеты по-прежнему очень полезны, особенно при упаковке компонентов.