1. Vuex是什么?什么场景下使用?
Vuex是vue的一个插件,叫做状态管理模式,全局共享某一些状态
通俗来讲,当各组件需要共享某一组状态的时候,会用到Vuex,兄弟组件及跨级组件传值也可以派上用场(如果数据量不大,或者组件状态不需要共享也可以用中央信息插件event-bus)
2. Vuex的基本使用
vue-cli 4.0 以上,在搭建脚手架的时候选择此项就可以
项目搭建完成,便会在src文件夹下看到一个store,这就是自动生成的仓库
以下是vuex的一些基本操作,供参考:
import Vue from 'vue' import Vuex from 'vuex' Vue.use(Vuex) export default new Vuex.Store({ state: { name: 'Vuex', age: 18 }, // 可以看做vuex的计算属性 getters: { addName(state) { return `${state.name}牛逼` } }, // 提交数据更改 mutations: { syncAdd(state, payload){ state.age += payload }, syncReduce(state, payload){ state.age -= payload } }, // 处理异步,此处为异步提交数据 actions: { asyncReduce({commit}, payload) { setTimeout( () => { commit('syncReduce', payload) }, 1000) } }, // 管理多个模块,当vuex比较大的时候会用到 modules: { } })
- vue组件中的调用
<template> <div id="app"> <h2>{{$store.state.name}}</h2> <div>{{$store.getters.addName}}</div> <div>年龄: {{$store.state.age}}</div> <div><button @click="add()">加10</button></div> <div><button @click="reduce()">减10-异步</button></div> </div> </template> <script> export default { mounted () { // 这里可以访问到 vuex中的整个store console.log(this.$store) }, methods: { // 同步加10 add(){ this.$store.commit('syncAdd', 10) }, // 异步减2 reduce() { // 会去找对应的action this.$store.dispatch('asyncReduce', 2) } } } </script>
3. 手写一个vuex
- 从以上的应用,便可以反推出Vuex的基本源码
let Vue; class Store { constructor(options = {}) { // 实现响应式 核心(刚刚直接拿过用户的数组放上去,是没有响应式的) this.s = new Vue({ data() { return { state: options.state } } }) // 将用户传入的getters放到store实例之上 let getters = options.getters this.getters = {} // 通过循环,拿出键值,绑定访问器属性get 劫持对象的所有属性 Object.keys(getters).forEach((getterName) => { Object.defineProperty(this.getters, getterName, { get: () => { // 执行此函数 return getters[getterName](this.state) } }) }) // 获取所有同步更新的操作方法 let mutations = options.mutations // 放到实例上去 this.mutations = {} // 订阅,下面commit是发布 Object.keys(mutations).forEach( (mutationName)=> { // 当前实例上,通过名找方法 this.mutations[mutationName] = (payload) =>{ // 内部的第一参数是状态 mutations[mutationName](this.state, payload) } }) let actions = options.actions this.actions = {} forEachFn(actions, (actionName, fn) => { this.actions[actionName] = (payload) => { // fn 是这个玩意 asyncReduce fn(this, payload) } }) } // 提交更改,在当前store找到对应函数执行,通过名字找 发布 commit = (mutationName, payload) => { this.mutations[mutationName](payload) } // action 分发的方法 dispatch = (actionName, payload) => { this.actions[actionName](payload) } // 为了方便取值 get state() { return this.s.state } } const install = (_Vue) => { Vue = _Vue Vue.mixin({ beforeCreate() { console.log('beforeCreate') if (this.$options && this.$options.store) { // 根实例 // 根实例增加$store属性 this.$store = this.$options.store } else { this.$store = this.$parent && this.$parent.$store } } }) } export default { install, Store }
- 总体思路就是在Vue实例上挂上一个store实例,使用Vue提供的install方法注入,之后将用户传入的都绑定上去即可