По традиции делимся полезными переводными материалами во frontend-разработке. В этот раз frontend-специалист SimbirSoft Никита сделал выбор в пользу материалов Nwose Lotanna, опубликованных на сайте blog.logrocket.com. С разрешения автора мы перевели статью, в которой он рассказывать о способах использования пропсов для передачи данных дочерним компонентам в Vue 3.
Примечание автора: Данная статья последний раз была обновлена 15 декабря 2022, чтобы отразить обновления, добавленные в Vue 3.
Пропсы — это важная фича в Vue для управления родительскими и дочерними компонентами, однако взаимодействие с ними может быть довольно мудреным. В этой статье мы изучим, как передавать данные из родительского компонента в дочерний с использованием пропсов в Vue 3. Весь код из этой статьи вы можете найти на GitHub. Что ж, начнем!

Содержание:
Перед началом
Что такое пропсы в Vue?
Зачем мне использовать пропсы?
Определение данных в родительском компоненте
Получение пропсов в Vue
Регистрация пропсов в Vue
Использование пропсов в Vue
Строго типизированные пропсы
Перед началом
Эта статья предназначена для разработчиков любого уровня, включая новичков.
Чтобы отслеживать то, что будет происходить в этой статье, вам понадобится установленный Node.js версии не ниже 16.х. Вы можете проверить установленную версию в терминале, выполнив команду:
node -v
Кроме того, вам понадобится текстовый редактор. Мы настоятельно рекомендуем VS Code. И наконец, вам необходим глобально установленный Vue 3. На момент написания статьи, актуальной является третья версия.
Прежде чем начать, скачайте стартовый проект Vue. Разархивируйте скачанный проект, перейдите в папку проекта, а затем выполните команду ниже для установки всех зависимостей:
npm install
Что такое пропсы в Vue?
Пропс в Vue — это кастомный атрибут, который вы можете зарегистрировать в любом компоненте. Вы определяете данные в родительском компоненте и присваиваете им определенное значение. Затем переходите в дочерний компонент, которому эти данные необходимы, и передаете значение атрибуту props. В результате данные становятся свойством дочернего компонента.
В компоненте, реализованном на Composition API, то есть с использованием <script setup>
, синтаксис будет выглядеть следующим образом:
<script setup>
const props = defineProps(['title'])
console.log(props.title)
</script>
Для компонентов, реализованных с помощью Options API:
export default {
props: ['title'],
setup(props) {
// setup() принимает пропсы в качестве первого аргумента
console.log(props.title)
}
}
Чтобы получить доступ к этим данным динамически из любого компонента, которому они нужны, вы можете использовать корневой компонент App.vue как родительский, хранить в нем данные, а затем регистрировать пропсы.
Зачем мне использовать пропсы?
Давайте представим, что у вас в есть объект с данными, которые вы хотите по-разному отобразить в двух разных компонентах. К примеру, пусть это будет топ-10 лучших исполнителей. Вполне вероятно, что в первую очередь вы подумаете о создании двух отдельных компонентов, в каждом из которых будет массив объектов с исполнителями и их отображение с помощью блока <template>
.
В данном случае это будет отличным решением, однако по мере масштабирования проекта и добавления все новых и новых компонентов, этот метод перестанет быть эффективным. Давайте убедимся в этом на примере стартового проекта, который вам нужно открыть с помощью VS Code. Откройте файл Test.vue и скопируйте в него код:
<template>
<div>
<h1>Vue Top 20 Artists</h1>
<ul>
<li v-for="(artist, x) in artists" :key="x">
<h3>{{artist.name}}</h3>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Test',
data (){
return {
artists: [
{name: 'Davido', genre: 'afrobeats', country: 'Nigeria'},
{name: 'Burna Boy', genre: 'afrobeats', country: 'Nigeria'},
{name: 'AKA', genre: 'hiphop', country: 'South-Africa'},
{name: 'Sarkodie', genre: 'hiphop', country: 'Ghana'},
{name: 'Stormzy', genre: 'hiphop', country: 'United Kingdom'},
{name: 'Lil Nas', genre: 'Country', country: 'United States'},
{name: 'Nasty C', genre: 'hiphop', country: 'South-Africa'},
{name: 'Shatta-walle', genre: 'Reagae', country: 'Ghana'},
{name: 'Khalid', genre: 'pop', country: 'United States'},
{name: 'ed-Sheeran', genre: 'pop', country: 'United Kingdom'}
]
}
}
}
</script>
Создайте новый файл Test2.vue
в папке Components и скопируйте в него код ниже:
<template>
<div>
<h1>Vue Top Artist Countries</h1>
<ul>
<li v-for="(artist, x) in artists" :key="x">
<h3>{{artist.name}} from {{artist.country}}</h3>
</li>
</ul>
</div>
</template>
<script>
export default {
name: 'Test2',
data (){
return {
artists: [
{name: 'Davido', genre: 'afrobeats', country: 'Nigeria'},
{name: 'Burna Boy', genre: 'afrobeats', country: 'Nigeria'},
{name: 'AKA', genre: 'hiphop', country: 'South-Africa'},
{name: 'Sarkodie', genre: 'hiphop', country: 'Ghana'},
{name: 'Stormzy', genre: 'hiphop', country: 'United Kingdom'},
{name: 'Lil Nas', genre: 'Country', country: 'United States'},
{name: 'Nasty C', genre: 'hiphop', country: 'South-Africa'},
{name: 'Shatta-walle', genre: 'Reagae', country: 'Ghana'},
{name: 'Khalid', genre: 'pop', country: 'United States'},
{name: 'ed-Sheeran', genre: 'pop', country: 'United Kingdom'}
]
}
}
}
</script>
<style scoped>
li{
height: 40px;
width: 100%;
padding: 15px;
border: 1px solid saddlebrown;
display: flex;
justify-content: center;
align-items: center;
}
a {
color: #42b983;
}
</style>
Чтобы зарегистрировать новый компонент, который вы только что создали, откройте файл App.vue
и скопируйте в него код:
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<Test/>
<Test2/>
</div>
</template>
<script>
import Test from './components/Test.vue'
import Test2 from './components/Test2.vue'
export default {
name: 'app',
components: {
Test, Test2
}
}
</script>
В терминале VS Code запустите ваш проект локально, выполнив команду:
npm run dev
Результат в окне браузера должен быть следующим:

