Исходный код Vuex: как реализовать простой vuex

Vuex

предисловие

Сначала нам нужно знать, почему мы используем 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, которая реализуется в два этапа:

  1. создать экземпляр шины;
  2. Сделайте 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, достаточное для простой связи между неродительскими и дочерними компонентами.

Создать магазин в конструкторе Магазинаbusinstance и внедрить его в прототип Vue, чтобы все компоненты могли получить к нему доступthis.$storeто есть экземпляр автобуса.this.$storeявляется экземпляром Vue, поэтому доступthis.$store.state.countФактически осуществляется доступ к данным, тем самым реализуя синхронизацию ответов между неродительскими и дочерними компонентами. Все ссылки на исходный кодздесь.