Слоты с ограниченной областью видимости

Последнее обновление: 04.11.2020

Иногда возникает необходимость использовать данные дочернего компонента в содержимом родительского компонента, которое передается в дочерний. Что-то наподобие:

<div id="app">
    <user>
        <h3>Данные о пользователе</h3>
		<p>Имя: {{ user.name }}</p>
		<p>Возраст: {{ user.age }}</p>
     </user>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
const app = Vue.createApp({});
 
app.component('user', {
	data(){
		return { user:{ name: 'Tom', age: 36 }}
	},
    template: `<div><slot></slot></div>` 
});
app.mount('#app');
</script>

Данный пример, конечно, не будет работать, потому что для родительского компонента - в данном случае объекта приложения Vue объект user не существует, соответственно мы не можем обратиться к его свойствам name и age. Для решения этой задачи воспользуемся слотами с ограниченной областью видимости.

Слоты с ограниченной областью видимости (scoped slots) позволяют передавать данные между слотом и родительским компонентом. Подобные слоты определяют шаблон, в который можно передавать данные из дочернего компонента. И эти данные ограничены слотом.

Для определения шаблона в родительском компоненте применяется элемент <template>, в котором устанавливается специальный атрибут v-slot:имя_слота="данные". Значение этого атрибута - название объекта с данными, которые передаются от дочернего компонента.

Например, определим следующую веб-страницу:

<!DOCTYPE html>
<html>
<head>
<title>Слоты Vue 3</title>
<meta charset="utf-8" />
</head>
<body>
<div id="app">
    <user>
        <template v-slot:default="props">
          <h3>Данные о пользователе</h3>
          <p>Имя: {{ props.userinfo.name }}</p>
          <p>Возраст: {{ props.userinfo.age }}</p>
        </template>
     </user>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
const app = Vue.createApp({});
 
app.component('user', {
	data(){
		return { user:{ name: 'Tom', age: 36 }}
	},
    template: `<div>
                    <slot v-bind:userinfo="user"></slot>
            </div>` 
});
app.mount('#app');
</script>
</body>
</html>

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

<slot v-bind:userinfo="user"></slot>

Здесь устанавливается привязка. То есть через слот в родительский компонент мы передаем объект user. В родительском компоненте мы можем получить этот объект через userinfo.

Для слота с ограниченной областью видимости в родительском компоненте определен шаблон:

<template v-slot:default="props">
	<h3>Данные о пользователе</h3>
	<p>Имя: {{ props.userinfo.name }}</p>
	<p>Возраст: {{ props.userinfo.age }}</p>
</template>

В дочернем компоненте для слота не указано имя, поэтому по умолчанию его имя будет "default". Поэтому для получения данных из дочернего компонента применяется атрибут v-slot:default, то есть v-slot:название_слота. Значение этого атрибута props, указывает, что внутри шаблона все переданные данные мы сможем получить через ссылку props. Далее внутри шаблона мы можем обратиться к переданным данным: props.userinfo.name.

Слоты с ограниченной областью видимости Scoped slots in Vue 3

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

<!DOCTYPE html>
<html>
<head>
<title>Слоты Vue 3</title>
<meta charset="utf-8" />
</head>
<body>
<div id="app">
	<userslist>
		 <template v-slot:userdetails="props">
			<div>
			  <p>Имя: {{ props.userinfo.name}}</p>
			  <p>Возраст: {{ props.userinfo.age }}</p>
			</div>
        </template>
    </userslist>
</div>
<script src="https://unpkg.com/vue"></script>
<script>
const app = Vue.createApp({});
 
app.component('userslist', {
    data(){
		return { 
			users: [
					{name:'Tom', age: 36}, 
					{name:'Sam', age: 39}, 
					{name:'Bob', age: 25}
				]	
		}				
	},
    template: `<ul>
                <li v-for="user in users">
					<slot name="userdetails" v-bind:userinfo="user"></slot>
				</li>
            </ul>` 
});
app.mount('#app');
</script>
</body>
</html>

В данном случае компонент userslist выводит список users. Для каждого элемента из этого списка создается свой элемент slot:

<slot name="userdetails" v-bind:userinfo="user"></slot>

Для слота определяется одно свойство - userdetails. Каждый объект user из массива передается в родительский компонент через ссылку userinfo.

В родительском компоненте определяется шаблон, в котором выводится каждый объект user:

<template v-slot:userdetails="props">
	<div>
		<p>Имя: {{ props.userinfo.name}}</p>
		<p>Возраст: {{ props.userinfo.age }}</p>
	</div>
</template>

Причем в данном случае родительский компонент сам определяет шаблон для элементов списка и правила их стилизации.

Передача списков через scoped slot в компонентах в Vue 3
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850