Vuex很难?几十行代码我们实现一个!

Vuex的鼎鼎大名,用Vue的同学没有不知道的吧,其实它的实现并没有很复杂,仅仅几十行代码,我们就能构建一个自己的Vuex,还不学会它,在面试官面前装一波!

vuex的使用

store/index.js中,我们是这样使用vuex的,包括我们常用的state、getters、mutations、actions,其中actions是执行异步操作的:

javascript 复制代码
<!-- store/index.js -->
import Vuex from 'vuex';
import Vue from 'vue';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        age: 18
    },
    getters: {
        age(state){
           return state.age
        }
    },
    mutations: {
        setAge(state,payload){
            state.age = state.age + payload
        }
    },
    // actions 只是一个架构,  最终都是通过mutations来修改状态的 ,每个mutation执行完毕之后,可以得到对应的状态, devtools可以追踪每个状态变化
    actions: {
        delayAge(store,payload){
            setTimeout(()=>{store.commit('setAge',payload)},2000)
        } 
    }
})

export default store;

在页面中使用vuex:

vue 复制代码
<!-- xxx.vue -->
<template>
  <div>
    state今年:{{$store.state.age}}岁了!
    <br />
    getters今年:{{$store.getters.age}}岁了!
    <div>
      <button @click="add">过一年</button>
      <br />
      <button @click="deleyAdd">等会过一年</button>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {};
  },
  mounted() {},
  methods: {
    add() {
      this.$store.commit("setAge", 1);
    },
    deleyAdd() {
      this.$store.dispatch("delayAge", 1);
    },
  },
};
</script>

这样,我们的页面就可以操作vuex的数据,

点击按钮,第一个按钮是commit("setAge", 1),让数字加1,第二个按钮是dispatch("delayAge", 1),2秒后让数字加1。

使用自己的vuex

store/index.js中,我们将import Vuex from 'vuex' 变为 import Vuex from './vuex',也就是将使用node_modules中的vuex变为我们自己新建的vuex.js文件,所有我们需要在store/下新建一个vuex.js

从使用上可以看出,Vue.use(Vuex)const store = new Vuex.Store(),我们需要有install方法和一个Store构造函数:

js 复制代码
// vuex.js

// Vue.use()时,就会传过了一个Vue
const install = (vue) => {
   
}
class Store {
    // options 就是new Vuex.Store({}) 传入的配置项,包括state、getters、mutations、actions
    constructor(options) {
       
    }
}

export default {
    Store,
    install
};

Vue.use()时,就会传过来一个Vue实例 ,options 就是new Vuex.Store({}) 传入的配置项,包括state、getters、mutations、actions

将store放到每个组件上

