源代码可以查看我的github:  https://github.com/Jasonwang911/TryHardEveryDay/tree/master/Vuex/vuex-resouce  欢迎star

先描述一下vuex的使用:

store.js

import Vue from "vue";
import Vuex from "./vuex/myVuex"; Vue.use(Vuex); export default new Vuex.Store({
state: {
age: 20
},
getters: {
// date 的 computed
myAge(state) {
return state.age + 10;
}
},
mutations: {
syncAdd(state, payload) {
state.age += payload;
},
syncMinuts(state, payload) {
state.age -= payload;
}
},
actions: {
asyncMinus({ commit }, payload) {
setTimeout(() => {
commit("syncMinuts", payload);
}, 1000);
}
}
});

  

main.js中引用:

import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store"; Vue.config.productionTip = false; new Vue({
router,
store, // 在每个实例上添加一个 $store 对象
render: h => h(App)
}).$mount("#app");

先说这两点 

1. Store是一个类

2. Vue.use(Vuex);

首先建立一个类并导出,同时导出一个install的方法,这个方法接收一个参数 _Vue,即 vue实例

let Vue

class Store {

}

const install = _Vue => {
Vue = _Vue
} export default {
Store,
install
}

  

然后再main.js 中所作的就是讲store实例注册到vue的跟组件和所有的子组件上, 这里使用了Vue.mixin()的方法,在每个组件中注入$store,并在子组件中通过 this.$parents来拿到父组件的$store并添加到子组件的实例上

const install = _Vue => {
Vue = _Vue;
// console.log(Vue);
Vue.mixin({
beforeCreate() {
if (this.$options && this.$options.store) {
// 根组件
this.$store = this.$options.store;
} else {
this.$store = this.$parent && this.$parent.$store;
}
}
});
};

  

先来看看state是怎么用的

import Vue from "vue";
import Vuex from "./vuex/myVuex"; Vue.use(Vuex); export default new Vuex.Store({
state: {
age: 20
},
});

在new Vuex.Store的实例的时候传入了一个对象,这个对象options

然后我们添加state的这个属性

class Store {
constructor(options) {
// options 是 new Vuex时注入的对象
this._vm = options.state || {};
}
get state() {
// store.state
return this._vm;
}
}

这里有一个问题,通过options获取的state并不是Observe状态的,并不能响应式的更新视图,如何做才能使state变成响应式的并触发视图的更新呢,也就是通过Vue的数据劫持进行包装转换,

这里通过new Vue,并把state放入创建的Vue的data中来实现这个操作

class Store {
constructor(options) {
// options 是 new Vuex时注入的对象
this._vm = new Vue({
data: {
state: options.state
}
});
}
get state() {
// store.state
return this._vm.state;
}
}

 

这样,$store.state就变成了响应式的状态了

接下来,同理  getters,mutations, actions 也是通过options传入获取的

import Vue from "vue";
import Vuex from "./vuex/myVuex"; Vue.use(Vuex); export default new Vuex.Store({
state: {
age: 20
},
getters: {
// date 的 computed
myAge(state) {
return state.age + 10;
}
},
mutations: {
syncAdd(state, payload) {
state.age += payload;
},
syncMinuts(state, payload) {
state.age -= payload;
}
},
actions: {
asyncMinus({ commit }, payload) {
setTimeout(() => {
commit("syncMinuts", payload);
}, 1000);
}
}
});

  

先来实现一下getters方法: 每一个getter方法其实都是getters的一个属性,但是这个属性返回了一个函数。属性可以返回函数的方法可以通过Object.definedProperty()中的get()来实现:

class Store {
constructor(options) {
// options 是 new Vuex.Store时注入的对象
// getters 拿到new Store的时候传入的getters
let getters = options.getters || {};
// 创建 Store 的 getters 属性
this.getters = {};
Object.keys(getters).forEach(getterName => {
// 是个函数,但是返回的是个属性
Object.defineProperty(this.getters, getterName, {
get() {
return getters[getterName](this.state);
}
});
});
} }

  

这里其实只做了一件事情: 循环传入的options上的getters对象,并在用户调用getters中的每一个属性的时候返回一个getter函数并执行,

同理,mutations和actions也是如此实现的,只不过各自多了一个commit和dispatch的方法。

commit 和 dispatch 方法的原理就是通过参数type去对应的mutations和actions中查找对应的mutation或者action传入payload并执行

dispatch = (type, payload) => {
this.actions[type](payload);
};
commit = (type, payload) => {
this.mutations[type](payload);
};

  

查看Vuex源码,作者巧妙的将这个通过对象key进行循环的方法封装成了一个forEach函数:

const forEach = (obj, callback) => {
Object.keys(obj).forEach(key => {
callback(key, obj[key]);
});
};

 这个函数传入了一个对象和一个回调函数,通过对key的循环,执行了回调函数,并向回调函数中传入了循环出对象obj的key和value,整理后整个Store对象变成了如下:

