Связь между компонентами Sibling в VueJs 2.0
В vuejs 2.0 model.sync
будет устарел.
Итак, что такое правильный способ связи между компонентами-братьями в vuejs 2.0?
Как я понимаю, идея в Vue 2.0 состоит в том, чтобы иметь связь с помощью магазина или шины событий.
Согласно evan:
Также стоит упомянуть, что "передача данных между компонентами" как правило, плохая идея, потому что в конечном итоге поток данных становится не поддающийся проверке и очень трудно отлаживать.
Если часть данных должна использоваться несколькими компонентами, предпочитайте глобальные магазины или Vuex.
[Ссылка на обсуждение]
и
.once
и .sync
устарели. Опоры теперь всегда в одну сторону вниз. к производить побочные эффекты в родительской области, компонент должен явно emit
событие вместо того, чтобы полагаться на неявное связывание.
(Итак, он предлагает использовать $emit
и $on
)
Я беспокоюсь из-за:
- Каждый
store
и event
имеет глобальную видимость (исправьте меня, если я ошибаюсь);
- Это много для создания нового хранилища для каждого младшего сообщения;
То, что я хочу, - это область как-то events
или stores
видимость для компонентов сиблингов. Или, может быть, я не понял эту идею.
Итак, как правильно общаться?
Ответы
Ответ 1
В Vue 2.0 я использую механизм eventHub, как показано в документации.
-
Определите централизованный центр событий.
const eventHub = new Vue() // Single event hub
// Distribute to components using global mixin
Vue.mixin({
data: function () {
return {
eventHub: eventHub
}
}
})
-
Теперь в вашем компоненте вы можете генерировать события с
this.eventHub.$emit('update', data)
-
И слушать ты делаешь
this.eventHub.$on('update', data => {
// do your thing
})
Обновление Пожалуйста, посмотрите ответ @alex, в котором описано более простое решение.
Ответ 2
Вы даже можете сделать это короче и использовать экземпляр root Vue
качестве глобального Event Hub:
Компонент 1:
this.$root.$emit('eventing', data);
Компонент 2:
mounted() {
this.$root.$on('eventing', data => {
console.log(data);
});
}
Ответ 3
Я знаю, что это старый вопрос, но я хотел показать другие каналы связи и как посмотреть приложение и сообщения с более высокой точки зрения.
Типы связи
Первое, что нужно понять при разработке приложения Vue (или фактически любого приложения на основе компонентов), - это то, что существуют разные типы связи, которые зависят от того, с какими проблемами мы имеем дело, и им нужны свои собственные каналы связи.
Бизнес-логика: относится ко всему, что относится к вашему приложению и его цели.
Логика представления: все, с чем взаимодействует пользователь или что является результатом взаимодействия с пользователем.
Эти две проблемы связаны с этими типами общения:
- Состояние приложения
- Родитель-ребенок
- Ребенок-Родитель
- Братья и сестры
Каждый тип должен использовать правильный канал связи.
Каналы связи
Канал - это свободный термин, который я буду использовать для обозначения конкретных реализаций для обмена данными вокруг приложения Vue.
Реквизит (Презентационная логика)
Самый простой канал связи в Vue для прямого общения между родителями и детьми. Его в основном следует использовать для передачи данных, относящихся к логике представления или ограниченному набору данных, по иерархии.
Ссылки и методы (логика представления)
Когда нет смысла использовать реквизит, чтобы позволить потомку обрабатывать событие от родителя, установка ref
для дочернего компонента и вызов его методов - это нормально.
Некоторые люди могут сказать, что это тесная связь между родителем и ребенком, но это та же связь, что и при использовании реквизита. Если мы можем договориться о контракте для реквизита, мы можем также договориться о контракте для методов.
События (Логика презентации)
$emit
и $on
. Самый простой канал связи для прямого общения между ребенком и родителем. Опять же, следует использовать логику представления.
Шина событий (Оба)
Большинство ответов дают хорошие альтернативы для шины событий, которая является одним из каналов связи, доступных для удаленных компонентов, или чего-то еще.
Это может оказаться полезным при передаче реквизитов повсюду - от дна к глубоко вложенным дочерним компонентам, при этом почти никаким другим компонентам они не нужны.
Будьте осторожны: последующее создание компонентов, привязывающих себя к шине событий, будет связано более одного раза, что приведет к срабатыванию нескольких обработчиков и утечкам. Лично я никогда не чувствовал необходимость в шине событий во всех одностраничных приложениях, которые я разрабатывал в прошлом.
Далее показано, как простая ошибка приводит к утечке, когда компонент Item
все еще срабатывает, даже если он удален из DOM.
// A component that binds to a custom 'update' event.
var Item = {
template: '<li>{{text}}</li>',
props: {
text: Number
},
mounted() {
this.$root.$on('update', () => {
console.log(this.text, 'is still alive');
});
},
};
// Component that emits events
var List = new Vue({
el: '#app',
components: {
Item
},
data: {
items: [1, 2, 3, 4]
},
updated() {
this.$root.$emit('update');
},
methods: {
onRemove() {
console.log('slice');
this.items = this.items.slice(0, -1);
}
}
});
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<div id="app">
<button type="button" @click="onRemove">Remove</button>
<ul>
<item v-for="item in items" :key="item" :text="item"></item>
</ul>
</div>
Ответ 4
Хорошо, мы можем общаться между братьями и сестрами через родителя, используя события v-on
.
Parent
|-List of items //sibling 1 - "List"
|-Details of selected item //sibling 2 - "Details"
Предположим, что мы хотим обновить компонент Details
при нажатии какого-либо элемента в List
.
в Parent
:
Шаблон:
<list v-model="listModel"
v-on:select-item="setSelectedItem"
></list>
<details v-model="selectedModel"></details>
Здесь:
-
v-on:select-item
это событие, которое будет вызываться в компоненте List
(см. ниже);
-
setSelectedItem
это метод Parent
для обновления selectedModel
;
JS:
//...
data () {
return {
listModel: ['a', 'b']
selectedModel: null
}
},
methods: {
setSelectedItem (item) {
this.selectedModel = item //here we change the Detail model
},
}
//...
В List
:
Шаблон:
<ul>
<li v-for="i in list"
:value="i"
@click="select(i, $event)">
<span v-text="i"></span>
</li>
</ul>
JS:
//...
data () {
return {
selected: null
}
},
props: {
list: {
type: Array,
required: true
}
},
methods: {
select (item) {
this.selected = item
this.$emit('select-item', item) // here we call the event we waiting for in "Parent"
},
}
//...
Здесь:
-
this.$emit('select-item', item)
отправит элемент через select-item
непосредственно в родительский. И родитель отправит его в представление Details
Ответ 5
Что я обычно делаю, если я хочу "взломать" обычные шаблоны связи в Vue, особенно сейчас, когда .sync
устарел, заключается в создании простого EventEmitter, который обрабатывает связь между компонентами. Из одного из моих последних проектов:
import {EventEmitter} from 'events'
var Transmitter = Object.assign({}, EventEmitter.prototype, { /* ... */ })
С помощью этого объекта Transmitter
вы можете сделать в любом компоненте:
import Transmitter from './Transmitter'
var ComponentOne = Vue.extend({
methods: {
transmit: Transmitter.emit('update')
}
})
И создать "принимающий" компонент:
import Transmitter from './Transmitter'
var ComponentTwo = Vue.extend({
ready: function () {
Transmitter.on('update', this.doThingOnUpdate)
}
})
Опять же, это действительно для конкретных целей. Не основывайте свое приложение на этом шаблоне, вместо этого используйте что-то вроде Vuex
.