源代码可以查看我的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. netty服务端启动--ServerBootstrap源码解析

    netty服务端启动--ServerBootstrap源码解析 前面的第一篇文章中,我以spark中的netty客户端的创建为切入点,分析了netty的客户端引导类Bootstrap的参数设置以及启动 ...

  2. 【nginx】反向代理

    反向代理事项负载均衡 是什么:百度 版本 :tomcat8 x2 nginx 1.8.1 保证两台tomcat正常启动. 配置文件:D:\nginx-1.8.1\conf\nginx.conf ,红色 ...

  3. SQLPLUS执行PL/SQL语句块

    1.首先登录Oracle HR schema: 2.对于PL/SQL程序,分号表示语句的结束:而使用 "."  号表示整个语句块的结束,也可以省略.按回车键后,该语句块不会执行,即 ...

  4. 你真的会用mysql行级锁吗?mysql 行级锁全解析

    在互联网大并发应用大行其道的今天,应用的开发总是离不开锁,在分布式应用中,最常见的莫过于基于数据库的行级锁了,由于互联网公司中比较主流的数据库还是mysql,所以这一话题绕不开的就是mysql了,但是 ...

  5. 【PostgreSQL】 前缀模糊查询级优化

    前匹配模糊 使用B-Tree来加速优化前匹配模糊查询 构造数据 新建一张商品表,插入一千万条数据. create table goods(id int, name varchar); insert i ...

  6. 充气娃娃什么感觉?Python告诉你

    上期为大家介绍了requests库的基本信息以及使用requests库爬取某东的商品页,收到了很多同学的反馈说期待猪哥的更新,猪哥感到非常开心,今天就带大家来玩一把刺激的! 一.需求背景 在实际开发过 ...

  7. c++快速排序算法

    c++快速排序算法 题目描述 利用快速排序算法将读入的NN个数从小到大排序后输出. 快速排序是信息学竞赛的必备算法之一.对于快速排序不是很了解的同学可以自行上网查询相关资料,掌握后独立完成.(C++选 ...

  8. CentOS 6.5 下安装及使用中文输入法

    第一次在本机环境下搭载Linux环境,但搭载后发现在CentOS 6.5只能英文输入,于是试着安装并启用中文输入法,经过一翻折腾,实现了在终端和自带火狐浏览器下支持中文输入法. CentOS下安装中文 ...

  9. OSPF 单区域实验

    实验拓扑 实验需求 按照图示配置 IP 地址 按照图示分区域配置 OSPF ,实现全网互通 为了路由结构稳定,要求路由器使用环回口作为 Router-id 实验步骤 每台路由器都要将本地的所有直连网段 ...

  10. windows快速创建文本文档的几个方法快捷键和

    1. 在平常使用电脑中要经常用到在左面创建文本文档txt最笨重的方法就是右键但是这样非常的慢,有没有什么快捷键呢 2. 快捷键 快捷键就是Win+R ,键入notepad 然后回车就可以编辑了 是不是 ...