深入Vue底层,手写一个vuex

Posted 欧阳呀

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入Vue底层,手写一个vuex相关的知识,希望对你有一定的参考价值。


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方法注入,之后将用户传入的都绑定上去即可

1. 希望本文能对大家有所帮助,如有错误,敬请指出

2. 原创不易,还请各位客官动动发财的小手支持一波(关注、评论、点赞、收藏)
3. 拜谢各位!后续将继续奉献优质好文
4. 如果存在疑问,可以私信我(主页有Q)

以上是关于深入Vue底层,手写一个vuex的主要内容,如果未能解决你的问题,请参考以下文章

深入Vue底层,手写一个vuex

深入Vue底层,手写一个vuex

手写Vuex源码

Vuex深入解读(适用于Vue2)

VSCode自定义代码片段13——Vue的状态大管家

VSCode自定义代码片段13——Vue的状态大管家