const forEach = (obj, callback) => {
Object.keys(obj).forEach(key => {
callback(key, obj[key]);
});
}; class Store {
constructor(options) {
// options 是 new Vuex时注入的对象
// this._s = options.state || {};
// 将store中的状态变成可被观测的数据
this._vm = new Vue({
data: {
state: options.state
}
});
// getters 拿到new Store的时候传入的getters
let getters = options.getters || {};
// 创建 Store 的 getters 属性
this.getters = {};
forEach(getters, (getterName, fn) => {
Object.defineProperty(this.getters, getterName, {
get: () => {
return fn(this.state);
}
});
});
// mutations
let mutations = options.mutations || {};
this.mutations = {};
forEach(mutations, (mutationName, fn) => {
this.mutations[mutationName] = payload => {
fn(this.state, payload);
};
});
// actions
let actions = options.actions || {};
this.actions = {};
forEach(actions, (actionName, fn) => {
this.actions[actionName] = payload => {
fn(this, payload);
};
});
}
dispatch = (type, payload) => {
this.actions[type](payload);
};
commit = (type, payload) => {
this.mutations[type](payload);
};
get state() {
return this._vm.state;
}
}

 

以上基本实现了一个简单的vuex的基本流程,所有的源码可以在我的github上查看,后续会继续修改支持vuex的模块化。

vuex的实现的更多相关文章

  1. 关于Vue.js 2.0 的 Vuex 2.0,你需要更新的知识库

    应用结构 实际上,Vuex 在怎么组织你的代码结构上面没有任何限制,相反,它强制规定了一系列高级的原则: 应用级的状态集中放在 store 中. 改变状态的唯一方式是提交mutations,这是个同步 ...

  2. vuex复习方案

    这次复习vuex,发现官方vuex2.0的文档写得太简略了,有些看不懂了.然后看了看1.0的文档,感觉很不错.那以后需要复习的话,还是先看1.0的文档吧.

  3. vuex 初体验

    vuex是vue的状态管理工具,vue进阶从es6和npm开始,es6推荐阮一峰大神的教程. vuex学习从官方文档和一个记忆小游戏开始.本着兴趣为先的原则,我先去试玩了一把-->. Vuex ...

  4. vuex(1.0版本写法)

    Vuex 是一个专门为 Vue.js 应用所设计的集中式状态管理架构. 官方文档:http://vuex.vuejs.org/zh-cn/  2.0和1.0都能在此找到 每一个 Vuex 应用的核心就 ...

  5. 关于Vue vuex vux 文档

    01. vue 链接 http://vuejs.org.cn/guide/ 02. vuex  ----->>状态管理模块儿<<------- https://vuex.vue ...

  6. vuex

    英文:(Introduction)中文:https://github.com/vuejs/vuex/issues/176(贡献者努力中)

  7. Vue 2.0 + Vue Router + Vuex

    用 Vue.js 2.x 与相配套的 Vue Router.Vuex 搭建了一个最基本的后台管理系统的骨架. 当然先要安装 node.js(包括了 npm).vue-cli 项目结构如图所示: ass ...

  8. Vue2.X的状态管理vuex记录

    记住上述的顺序情况:想要改变state,只能通过Mutation,虽然action可以直接改变state,这样会使每个状态可以方便的跟踪和记录(用Devtools跟踪) vue Method   -- ...

  9. 在vue1.0遇到vuex和v-model的坑

    事情是这样的,在开发项目的过程中我使用了vuex并且在store中定义了一个保存用户信息的对象 userInfo : { 'nickName' : '', // 昵称 'password' :'', ...

  10. vuex 笔记

    Vuex 笔记 一个简单的状态管理 单一数据源: const sourceOfTruth = {} const vmA = new Vue({ data: sourceOfTruth }) const ...

随机推荐

  1. 常用的HTTP状态代码(4xx、5xx)详解

    HTTP状态代码常用的如下: 400 无法解析此请求. 401.1 未经授权:访问由于凭据无效被拒绝. 401.2 未经授权: 访问由于服务器配置倾向使用替代身份验证方法而被拒绝. 401.3 未经授 ...

  2. Salesforce LWC学习(二) helloWorld程序在VSCode中的实现

    上一篇我们简单的描述了一下Salesforce DX的配置以及CLI的简单功能使用,此篇主要简单描述一下LWC如何实现helloWorld以及LWC开发时应该注意的一些规范. 做国内项目的同学直观的感 ...

  3. C语言版数据结构笔记

    现在把以前学的数据结构知识再理一遍,上机测试.首先最重要的是链表.在我看来,链表其实就是由一个个结构体连接而成的,创建一个链表有多种方式,头插法,尾插法等,这里采用的是尾插法.表述有不对的地方,欢迎更 ...

  4. GRPC与.net core

    系列章节 GRPC与.net core GRPC截止时间与元数据 GRPC与netcore Identity GRPC与netcore IdentityServer4 概述 GRPC的数据交互模式有: ...

  5. Linux 中 IDEA 不能调试(Debug)项目

    问题描述: can't debug project on idea linux. 在Linux 中, IDEA能运行项目,但是点击调试项目,弹出警告.警告内容如下: Required connecto ...

  6. 微服务-springboot热部署

    spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用. IDEA进行热 ...

  7. websocket实现群聊和单聊(转)

    昨日内容回顾 1.Flask路由 1.endpoint="user" # 反向url地址 2.url_address = url_for("user") 3.m ...

  8. Linux命令及安装

    1.三大操作系统 1.Unix Solaris(SUN) IOS(Aplle移动端) Mas OS(Aplle平板,电脑端) 2.Windows XP win7 win8 win10 3.Linux ...

  9. 前端动画 wow.js 效果

    让花里胡哨的特效变简单 wow.js动画class介绍 引入css样式以及js插件 <link rel="stylesheet" type="text/css&qu ...

  10. 转载《Flex 布局》

    网页布局(layout)是 CSS 的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂 ...