Связь между родственными компонентами в VueJs 2.0
18855 просмотра
5 ответа
5822 Репутация автора
В vuejs 2.0 model.sync
будет устаревшим .
Итак, как правильно общаться между родственными компонентами в vuejs 2.0 ?
Как я понял, идея Vue 2.0 заключается в том, чтобы общаться друг с другом с помощью магазина или шины событий .
По словам Эвана :
Также стоит упомянуть, что «передача данных между компонентами», как правило, плохая идея, потому что в конце поток данных становится не отслеживаемым и очень сложным для отладки.
Если часть данных должна совместно использоваться несколькими компонентами, предпочтите глобальные хранилища или Vuex .
А также:
.once
и.sync
устарели. Опоры теперь всегда в одну сторону. Чтобы создать побочные эффекты в родительской области, компонент должен явноemit
явить событие, а не полагаться на неявное связывание.
(Итак, он предлагает использовать $emit
и $on
)
Я волнуюсь из-за:
- У каждого
store
иevent
есть глобальная видимость (поправьте меня, если я не прав); - Слишком много, чтобы создать новый магазин для каждого незначительного общения;
То , что я хочу, чтобы рамки каких - то образом events
или stores
видимость для сибсов компонентов. Или, возможно, я не уловил идею.
Итак, как правильно общаться?
Автор: Sergei Panfilov Источник Размещён: 27.07.2016 02:40Ответы (5)
5 плюса
798 Репутация автора
Что я обычно делаю, если хочу «взломать» нормальные шаблоны взаимодействия в 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
этого.
9 плюса
5822 Репутация автора
Хорошо, мы можем общаться между братьями и сестрами через родителя, используя 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's 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
просмотр
58 плюса
3722 Репутация автора
В 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 , в котором описано более простое решение.
Автор: kakoni Размещён: 05.11.2016 08:4155 плюса
11442 Репутация автора
Вы даже можете сделать его короче и использовать корневой Vue
экземпляр в качестве глобального концентратора событий:
Компонент 1:
this.$root.$emit('eventing', data);
Компонент 2:
mounted() {
this.$root.$on('eventing', data => {
console.log(data);
});
}
Автор: Alex
Размещён: 29.10.2017 07:14
26 плюса
10567 Репутация автора
Я знаю, что это старый вопрос, но я хотел показать другие каналы связи и узнать, как просматривать приложение и сообщения с более высокой точки зрения.
Типы связи
Первое, что нужно понять при разработке приложения Vue (или фактически любого приложения на основе компонентов), - это то, что существуют разные типы связи, которые зависят от того, с какими проблемами мы имеем дело, и им нужны свои собственные каналы связи.
Бизнес-логика: относится ко всему, что относится к вашему приложению и его цели.
Логика представления: все, с чем взаимодействует пользователь или что является результатом взаимодействия с пользователем.
Эти две проблемы связаны с этими типами общения:
- Состояние приложения
- Родитель-ребенок
- Ребенок-Родитель
- Братья и сестры
Каждый тип должен использовать правильный канал связи.
Каналы связи
Канал - это свободный термин, который я буду использовать для обозначения конкретных реализаций для обмена данными вокруг приложения Vue.
Реквизит (Презентационная логика)
Самый простой канал связи в Vue для прямого общения между родителями и детьми . Его в основном следует использовать для передачи данных, относящихся к логике представления или ограниченному набору данных, по иерархии.
Ссылки и методы (логика представления)
Если нет смысла использовать реквизит для того, чтобы дочерний элемент мог обрабатывать событие от родителя, настройка a 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/vue@2.5.17/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>
Не забудьте удалить слушателей в destroyed
хуке жизненного цикла.
Централизованный магазин (Бизнес логика)
Vuex - это путь к Vue для управления государством . Он предлагает гораздо больше, чем просто события, и он готов к полномасштабному применению.
А теперь вы спросите :
[S] я должен создать магазин Vuex для каждого второстепенного сообщения?
Это действительно светит, когда:
- иметь дело с вашей бизнес-логикой,
- общение с бэкэндом
Таким образом, ваши компоненты могут действительно сосредоточиться на том, чем они должны быть, управляя пользовательскими интерфейсами.
Это не означает, что вы не можете использовать его для компонентной логики, но я бы применил эту логику к модулю Vuex с пространством имен, имеющему только необходимое глобальное состояние пользовательского интерфейса.
Чтобы избежать беспорядка в глобальном состоянии, мы должны разделить хранилище на несколько модулей с пространством имен.
Типы компонентов
Чтобы организовать все эти коммуникации и упростить повторное использование, мы должны думать о компонентах как о двух разных типах.
- Контейнеры для приложений
- Общие компоненты
Опять же, это не означает, что универсальный компонент должен быть повторно использован или что контейнер конкретного приложения не может быть повторно использован, но у них разные обязанности.
Контейнеры для приложений
Это просто простой компонент Vue, который оборачивает другие компоненты Vue (общие или другие специфичные для приложения контейнеры). Именно здесь должно происходить взаимодействие хранилища Vuex, и этот контейнер должен взаимодействовать с помощью других более простых средств, таких как реквизиты и прослушиватели событий.
Эти контейнеры могут даже не иметь нативных элементов DOM вообще, и общие компоненты справляются с этим.
каким-то образом сфера
events
илиstores
видимость для компонентов родного брата
Вот где происходит обзор. Большинство компонентов не знают о хранилище, и этот компонент должен (в основном) использовать один модуль хранилища с пространством имен с ограниченным набором getters
и actions
применяться с помощью предоставленных сопоставителей Vuex.
Общие компоненты
Они должны получать свои данные из реквизита, вносить изменения в свои локальные данные и генерировать простые события. Большую часть времени они не должны знать, что магазин Vuex существует.
Их также можно назвать контейнерами, поскольку их единственной обязанностью может быть отправка другим компонентам пользовательского интерфейса.
Родственное общение
Итак, после всего этого, как мы должны общаться между двумя родственными компонентами?
Это проще понять на примере: скажем, у нас есть поле ввода, и его данные должны быть общими для всего приложения (братья и сестры в разных местах дерева) и сохраняться с помощью бэкэнда.
Начиная с наихудшего сценария , наш компонент будет сочетать представление и бизнес- логику.
// MyInput.vue
<template>
<div class="my-input">
<label>Data</label>
<input type="text"
:value="value"
:input="onChange($event.target.value)">
</div>
</template>
<script>
import axios from 'axios';
export default {
data() {
return {
value: "",
};
},
mounted() {
this.$root.$on('sync', data => {
this.value = data.myServerValue;
});
},
methods: {
onChange(value) {
this.value = value;
axios.post('http://example.com/api/update', {
myServerValue: value
})
.then((response) => {
this.$root.$emit('update', response.data);
});
}
}
}
</script>
Чтобы разделить эти две проблемы, мы должны поместить наш компонент в специальный контейнер приложения и сохранить логику представления в нашем общем компоненте ввода.
Наш входной компонент теперь можно использовать повторно, и он не знает ни о бэкенде, ни о братьях и сестрах.
// MyInput.vue
// the template is the same as above
<script>
export default {
props: {
initial: {
type: String,
default: ""
}
},
data() {
return {
value: this.initial,
};
},
methods: {
onChange(value) {
this.value = value;
this.$emit('change', value);
}
}
}
</script>
Контейнер для нашего приложения теперь может стать мостом между бизнес-логикой и коммуникацией презентации.
// MyAppCard.vue
<template>
<div class="container">
<card-body>
<my-input :initial="serverValue" @change="updateState"></my-input>
<my-input :initial="otherValue" @change="updateState"></my-input>
</card-body>
<card-footer>
<my-button :disabled="!serverValue || !otherValue"
@click="saveState"></my-button>
</card-footer>
</div>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
import { NS, ACTIONS, GETTERS } from '@/store/modules/api';
import { MyButton, MyInput } from './components';
export default {
components: {
MyInput,
MyButton,
},
computed: mapGetters(NS, [
GETTERS.serverValue,
GETTERS.otherValue,
]),
methods: mapActions(NS, [
ACTIONS.updateState,
ACTIONS.updateState,
])
}
</script>
Так как магазин Vuex действия иметь дело с серверной связи, наш контейнер здесь не нужно знать о Вардар и внутреннем интерфейсе.
Автор: Emile Bergeron Размещён: 07.04.2018 01:34Вопросы из категории :
- javascript Как определить, какой из указанных шрифтов был использован на веб-странице?
- javascript Валидация клиентской стороны ASP.Net
- javascript Длина объекта JavaScript
- javascript Получение текста из выпадающего списка
- vue.js Проверка формы vue.js и отправка ajax
- vue.js Элемент DOM для соответствующего компонента vue.js
- vue.js [Vue warn]: не удается найти элемент
- vue.js vuejs: попытка сфокусировать ввод с помощью директивы v-el
- vuejs2 Перенаправление Vue.js на другую страницу
- vuejs2 Компоненты VueJS
- vuejs2 Связь между родственными компонентами в VueJs 2.0
- vuejs2 Vue 2 - Мутирующие реквизиты vue-warn
- vue-component Vue.js: Как указать реквизит в одном компоненте файла?
- vue-component Вызов гетеров Vuex от Vue-Router
- vue-component Vue.js - Использование родительских данных в компоненте
- vue-component Vue компонент доступа к объекту данных
- vuex Явные действия вызова vuex в компоненте `.vue` отсоединения / готовности
- vuex Uncaught TypeError: router.afterEach не является функцией
- vuex Vue.js автоматическое предупреждение о выходе из магазина Vuex
- vuex Vuex и реактивность в рендеринге списка