Компоненты — это сердце современной разработки
Слоты — это мощный и универсальный механизм распределения и компоновки контента. Вы можете думать о слотах как о настраиваемых шаблонах (например, похожих на шаблоны PHP), которые вы можете использовать в разных местах, для разных вариантов использования, создавая разные эффекты. Например, в фреймворках пользовательского интерфейса, таких как Vuetify, слоты используются для создания универсальных компонентов, таких как компонент оповещения. В компонентах такого типа слоты используются в качестве заполнителей для содержимого по умолчанию и любого дополнительного/необязательного содержимого, такого как значки, изображения и т. д.
Слоты позволяют добавлять любую структуру, стиль и функциональность к конкретному компоненту. Используя слоты, разработчики могут значительно сократить количество свойств, используемых в одном компоненте, что делает компоненты более чистыми и управляемыми.
В этом руководстве мы рассмотрим, как использовать возможности слотов в контексте Vue 3. Давайте начнем.
Основное использование слотов
По сути, Vue предлагает два типа слотов: простой слот и слот с ограниченной областью действия. Начнем с простого. Рассмотрим следующий пример:
const app = Vue.createApp ({})
app.component ('
template: `
`
})
app.mount ('#app’)
Здесь у нас есть основной компонент кнопки. Мы хотим, чтобы текст кнопки можно было настраивать, поэтому мы используем slotкомпонент внутри buttonэлемента, чтобы добавить заполнитель для текста. Нам также нужно общее значение по умолчанию (резервное) на случай, если мы не предоставим пользовательское значение. Vue использует в качестве содержимого слота по умолчанию все, что мы помещаем внутрь slotкомпонента. Поэтому мы просто помещаем текст «ОК» внутри компонента. Теперь мы можем использовать компонент следующим образом:
<
В результате появится кнопка с текстом «ОК», потому что мы не указали никакого значения. Но что, если мы хотим создать кнопку с произвольным текстом? В этом случае мы предоставляем пользовательский текст в реализации компонента следующим образом:
<
Здесь Vue берет пользовательский текст «Подписаться» и использует его вместо текста по умолчанию.
Как видите, даже в этом простом примере мы получаем большую гибкость в том, как мы хотим представить наш компонент. Но это только вершина айсберга. Давайте рассмотрим более сложный пример.
Создание компонента «Цитата дня»
Теперь мы создадим компонент котировки, который отображает котировку дня. Вот код:
const app = Vue.createApp ({})
app.component ('quote’, {
template: `
The quote of the day says:
`
})
app.mount ('#app’)
«Creativity is just connecting things.»
— Steve Jobs
.
width: 300px;
padding: 5px 10px;
}
.
}
В этом примере мы создаем заголовок заголовка, содержимое которого будет постоянным, а затем мы помещаем компонент слота внутрь абзаца, содержимое которого будет меняться в зависимости от котировки текущего дня. Когда компонент визуализируется, Vue отобразит заголовок из компонента цитаты, за которым следует содержимое, которое мы поместили в теги цитаты. Также обратите внимание на классы CSS, используемые как при создании, так и при реализации котировки. Мы можем стилизовать наши компоненты обоими способами в зависимости от наших потребностей.
Наш компонент котировки дня работает нормально, но нам все равно нужно обновлять котировку вручную. Давайте сделаем его динамическим, используя Fav Quotes API:
const app = Vue.createApp ({
data () {
return {
quoteOfTheDay: null,
show: false
};
},
methods: {
showQuote () {
axios.get ('https: //favqs.com/api/qotd’).then (result => {
this.quoteOfTheDay = result.data
this.show = true
}) ;
}
}
})
...
app.mount ('#app’)
{{ quoteOfTheDay.quote.body }}
— {{ quoteOfTheDay.quote.author }}
Здесь мы используем Axios для вызова конечной точки API «Цитата дня», а затем используем свойства bodyи authorиз возвращенного объекта JSON для заполнения цитаты. Таким образом, нам больше не нужно добавлять цитату вручную; это делается автоматически для нас.
Использование нескольких слотов
Хотя один слот может быть довольно мощным, во многих случаях этого будет недостаточно. В реальном сценарии нам часто требуется более одного слота для выполнения работы. К счастью, Vue позволяет нам использовать столько слотов, сколько нам нужно. Давайте посмотрим, как мы можем использовать несколько слотов, создав простой компонент карты.
Создание базового компонента карты
Мы создадим компонент карты с тремя разделами: заголовок, тело и нижний колонтитул:
const app = Vue.createApp ({})
app.component ('card’, {
template: `
`
})
app.mount ('#app’)
v-slot: header>
Card Header Title
v-slot: default>
Lorem ipsum leo risus, porta ac consectetur ac, vestibulum at eros. Donec id elit non mi porta gravida at eget metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras mattis consectetur purus sit amet fermentum.
Чтобы использовать несколько слотов, мы должны указать имя для каждого из них. Единственным исключением является слот по умолчанию. Итак, в приведенном выше примере мы добавляем nameсвойство для слотов верхнего и нижнего колонтитула. Слот без имени считается по умолчанию.
Когда мы используем cardкомпонент, нам нужно использовать templateэлемент с
Примечание:
Именованные слоты также можно использовать со сторонними компонентами, как мы увидим в следующем разделе.
Использование именованных слотов с карточным компонентом Bulma
Давайте возьмем компонент Bulma’s Card и немного его подправим:
const app = Vue.createApp ({})
app.component ('card’, {
template: `
`
})
app.mount ('#app’)
.container {
width: 300px;
}
v-slot: header>
Card Header Title
v-slot: default>
Lorem ipsum leo risus, porta ac consectetur ac, vestibulum at eros. Donec id elit non mi porta gravida at eget metus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Cras mattis consectetur purus sit amet fermentum.
v-slot: footer>
Здесь мы используем классы из компонента Bulma Card в качестве базового скелета и добавляем слот для каждого раздела (заголовок, контент, нижний колонтитул). Затем, когда мы добавляем контент, все структурируется должным образом.
Использование слотов с ограниченной областью действия
Мы сделали большой шаг вперед, используя несколько слотов, но настоящая мощь исходит от слотов с прицелом. Они позволяют родителю получить доступ к дочерним данным, что дает нам много возможностей. Давайте посмотрим их на практике.
Создание компонента многоцелевого списка
Чтобы продемонстрировать мощь слотов с ограниченной областью действия, мы создадим многоцелевой компонент списка, который можно использовать в различных сценариях, когда нам нужно перечислить некоторые данные:
const app = Vue.createApp ({
data () {
return {
tasks: ['Reading a book’, 'Buying vegetables’, 'Going for a walk’]
}
}
})
app.component ('list’, {
props: ['items’, 'name’],
template: `
{{ name }}
- v-for="item in items">
`
})
app.mount ('#app’)
{name: 'Cucumbers’, quantity: '2'},
{name: 'Red onion’, quantity: '1'},
]
}
}
})
...
app.mount ('#app’)
vacation-card’, {
props: ['url’, 'img’, 'imgAlt’, 'eyebrow’, 'title’, 'pricing’],
template: `
})
app.mount ('#app’)
<
url="/vacations/cancun"
img="https://images.unsplash.com/photo-1452784444945-3f422708fe5e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=512&q=80"
imgAlt="Beach in Cancun"
eyebrow="Private Villa"
title="Relaxing All-Inclusive Resort in Cancun"
pricing="$299 USD per night"
>
vacation-card>
Как видите, для предоставления всех необходимых данных/контента этот
Перепишем компонент со слотами:
const app = Vue.createApp ({})
app.component ('
props: ['url’, 'img’, 'imgAlt’],
template: `
})
app.mount ('#app’)
<
url="/vacations/cancun"
img="https://images.unsplash.com/photo-1452784444945-3f422708fe5e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=512&q=80"
imgAlt="Beach in Cancun"
>
v-slot: eyebrow>
Private Villa
v-slot: title>
Relaxing
v-slot: pricing>
$299 USD per night
vacation-card>
Здесь мы сокращаем реквизиты до трех. Мы оставляем props только для метаданных и используем именованные слоты для фактического контента, что мне кажется более логичным.
Вот мои общие соображения об использовании реквизита и слотов.
Используйте реквизит, когда:
родитель может передавать данные только дочернему компоненту
родитель не имеет контроля над тем, как будут отображаться данные, и не может настраивать дочерний компонент
у вас есть определенный дизайн, количество переменных невелико, а компонент простой
вам нужно предоставить метаданные или
Используйте слоты, когда:
вам нужно передать данные от ребенка к родителю
родитель может определить, как данные будут отображаться
вы хотите передавать не только данные, но и сложную
вам нужна универсальность для настройки дочернего компонента из родительского
вам нужно больше гибкости для настройки компонента, компонент большой и задействовано много переменных
Суть: для достижения наилучших результатов комбинируйте реквизит и слоты! ?
Изучение других вариантов использования игровых автоматов
На этом этапе вы должны увидеть мощь и гибкость слотов, но есть и более полезные способы их использования. Давайте исследуем их сейчас.
Повторное использование функциональности со слотами
Слоты могут предоставлять не только контент/структуру, но и функциональность. Давайте посмотрим на это в действии:
const app = Vue.createApp ({
data () {
return {
counter: 1
}
},
methods: {
increment () {
this.counter++
}
}
})
app.component ('
props: ['counter’],
template: `
`,
computed: {
double () {
return this.counter * 2
}
}
})
app.mount ('#app’)
<
v-slot: default="{ double }">
{{ counter }} x 2 = {{ double }}
double-counter>
Здесь мы создаем
В родительском элементе у нас есть counterсвойство данных и increment () метод, который увеличивает его на единицу. Когда мы используем
Мы можем сделать этот компонент более гибким. Давайте настроим его, чтобы умножить счетчик на любое пользовательское значение:
const app = Vue.createApp ({
data () {
return {
counter: 1,
by: 4
}
},
methods: {
increment () {
this.counter++
}
}
})
app.component ('
props: ['counter’, 'by’],
template: `
`,
computed: {
multiply () {
return this.counter * this.by
}
}
})
app.mount ('#app’)
<
v-slot: default="{ multiply }">
{{ counter }} x {{ by }} = {{ multiply }}
multiply-counter>
Здесь мы добавляем свойство by, которое устанавливает число умножения, и меняем doubleвычисляемое свойство на multiply, которое умножает counterна заданное число.
В родителя мы добавляем byсвойство данных и привязываем его к byреквизиту. Итак, теперь, если мы установим byсвойство данных равным 3, а свойство counterравно 4, результатом будет 4×3 = 12.
Использование слотов в компонентах без визуализации
Другой эффективный способ использования слотов — поместить их в компонент без рендеринга. Компонент без рендеринга не имеет templateэлемента. Он имеет функцию рендеринга, которая предоставляет один слот с областью действия. Давайте создадим версию нашего многоцелевого списка без рендеринга:
const app = Vue.createApp ({
data () {
return {
products: [
{name: 'Tomatoes’, quantity: '4'},
{name: 'Cucumbers’, quantity: '2'},
{name: 'Red onion’, quantity: '1'},
]
}
}
})
app.component ('
props: ['items’, 'name’],
render () {
return this. $slots.default ({
items: this.items,
name: this.name
}) ;
}
})
app.mount ('#app’)
<
v-slot: default="{name, items: products}">
{{ product.quantity }} {{ product.name }} {{ name }}
renderless-list>
Здесь мы создаем
Затем в родительском компоненте мы используем его так же, как наш многоцелевой компонент списка, за исключением того, что на этот раз структура контента определяется в родительском элементе, что дает нам большую гибкость, как мы увидим в следующем примере.
Примечание: в Vue 3 this. $scopedSlotsон удален и this. $slotsиспользуется вместо него. Кроме того, this. $slotsпредоставляет слоты как функции. Дополнительную информацию см. в разделе Объединение слотов.
Настоящая сила этого компонента в том, что мы не ограничены в том, как будем отображать контент. Давайте посмотрим, как легко отобразить тот же контент в виде таблицы:
<
v-slot: default="{name, items: products}">
{{ name }}
Quantity
Product
{{ product.quantity }}
{{ product.name }}
renderless-list>
table, th, td {
border: 1px solid black;
padding: 5px;
}
Здесь мы используем ту же функциональность, но определяем другую структуру контента.
Заключение
Так что в этом вся мощь и гибкость слотов. Как мы видели, их можно использовать в самых разных случаях, что позволяет нам производить многоразовые и универсальные компоненты. В сочетании с реквизитом слоты дают нам все необходимое для создания сложных компонентов и приложений. Слоты просты в использовании, но чрезвычайно эффективны. Если вы не использовали их раньше, я думаю, что сейчас самое подходящее время, чтобы начать это делать. Лучшее место для начала или продолжения этого пути — официальная документация по игровым автоматам. Удачи!