Разработка сайтов в Артемовске, ЛНР. Полное руководство по слотам Vue

Компоненты — это сердце современной разработки веб-приложений. Каждое приложение состоит из нескольких компонентов, плавно сшитых вместе, чтобы работать как единое целое. Эти компоненты должны быть максимально гибкими и многоразовыми, чтобы их можно было использовать в разных ситуациях и даже в разных приложениях. Один из основных механизмов, который многие фреймворки используют для удовлетворения таких требований, в частности Vue, называется «слотом».

Слоты — это мощный и универсальный механизм распределения и компоновки контента. Вы можете думать о слотах как о настраиваемых шаблонах (например, похожих на шаблоны PHP), которые вы можете использовать в разных местах, для разных вариантов использования, создавая разные эффекты. Например, в фреймворках пользовательского интерфейса, таких как Vuetify, слоты используются для создания универсальных компонентов, таких как компонент оповещения. В компонентах такого типа слоты используются в качестве заполнителей для содержимого по умолчанию и любого дополнительного/необязательного содержимого, такого как значки, изображения и т. д.

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

В этом руководстве мы рассмотрим, как использовать возможности слотов в контексте Vue 3. Давайте начнем.

Основное использование слотов

По сути, Vue предлагает два типа слотов: простой слот и слот с ограниченной областью действия. Начнем с простого. Рассмотрим следующий пример:

const app = Vue.createApp ({})

app.component ('primary-button’, {

template: `

 

 

`

})

app.mount ('#app’)

Здесь у нас есть основной компонент кнопки. Мы хотим, чтобы текст кнопки можно было настраивать, поэтому мы используем slotкомпонент внутри buttonэлемента, чтобы добавить заполнитель для текста. Нам также нужно общее значение по умолчанию (резервное) на случай, если мы не предоставим пользовательское значение. Vue использует в качестве содержимого слота по умолчанию все, что мы помещаем внутрь slotкомпонента. Поэтому мы просто помещаем текст «ОК» внутри компонента. Теперь мы можем использовать компонент следующим образом:

 

 

<primary-button>primary-button>

 

 

В результате появится кнопка с текстом «ОК», потому что мы не указали никакого значения. Но что, если мы хотим создать кнопку с произвольным текстом? В этом случае мы предоставляем пользовательский текст в реализации компонента следующим образом:

 

 

<primary-button>Subscribeprimary-button>

 

 

Здесь 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

 

 

 

 

 

.quote-box {

background-color: lightgreen;

width: 300px;

padding: 5px 10px;

}

.quote-text {

font-style: italic;

}

В этом примере мы создаем заголовок заголовка, содержимое которого будет постоянным, а затем мы помещаем компонент слота внутрь абзаца, содержимое которого будет меняться в зависимости от котировки текущего дня. Когда компонент визуализируется, 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’)

 

 

 

v-if="show" class="quote-box">

 

{{ quoteOfTheDay.quote.body }}


 

— {{ quoteOfTheDay.quote.author }}

 

 

 

 

 

Здесь мы используем Axios для вызова конечной точки API «Цитата дня», а затем используем свойства bodyи authorиз возвращенного объекта JSON для заполнения цитаты. Таким образом, нам больше не нужно добавлять цитату вручную; это делается автоматически для нас.

Использование нескольких слотов

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

Создание базового компонента карты

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

const app = Vue.createApp ({})

app.component ('card’, {

template: `

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

`

 

})

app.mount ('#app’)

 

 

 

 

 

Чтобы использовать несколько слотов, мы должны указать имя для каждого из них. Единственным исключением является слот по умолчанию. Итак, в приведенном выше примере мы добавляем nameсвойство для слотов верхнего и нижнего колонтитула. Слот без имени считается по умолчанию.

Когда мы используем cardкомпонент, нам нужно использовать templateэлемент с v-slotдирективой с именем слота: v-slot:[slot-name].

Примечание: v-slotдиректива имеет сокращение, в котором используется специальный символ #, за которым следует имя слота. Так, например, вместо v-slot: header, мы можем написать #header.

Именованные слоты также можно использовать со сторонними компонентами, как мы увидим в следующем разделе.

Использование именованных слотов с карточным компонентом Bulma

Давайте возьмем компонент Bulma’s Card и немного его подправим:

const app = Vue.createApp ({})

app.component ('card’, {

template: `

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

`

 

})

app.mount ('#app’)

.container {

width: 300px;

}

 

 

 

 

 

Здесь мы используем классы из компонента 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: `

 

 

 

 

 

 

 

{{ eyebrow }}

 

 

 

{{ title }}

 

 

 

{{ pricing }}

 

 

 

 

 

 

`

 

})