js 复制代码
// vuex.js
let Vue;
// Vue.use()时,就会传过了一个Vue
const install = (vue) => {
    Vue = vue;
    // 将store放到每个组件上
    Vue.mixin({
        beforeCreate() {
            // 判断options上有没有store  没有直接找父级   因为根组件,我们会手动传store  可以看main.js  
            if (this.$options.store) {
                this.$store = this.$options.store
            } else {
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}

这里有一个判断,因为在main.js中,我们将store放在了根组件的options上,全局混入时,每个组件都需要获取根组件的options上的store(因为在组件上我们需要this.$store获取store),有的话(跟组件)直接获取,没有的话就需要一级级的向上寻找!然后放在每个组件的实例上的$store属性上。

js 复制代码
// main.js
import Vue from 'vue'
import App from './App.vue'
import store from './store'

new Vue({
  render: h => h(App),
  store, //这里放在根组件
}).$mount('#app')

初始化store/index.js 传入的options

js 复制代码
//vuex.js
class Store {
    constructor(options) {
        //state 将state变为响应式
        this.vm = new Vue({
            data: options.state
        })
        // this.vm.$data上就是Vue中data定义的数据,都是响应式的
        this.state = this.vm.$data;
        // 定义getters,mutations,actions 并默认为{}
        let { getters = {}, mutations = {}, actions = {} } = options;
        // 将store/index.js传入的getters、mutations、actions赋予this.getters、this.mutations、this.actions
        // 实现getters
        this.getters = {};
        // 注意this指向问题
        let _this = this;
        //Object.keys能打对象中的key遍历成数组,通过每个key,能找到对应的getter, getters[getterName]
        Object.keys(getters).forEach(getterName => {
            Object.defineProperty(this.getters, getterName, {
                get() {
                    return getters[getterName](_this.state)   // age(state){}
                }
            })
        })
        // 实现mutations 通过commit触发
        this.mutations = {}
        Object.keys(mutations).forEach(mutationName => {
            this.mutations[mutationName] = function (payload) {
                mutations[mutationName](_this.state, payload)  //setAge(state,payload){}
            }
        })
        //实现actions 通过dispatch触发
        this.actions = {}
        Object.keys(actions).forEach(actionName => {
            this.actions[actionName] = function (payload) {
                //_this就是store哦
                actions[actionName](_this, payload)   //delayAge(store,payload)
            }
        })
    }
}

实现commit和dispatch

js 复制代码
// vuex.js
commit(mutationName, payload) {  //commit('setAge',1)
    this.mutations[mutationName](payload)
}
dispatch(actionName, payload) {
    this.actions[actionName](payload)
}

完整代码

js 复制代码
//  vuex.js
/*
 这是我们自己写的vuex.js
 */

let Vue;
// Vue.use()时,就会传过了一个Vue
const install = (vue) => {
    Vue = vue;
    // 将store放到每个组件上
    Vue.mixin({
        beforeCreate() {
            // 判断options上有没有store  没有直接找父级   因为根组件,我们会手动传store  可以看main.js  
            if (this.$options.store) {
                this.$store = this.$options.store
            } else {
                this.$store = this.$parent && this.$parent.$store
            }
        }
    })
}
class Store {
    constructor(options) {
        //state 将state变为响应式
        this.vm = new Vue({
            data: options.state
        })
        // this.vm.$data上就是Vue中data定义的数据,都是响应式的
        this.state = this.vm.$data;
        // 定义getters,mutations,actions 并默认为{}
        let { getters = {}, mutations = {}, actions = {} } = options;
        // 将store/index.js传入的getters、mutations、actions赋予this.getters、this.mutations、this.actions
        // 实现getters
        this.getters = {};
        // 注意this指向问题
        let _this = this;
        //Object.keys能打对象中的key遍历成数组,通过每个key,能找到对应的getter, getters[getterName]
        Object.keys(getters).forEach(getterName => {
            Object.defineProperty(this.getters, getterName, {
                get() {
                    return getters[getterName](_this.state)   // age(state){}
                }
            })
        })
        // 实现mutations 通过commit触发
        this.mutations = {}
        Object.keys(mutations).forEach(mutationName => {
            this.mutations[mutationName] = function (payload) {
                mutations[mutationName](_this.state, payload)  //setAge(state,payload){}
            }
        })
        //实现actions 通过dispatch触发
        this.actions = {}
        Object.keys(actions).forEach(actionName => {
            this.actions[actionName] = function (payload) {
                //_this就是store哦
                actions[actionName](_this, payload)   //delayAge(store,payload)
            }
        })
    }
    commit(mutationName, payload) {  //commit('setAge',1)
        this.mutations[mutationName](payload)
    }
    dispatch(actionName, payload) {
        this.actions[actionName](payload)
    }
}

export default {
    Store,
    install
};

可以看出,不到70行的代码,就实现了我们自己的vuex,注释我都放在代码上了,不懂留言哦,赶紧去实操下吧!

相关推荐
Sun_light16 分钟前
6个你必须掌握的「React Hooks」实用技巧✨
前端·javascript·react.js
爱学习的茄子18 分钟前
深度解析JavaScript中的call方法实现:从原理到手写实现的完整指南
前端·javascript·面试
百锦再19 分钟前
重新学习Vue中的按键监听和鼠标监听
javascript·vue.js·vue·计算机外设·click·up·down
快起来别睡了22 分钟前
Vue 3 中的组件通信与组件思想详解
vue.js
优雅永不过时_v27 分钟前
基于vite适用于 vue和 react 的Three.js低代码与Ai结合编辑器
前端·javascript
WildBlue31 分钟前
🧊 HTML5 王者对象 Blob - 二进制世界的魔法沙漏
前端·javascript·html
不讲道理的柯里昂35 分钟前
Vue MathJax Beautiful,基于Mathjax的数学公式编辑插件
vue.js·开源
啷咯哩咯啷35 分钟前
Vue3构建低代码表单设计器
前端·javascript·vue.js
用户261245834016137 分钟前
vue学习路线(10.监视属性-watch)
前端·vue.js
凌览38 分钟前
斩获 27k Star,一款开源的网站统计工具
前端·javascript·后端