Вы заметите, что если вам понадобится создать еще 5 похожих компонентов, вы будете копировать данные в каждый компонент по отдельности. Однако существует возможность один раз объявить данные в родительском компоненте, а затем передавать их в каждый из дочерних компонентов с помощью пропсов.
Определение данных в родительском компоненте
В тот момент, когда вы выбрали корневой компонент в качестве родительского, вам в первую очередь необходимо определить объект с данными внутри него. Если вы продолжаете следить за тем, что мы делаем, откройте файл App.vue
и скопируйте объект с данными в секцию <script>
.
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" />
<Test />
<Test2 />
</div>
</template>
<script>
import Test from "./components/Test.vue";
import Test2 from "./components/Test2.vue";
export default {
name: "app",
components: {
Test,
Test2,
},
data() {
return {
artists: [
{ name: "Davido", genre: "afrobeats", country: "Nigeria" },
{ name: "Burna Boy", genre: "afrobeats", country: "Nigeria" },
{ name: "AKA", genre: "hiphop", country: "South-Africa" },
{ name: "Sarkodie", genre: "hiphop", country: "Ghana" },
{ name: "Stormzy", genre: "hiphop", country: "United Kingdom" },
{ name: "Lil Nas", genre: "Country", country: "United States" },
{ name: "Nasty C", genre: "hiphop", country: "South-Africa" },
{ name: "Shatta-walle", genre: "Reagae", country: "Ghana" },
{ name: "Khalid", genre: "pop", country: "United States" },
{ name: "Ed Sheeran", genre: "pop", country: "United Kingdom" },
],
};
},
};
</script>
Получение пропсов в Vue
После определения данных, перейдите в каждый из дочерних компонентов и удалите из них объекты data()
вместе с их содержимым. Чтобы прокинуть пропсы в компонент, вы должны объявить пропсы, которые хотите получить, внутри каждого из компонентов. В каждом из Test
-компонентов на месте объектов с данными, которые мы только что удалили, создайте новое свойство так, как показано ниже:
<script>
export default {
name: 'Test',
props: ['artists']
}
</script>
Регистрация пропсов в Vue
Чтобы дать движку Vue понять, что у вас есть пропсы, которые вы динамически хотите передать в дочерние компоненты, вы должны сигнализировать об этом внутри родительского компонента. Сделать это можно в секции <template>
, как показано ниже:
<template>
<div id="app">
<Test v-bind:artists="artists"/>
<Test2 v-bind:artists="artists" />
</div>
</template>
<script>
export default {
name: 'Test',
props: {
artists: {
type: Array
}
}
}
</script>
В коде выше мы используем директиву v-bind
, чтобы связать массив artists
в родительском компоненте с пропсом artists
, который находится в каждом из дочерних компонентов.
Если вы сделаете это без использования директивы, то никакого смысла в этом не будет. Будьте внимательны: ни компилятор Vue, ни ESLint не подсветят это как ошибку:
<Test artists="artists"/>
<Test2 artists="artists"/>
Поэтому так важно быть внимательным и помнить об использовании директивы v-bind
для всех динамических связок.
Использование пропсов в Vue
После того как вы настроили пропсы в своем проекте Vue, вы можете использовать их внутри дочерних компонентов так, будто данные были объявлены внутри каждого из них. Это значит, что доступ к данным будет осуществляться с помощью this.artists
.
Строго типизированные пропсы
При строгой типизации пропсов вы можете быть уверены, что дочерний компонент получит именно тот тип данных, который вам нужен. В стартовом проекте для созданных нами пропсов вы можете добавить условие, что в качестве пропсов могут быть переданы только массивы:
<script>
export default {
name: 'Test',
props: {
artists: {
type: Array
}
}
}
</script>
Как следствие, если вы попытаетесь передать пропсом неверный тип, например String
, то в консоли появится сообщение об ошибке, которая укажет на несоответствие типов:

Заключение
В этой статье мы открыли для себя пропсы в Vue 3, выяснили, как они могут помочь соблюдать принцип DRY (не повторяйся) путем переиспользования объектов с данными. Мы также выяснили, как регистрировать и передавать пропсы внутри проекта Vue. Более подробную информацию о пропсах можно найти в официальной документации Vue. Удачи!
Спасибо за внимание! Надеемся, что этот перевод был полезен для вас.
Авторские материалы для разработчиков мы также публикуем в наших соцсетях – ВК и Telegram.