app.mount ('#app’)

 

 

<vacation-card

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>

 

 

Как видите, для предоставления всех необходимых данных/контента этот vacation-cardкомпонент использует шесть реквизитов. Это определенно делает его многоразовым, но также сложным в обслуживании. Мы можем создать гораздо более четкую и удобную в сопровождении версию, используя слоты вместо некоторых реквизитов.

Перепишем компонент со слотами:

const app = Vue.createApp ({})

app.component ('vacation-card’, {

props: ['url’, 'img’, 'imgAlt’],

template: `

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

`

 

})

app.mount ('#app’)

 

 

<vacation-card

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"

>

vacation-card>

 

 

Здесь мы сокращаем реквизиты до трех. Мы оставляем props только для метаданных и используем именованные слоты для фактического контента, что мне кажется более логичным.

Вот мои общие соображения об использовании реквизита и слотов.

Используйте реквизит, когда:

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

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

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

вам нужно предоставить метаданные или какую-то конфигурацию

Используйте слоты, когда:

вам нужно передать данные от ребенка к родителю

родитель может определить, как данные будут отображаться

вы хотите передавать не только данные, но и сложную HTML-разметку, определенный функционал и даже другие компоненты

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

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

Суть: для достижения наилучших результатов комбинируйте реквизит и слоты! 😀

Изучение других вариантов использования игровых автоматов

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

Повторное использование функциональности со слотами

Слоты могут предоставлять не только контент/структуру, но и функциональность. Давайте посмотрим на это в действии:

const app = Vue.createApp ({

data () {

return {

counter: 1

}

},

methods: {

increment () {

this.counter++

}

}

})

app.component ('double-counter’, {

props: ['counter’],

template: `

`,

computed: {

double () {

return this.counter * 2

}

}

})

app.mount ('#app’)

 

 

<double-counter: counter="counter">

 

double-counter>

 

 

Здесь мы создаем double-counterкомпонент, который будет удваивать значение счетчика. Для этого мы создаем вычисляемое свойство double, которое мы предоставляем родителю, привязывая его значение как атрибут слота. Вычисляемый принимает значение counterреквизита и удваивает его.

В родительском элементе у нас есть counterсвойство данных и increment () метод, который увеличивает его на единицу. Когда мы используем double-counter, мы привязываем свойство counter, а затем раскрываем doubleвычисляемое свойство. В выражении мы используем counterи double. Когда мы нажимаем кнопку, значение counterувеличивается на 1, а вычисляемое свойство пересчитывается с новым удвоенным значением. Например, если counterсвойство установлено на 3, удвоенное значение будет равно 6 (3×2 = 6).

Мы можем сделать этот компонент более гибким. Давайте настроим его, чтобы умножить счетчик на любое пользовательское значение:

const app = Vue.createApp ({

data () {

return {

counter: 1,

by: 4

}

},

methods: {

increment () {

this.counter++

}

}

})

app.component ('multiply-counter’, {

props: ['counter’, 'by’],

template: `

`,

computed: {

multiply () {

return this.counter * this.by

}

}

})

app.mount ('#app’)

 

 

<multiply-counter: by="by": counter="counter">

 

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 ('renderless-list’, {

props: ['items’, 'name’],

render () {

return this. $slots.default ({

items: this.items,

name: this.name

}) ;

}

})

app.mount ('#app’)

 

 

<renderless-list name="My shopping list:": items="products">

renderless-list>

 

 

Здесь мы создаем renderless-listкомпонент, который принимает nameи itemsподдерживает. Он также предоставляет один слот с ограниченной областью действия в функции рендеринга.

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

Примечание: в Vue 3 this. $scopedSlotsон удален и this. $slotsиспользуется вместо него. Кроме того, this. $slotsпредоставляет слоты как функции. Дополнительную информацию см. в разделе Объединение слотов.

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

 

 

<renderless-list name="My shopping list:": items="products">

 

renderless-list>

 

 

table, th, td {

border: 1px solid black;

border-collapse: collapse;

padding: 5px;

}

Здесь мы используем ту же функциональность, но определяем другую структуру контента.

Заключение

Так что в этом вся мощь и гибкость слотов. Как мы видели, их можно использовать в самых разных случаях, что позволяет нам производить многоразовые и универсальные компоненты. В сочетании с реквизитом слоты дают нам все необходимое для создания сложных компонентов и приложений. Слоты просты в использовании, но чрезвычайно эффективны. Если вы не использовали их раньше, я думаю, что сейчас самое подходящее время, чтобы начать это делать. Лучшее место для начала или продолжения этого пути — официальная документация по игровым автоматам. Удачи!

Делитесь нашими материалами с друзьями!

 

 

Заказать разработку сайта