предисловие
Сначала нам нужно знать, почему мы используем vuex. Взаимодействие между родительскими и дочерними компонентами может осуществляться с помощью реквизитов и пользовательских событий, а простое взаимодействие компонентов, не являющихся родительскими и дочерними, может осуществляться с помощью шины (пустой экземпляр Vue). Затем с помощью vuex можно решить сложную коммуникацию компонентов, не являющихся родительскими и дочерними.
Ничего не стоит просто использовать vuex, каждый может прочитать документацию и постучаться в код. Разве вы не хотите знать, как реализован vuex? !
Помимо исходного кода vuex, давайте сначала подумаем, как реализовать простой «vuex». Как все просто, мне не нужны геттеры, мутации, действия и т.д., мне нужно только состояние.
Коммуникация между компонентами, не являющимися родительскими и дочерними
Прежде чем это осознать, мы должны рассмотретьbus
Реализация, заимствующая пример с официального сайта:
var bus = new Vue()
// 触发组件 A 中的事件
bus.$emit('id-selected', 1)
// 在组件 B 创建的钩子中监听事件
bus.$on('id-selected', function (id) {
// ...
})
Тогда я не знал, куда поместить созданный автобус, и, наконец, у меня не было другого выбора, кроме как поставить его под окно и постоянно использовать window.bus. Хотя это нормально, это по-прежнему влияет на глобальную область видимости.
Внезапно в один прекрасный день я обнаружил, что могу смонтировать его под корневым экземпляром vue (с этого момента попрощайтесь с window.bus), поэтому у меня есть:
var app = new Vue({
el: '#app',
bus: bus
})
// 使用 bus
app.$options.bus
// or
this.$root.$options.bus
Потом я узнал, что автобус не просто$emit
а также$on
О событиях можно только сообщать. На самом деле шина — это экземпляр Vue, в котором данные реагируют. Например, в корневом экземпляре приложения есть два неродительско-дочерних компонента, оба из которых используют данные шины, поэтому они синхронны в ответе.
var bus = new Vue({
data: {
count: 0
}
})
Выше подкомпонент a изменяет счетчик, и если подкомпонент b использует счетчик, он может реагировать на последнее значение счетчика.
Сказав все это, вы еще не узнали? Это ли не реализация некомпонентной связи, состояние vuex? !
пакетный автобус
Да, инкапсулируйте шину прямо сейчас, это самый простой "vuex" (только функция состояния). Во-первых, у нас будет корневой экземплярapp
, в экземпляре есть два компонента, не являющихся родительско-дочернимиchildA
а такжеchildB
.
Реализация html кода выглядит следующим образом:
<div id="app">
<child-a></child-a>
<child-b></child-b>
</div>
Реализация неродительско-дочерних компонентов
Затем есть два компонента, не являющихся родительскими и дочерними, и реализация приложения.Все дочерние компоненты используют счетчик шины, который здесь представлен store.state, что согласуется с vuex:
// 待实现
const store = new Store(Vue, {
state: {
count: 0
}
})
// 子组件 a
const childA = {
template: '<button @click="handleClick">click me</button>',
methods: {
handleClick () {
this.$store.state.count += 1
}
}
}
// 子组件 b
const childB = {
template: '<div>count: {{ count }}</div>',
computed: {
count () {
return this.$store.state.count
}
}
}
new Vue({
el: '#app',
components: {
'child-a': childA,
'child-b': childB
},
store: store
})
Увидите, что в коде еще нужно реализовать Store. Обязательные параметры, потому что мне лень их здесь использоватьVue.use()
, так прямоVue
Он передается как параметр для использования, а затем второй параметр совпадает с параметром, который мы передали при использовании vuex.
Реализация магазина
Следующим шагом является реализация Store, которая реализуется в два этапа:
- создать экземпляр шины;
- Сделайте this.$store доступным для всех дочерних компонентов.
Первый шаг уже есть, а второй шаг в основном используетсяVue.mixin
к глобальным миксинам, а просто найдите корневой экземпляр с хранилищем и назначьте его прототипу Vue.$store
. Это гарантирует, что экземпляр дочернего компонента не будет перезаписан после его создания.$store
, это также может сделать так, чтобы приложению корневого экземпляра не нужно было специально писать миксины.
class Store {
constructor (Vue, options) {
var bus = new Vue({
data: {
state: options.state
}
})
this.install(Vue, bus)
}
install (Vue, bus) {
Vue.mixin({
beforeCreate () {
if (this.$options.store) {
Vue.prototype.$store = bus
}
}
})
}
}
Реализованный Store представляет собой простой «vuex», который имеет состояние vuex, достаточное для простой связи между неродительскими и дочерними компонентами.
Создать магазин в конструкторе Магазинаbus
instance и внедрить его в прототип Vue, чтобы все компоненты могли получить к нему доступthis.$store
то есть экземпляр автобуса.this.$store
является экземпляром Vue, поэтому доступthis.$store.state.count
Фактически осуществляется доступ к данным, тем самым реализуя синхронизацию ответов между неродительскими и дочерними компонентами. Все ссылки на исходный кодздесь.