предисловие
Компоненты — одна из самых мощных функций vue.js, а области действия экземпляров компонентов не зависят друг от друга, а это означает, что данные между разными компонентами не могут ссылаться друг на друга. В общем случае компоненты могут иметь следующие отношения:
Как показано на рисунке выше, A и B, B и C, B и D — все отношения между родителями и детьми, C и D — отношения между братьями и сестрами, а A и C — межпоколенческие (возможно, несколько поколений).
Как выбрать эффективный способ коммуникации для разных сценариев использования? Это тема, которую мы собираемся обсудить. В этой статье описаны несколько способов взаимодействия между компонентами vue, такими как реквизиты,$emit
/$on
,$parent
/ $children
,$attrs
/$listeners
С предоставлением/внедрением различия и сценарии использования описаны с простыми для понимания примерами, в надежде помочь вашим друзьям.
Пожалуйста, нажмите на код этой статьиблог на гитхабе, это мелко на бумаге, давайте начнем вводить больше кода!
метод первый,props
/$emit
Родительский компонент посредством реквизитов для передачи сусамблирования B, B до $ EMIT, V-на компонента B компонента B в способе, принятом способом.
1. Родительский компонент передает значение дочернему компоненту
Далее мы используем пример, чтобы проиллюстрировать, как родительский компонент передает значения дочернему компоненту: как получить данные в родительском компоненте App.vue в дочернем компоненте Users.vueusers:["Henry","Bucky","Emily"]
//App.vue父组件
<template>
<div id="app">
<users v-bind:users="users"></users>//前者自定义名称便于子组件调用,后者要传递数据名
</div>
</template>
<script>
import Users from "./components/Users"
export default {
name: 'App',
data(){
return{
users:["Henry","Bucky","Emily"]
}
},
components:{
"users":Users
}
}
//users子组件
<template>
<div class="hello">
<ul>
<li v-for="user in users">{{user}}</li>//遍历传递过来的值,然后呈现到页面
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props:{
users:{ //这个就是父组件中子标签自定义名字
type:Array,
required:true
}
}
}
</script>
Резюме: родительский компонент передает данные дочернему компоненту через свойства. Примечание. В компонентах есть три формы данных: данные, реквизиты, вычисляемые
2. Дочерний компонент передает значения родительскому компоненту (в виде событий)
Далее, давайте используем пример, чтобы проиллюстрировать, как дочерний компонент передает значение родительскому компоненту: когда мы нажимаем «Vue.js Demo», дочерний компонент передает значение родительскому компоненту, и текст меняется с «передача значения " to " Дочерний элемент передает значение родительскому компоненту", который реализует передачу значения от дочернего компонента к родительскому компоненту.
// 子组件
<template>
<header>
<h1 @click="changeTitle">{{title}}</h1>//绑定一个点击事件
</header>
</template>
<script>
export default {
name: 'app-header',
data() {
return {
title:"Vue.js Demo"
}
},
methods:{
changeTitle() {
this.$emit("titleChanged","子向父组件传值");//自定义事件 传递值“子向父组件传值”
}
}
}
</script>
// 父组件
<template>
<div id="app">
<app-header v-on:titleChanged="updateTitle" ></app-header>//与子组件titleChanged自定义事件保持一致
// updateTitle($event)接受传递过来的文字
<h2>{{title}}</h2>
</div>
</template>
<script>
import Header from "./components/Header"
export default {
name: 'App',
data(){
return{
title:"传递的是一个值"
}
},
methods:{
updateTitle(e){ //声明这个函数
this.title = e;
}
},
components:{
"app-header":Header,
}
}
</script>
Резюме: дочерний компонент отправляет сообщения родительскому компоненту через события, которые на самом деле представляют собой дочерний компонент, отправляющий свои собственные данные родительскому компоненту.
Способ второй,$emit
/$on
Этот метод использует пустой экземпляр Vue в качестве центральной шины событий (центра событий), которая используется для запуска событий и мониторинга событий, а также изобретательно и легко реализует связь между любыми компонентами, включая родительско-дочерние, одноуровневые, межуровневые.. Когда наш проект относительно большой, мы можем выбрать vuex, лучшее решение для управления состоянием.
1. Конкретный метод реализации:
var Event=new Vue();
Event.$emit(事件名,数据);
Event.$on(事件名,data => {});
2. Приведите пример
Предполагая, что есть три родственных компонента, а именно компоненты A, B и C, как компонент C получает данные компонента A или B
<div id="itany">
<my-a></my-a>
<my-b></my-b>
<my-c></my-c>
</div>
<template id="a">
<div>
<h3>A组件:{{name}}</h3>
<button @click="send">将数据发送给C组件</button>
</div>
</template>
<template id="b">
<div>
<h3>B组件:{{age}}</h3>
<button @click="send">将数组发送给C组件</button>
</div>
</template>
<template id="c">
<div>
<h3>C组件:{{name}},{{age}}</h3>
</div>
</template>
<script>
var Event = new Vue();//定义一个空的Vue实例
var A = {
template: '#a',
data() {
return {
name: 'tom'
}
},
methods: {
send() {
Event.$emit('data-a', this.name);
}
}
}
var B = {
template: '#b',
data() {
return {
age: 20
}
},
methods: {
send() {
Event.$emit('data-b', this.age);
}
}
}
var C = {
template: '#c',
data() {
return {
name: '',
age: ""
}
},
mounted() {//在模板编译完成后执行
Event.$on('data-a',name => {
this.name = name;//箭头函数内部不会产生新的this,这边如果不用=>,this指代Event
})
Event.$on('data-b',age => {
this.age = age;
})
}
}
var vm = new Vue({
el: '#itany',
components: {
'my-a': A,
'my-b': B,
'my-c': C
}
});
</script>
$on
Я прослушал пользовательские события data-a и data-b, потому что иногда не уверен, когда событие сработает, и обычно оно отслеживается в смонтированном или созданном хуке.
Способ третий, vuex
1. Кратко познакомим с принципом Vuex
Vuex реализует односторонний поток данных и имеет состояние для глобального хранения данных. Когда компонент хочет изменить данные в состоянии, это необходимо сделать с помощью мутации. Мутация также предоставляет режим подписки для внешних подключаемых модулей для вызова для получения обновленных данных о состоянии. Когда все асинхронные операции (обычные при вызове внутреннего интерфейса для асинхронного получения обновленных данных) или пакетные синхронные операции должны проходить через действие, но действие не может напрямую изменить состояние, все равно необходимо изменить данные состояния с помощью мутации. . Наконец, в соответствии с изменением состояния, оно отображается в представлении.
2. Кратко представить функции каждого модуля в процессе:
- Компоненты Vue: компоненты Vue. На HTML-странице он отвечает за получение интерактивного поведения, такого как пользовательские операции, и за выполнение метода отправки для запуска соответствующего действия для ответа.
- диспетчеризация: метод триггера действия, который является единственным методом, который может выполнять действие.
- действия:Модуль обработки операционного поведения, компонентом в
$store.dispatch('action 名称', data1)
для запуска. Затем вызов мутации запускается функцией commit(), которая косвенно обновляет состояние.. Отвечает за обработку всех взаимодействий, полученных Vue Components. Содержит синхронные/асинхронные операции, поддерживает несколько методов с одинаковыми именами и запускается в порядке регистрации. Операции, запрашиваемые в фоновом API, выполняются в этом модуле, включая инициирование других действий и отправку мутаций. Этот модуль предоставляет пакет Promise для поддержки последовательного запуска действий. - commit: метод операции фиксации изменения состояния. Выполнение мутации — единственный способ выполнить мутацию.
- мутации:Метод операции изменения состояния, действиями в
commit('mutation 名称')
для запуска. это единственный рекомендуемый способ изменения состояния Vuex. Этот метод может выполнять только синхронные операции, а имя метода может быть только глобально уникальным. Во время операции будут обнаружены некоторые крючки для мониторинга состояния и так далее. - state: объект-контейнер управления состоянием страницы. Централизованно храните разрозненные данные объекта данных в компонентах Vue, что является уникальным в глобальном масштабе для унифицированного управления состоянием. Данные, необходимые для отображения страницы, считываются из этого объекта, а детальный механизм ответа данных Vue используется для выполнения эффективных обновлений состояния.
- геттеры: метод чтения объекта состояния. Этот модуль не указан отдельно на рисунке и должен быть включен в визуализацию.Компоненты Vue считывают объект глобального состояния с помощью этого метода.
3.Vuex и локальное хранилище
vuex — это менеджер состояния vue, и сохраненные данные являются реактивными. Но не сохранится, после обновления вернется в исходное состояние.Конкретный метод должен заключаться в том, чтобы скопировать копию данных в vuex и сохранить ее в localStorage.После обновления, если в localStorage есть сохраненные данные, выньте их и замените состояние в хранилище.
let defaultCity = "上海"
try { // 用户关闭了本地存储功能,此时在外层加个try...catch
if (!defaultCity){
defaultCity = JSON.parse(window.localStorage.getItem('defaultCity'))
}
}catch(e){}
export default new Vuex.Store({
state: {
city: defaultCity
},
mutations: {
changeCity(state, city) {
state.city = city
try {
window.localStorage.setItem('defaultCity', JSON.stringify(state.city));
// 数据改变的时候把数据拷贝一份保存到localStorage里面
} catch (e) {}
}
}
})
Здесь следует отметить, что поскольку в vuex все состояния, которые мы сохраняем, являются массивами, а localStorage поддерживает только строки, поэтому его необходимо преобразовать с помощью JSON:
JSON.stringify(state.subscribeList); // array -> string
JSON.parse(window.localStorage.getItem("subscribeList")); // string -> array
Способ четвертый,$attrs
/$listeners
1. Введение
Когда для многоуровневой вложенности компонентов необходимо передать данные, обычно используется метод через vuex. Но если вы просто передаете данные без промежуточной обработки, использование обработки vuex немного излишне. Для этой версии Vue2.4 предусмотрен другой метод ----$attrs
/$listeners
-
$attrs
: содержит привязки свойств (кроме класса и стиля), которые не распознаются (и не приобретаются) реквизитами в родительской области. Когда компонент не объявляет никаких реквизитов, все привязки родительской области (кроме класса и стиля) включаются сюда и могут быть переданы внутренним компонентам через v-bind="$attrs" . Обычно используется с опцией inheritAttrs. -
$listeners
: содержит прослушиватель событий v-on в родительской области (без декоратора .native). Его можно передать внутренним компонентам через v-on="$listeners"
Далее мы рассмотрим пример межуровневого общения:
// index.vue
<template>
<div>
<h2>浪里行舟</h2>
<child-com1
:foo="foo"
:boo="boo"
:coo="coo"
:doo="doo"
title="前端工匠"
></child-com1>
</div>
</template>
<script>
const childCom1 = () => import("./childCom1.vue");
export default {
components: { childCom1 },
data() {
return {
foo: "Javascript",
boo: "Html",
coo: "CSS",
doo: "Vue"
};
}
};
</script>
// childCom1.vue
<template class="border">
<div>
<p>foo: {{ foo }}</p>
<p>childCom1的$attrs: {{ $attrs }}</p>
<child-com2 v-bind="$attrs"></child-com2>
</div>
</template>
<script>
const childCom2 = () => import("./childCom2.vue");
export default {
components: {
childCom2
},
inheritAttrs: false, // 可以关闭自动挂载到组件根元素上的没有在props声明的属性
props: {
foo: String // foo作为props属性绑定
},
created() {
console.log(this.$attrs); // { "boo": "Html", "coo": "CSS", "doo": "Vue", "title": "前端工匠" }
}
};
</script>
// childCom2.vue
<template>
<div class="border">
<p>boo: {{ boo }}</p>
<p>childCom2: {{ $attrs }}</p>
<child-com3 v-bind="$attrs"></child-com3>
</div>
</template>
<script>
const childCom3 = () => import("./childCom3.vue");
export default {
components: {
childCom3
},
inheritAttrs: false,
props: {
boo: String
},
created() {
console.log(this.$attrs); // { "coo": "CSS", "doo": "Vue", "title": "前端工匠" }
}
};
</script>
// childCom3.vue
<template>
<div class="border">
<p>childCom3: {{ $attrs }}</p>
</div>
</template>
<script>
export default {
props: {
coo: String,
title: String
}
};
</script>
Как показано на фиг.$attrs
Представляет объект без унаследованных данных в формате {имя свойства:значение свойства}. Vue2.4 обеспечивает$attrs
, $listeners
Для передачи данных и событий упрощается взаимодействие между межуровневыми компонентами.
Проще говоря:$attrs
а также$listeners
это два объекта,$attrs
Хранится в свойствах, не являющихся реквизитами, привязанными к родительскому компоненту,$listeners
Он хранит несобственные события, связанные с родительским компонентом.
Метод пятый, предоставить/ввести
1. Введение
Новый API Vue2.2.0, эту пару опций нужно использовать вместе,Чтобы компонент-предок мог внедрять зависимость во всех своих потомков, независимо от того, насколько глубоким является уровень компонента, и он всегда будет действовать, когда будут установлены восходящие и нисходящие отношения.. Одним словом: предоставлять переменные в компонентах-предках через провайдер, а затем внедрять переменные в компоненты-потомки через inject.API предоставления/внедрения в основном решает проблему связи между межуровневыми компонентами, но сценарии его использования в основном заключаются в том, что подкомпоненты получают состояние родительского компонента, а между межуровневыми устанавливается связь между активным предоставлением и внедрением зависимостей. компоненты.
2. Приведите пример
Предположим, что есть два компонента: A.vue и B.vue, B является подкомпонентом A
// A.vue
export default {
provide: {
name: '浪里行舟'
}
}
// B.vue
export default {
inject: ['name'],
mounted () {
console.log(this.name); // 浪里行舟
}
}
Как видите, в A.vue мы установилиprovide: name, значение гребет по волнам, его функция состоит в том, чтобыnameЭта переменная доступна для всех его дочерних компонентов. А в Б.вью, черезinject
вводит предоставленный компонент Anameпеременная, то в компоненте B вы можете напрямую передатьthis.nameОбращаясь к этой переменной, ее значение также гребет волнами. Это основное использование API предоставления/внедрения.
нужно знать, это:Привязки обеспечить и внедрить не являются реактивными. Это сделано намеренно. Однако, если вы передаете прослушиваемый объект, свойства объекта по-прежнему реактивны.----vue официальная документация Таким образом, если имя A.vue, указанное выше, изменить, this.name B.vue не изменится, и оно по-прежнему остается лодкой в волнах.
3. Как обеспечить и внедрить реакцию на данные агрегата
Вообще говоря, есть два пути:
- Предоставьте экземпляр компонента-предка, а затем внедрите зависимости в компонент-потомок, чтобы вы могли напрямую изменять свойства экземпляра компонента-предка в компоненте-потомке, но этот метод имеет недостаток, заключающийся в том, что монтируются многие ненужные вещи, такие как свойства. на этом экземпляре. , методы
- Используйте последнюю версию API Vue.observable версии 2.6 для оптимизации адаптивного предоставления (рекомендуется)
Давайте рассмотрим пример: внучатые компоненты D, E и F получают значение цвета, переданное компонентом A, и могут реализовывать изменения, реагирующие на данные, то есть после изменения цвета компонента A компоненты D, E и F изменятся. соответственно (основной код выглядит следующим образом:)
// A 组件
<div>
<h1>A 组件</h1>
<button @click="() => changeColor()">改变color</button>
<ChildrenB />
<ChildrenC />
</div>
......
data() {
return {
color: "blue"
};
},
// provide() {
// return {
// theme: {
// color: this.color //这种方式绑定的数据并不是可响应的
// } // 即A组件的color变化后,组件D、E、F不会跟着变
// };
// },
provide() {
return {
theme: this//方法一:提供祖先组件的实例
};
},
methods: {
changeColor(color) {
if (color) {
this.color = color;
} else {
this.color = this.color === "blue" ? "red" : "blue";
}
}
}
// 方法二:使用2.6最新API Vue.observable 优化响应式 provide
// provide() {
// this.theme = Vue.observable({
// color: "blue"
// });
// return {
// theme: this.theme
// };
// },
// methods: {
// changeColor(color) {
// if (color) {
// this.theme.color = color;
// } else {
// this.theme.color = this.theme.color === "blue" ? "red" : "blue";
// }
// }
// }
// F 组件
<template functional>
<div class="border2">
<h3 :style="{ color: injections.theme.color }">F 组件</h3>
</div>
</template>
<script>
export default {
inject: {
theme: {
//函数式组件取值不一样
default: () => ({})
}
}
};
</script>
Несмотря на то, что обеспечить и внедрить в основном предоставляют варианты использования для высокоуровневых библиотек подключаемых модулей/компонентов, если вы можете умело использовать их в своем бизнесе, вы можете добиться вдвое большего результата, затрачивая половину усилий!
Способ шестой,$parent
/ $children
а такжеref
-
ref
: при использовании в обычном элементе DOM ссылка указывает на элемент DOM; при использовании в дочернем компоненте ссылка указывает на экземпляр компонента. -
$parent
/$children
: доступ к родительскому/дочернему экземпляру
Следует отметить, что эти два метода напрямую получают экземпляр компонента, и вы можете напрямую вызвать метод компонента или получить доступ к данным после использования. Давайте сначала посмотримref
Чтобы получить доступ к примеру компонента:
// component-a 子组件
export default {
data () {
return {
title: 'Vue.js'
}
},
methods: {
sayHello () {
window.alert('Hello');
}
}
}
// 父组件
<template>
<component-a ref="comA"></component-a>
</template>
<script>
export default {
mounted () {
const comA = this.$refs.comA;
console.log(comA.title); // Vue.js
comA.sayHello(); // 弹窗
}
}
</script>
но,Недостатком этих двух методов является то, что нет возможности общаться между уровнями или братьями и сестрами..
// parent.vue
<component-a></component-a>
<component-b></component-b>
<component-b></component-b>
Мы хотим получить доступ к двум компонентам компонента-b на странице, которая ссылается на него (здесь parent.vue) в компоненте-а. В этом случае нам нужно настроить дополнительные плагины или инструменты, такие как решение Vuex и Bus.
Суммировать
Общие сценарии использования можно разделить на три категории:
- Общение отца и сына:
Данные передаются от родителя к дочернему через реквизиты, а от дочернего к родительскому через события ($emit
); также может общаться через родительскую цепочку/дочернюю цепочку ($parent
/ $children
); ref также может получить доступ к экземплярам компонентов; обеспечить/внедрить API;$attrs/$listeners
- Связь с братом:
Автобус; Векс
- Межуровневая коммуникация:
Bus; Vuex; предоставить/внедрить API,$attrs/$listeners
Порекомендуйте полезный инструмент мониторинга ошибок для всехFundebug, добро пожаловать, чтобы попробовать это бесплатно!