源代码可以查看我的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. MySQL之SQL优化详解(三)

    目录 MySQL 之SQL优化详解(三) 1. 索引优化 2. 剖析报告:Show Profile MySQL 之SQL优化详解(三) 1. 索引优化 一旦建立索引,select 查询语句的where ...

  2. Storm 学习之路(二)—— Storm核心概念详解

    一.Storm核心概念 1.1 Topologies(拓扑) 一个完整的Storm流处理程序被称为Storm topology(拓扑).它是一个是由Spouts 和Bolts通过Stream连接起来的 ...

  3. 以实现MongoDB副本集状态的监控为例,看Telegraf系统中Exec输入插件如何编写部署

    既有的Telegraf 关于MongoDB的输入插件很难实现对副本集节点状态的监控,副本集节点状态有 PRIMARY.SECONDARY.RECOVERYING.ARBITER 等.现在我们尝试通过  ...

  4. 【安装】Hadoop2.8.0搭建过程整理版

    Hadoop搭建过程 前期环境搭建主要分为软件的安装与配置文件的配置,集成的东西越多,配置项也就越复杂. Hadoop集成了一个动物园,所以配置项也比较多,且每个版本之间会有少许差异. 安装的方式有很 ...

  5. Java进阶——高性能MySQL(一)

    MySQL逻辑架构: 链接管理与安全性: MySQL5.5或更高版本版本提供了一个API,支持线程池(Thread-Pooling)插件,可以使用池中的少量线程来服务大量的连接. 优化与并行: MyS ...

  6. node中websocket的使用

    web Socket和Socket.IO框架 http协议是无状态的,就是说客户端可以给服务器提交请求,但是服务器不能向客户端提交请求,但是我们实际项目中会要求客户和服务器双方是类似电话那种关系, 一 ...

  7. 为什么很多IT公司不喜欢进过培训机构的人呢

    这几天在知乎看到一个问题“为什么很多IT公司不喜欢进过培训机构的人呢?” 身为IT培训师,这样的问题必然会引起我的关注, 花时间看了各路人士的回答, 我了个去,尽是对培训机构排山倒海的谩骂声, 负面评 ...

  8. Apicloud 接入海康摄像头

    1准备工作 , 加载apicloud 海康视频模块. 引入 SDK 重新生成项目测试 再config.xml写入appid 话不多说直接上代码 video=api.require("haik ...

  9. shell遍历文件

    取文件每行的数据,需要按列取  可以 sed 加管道 使用 awk 取列 platform="list.txt" line=`grep -vc '^$' $platform` ; ...

  10. 201907 TIOBE 编程语言排行榜-Python坐稳第三

    目录 一.编程语言7月排行榜 二.Top10编程语言指数走势(2002-2018) 三.历史排名(1988-2019) 四.编程语言"名人榜"( 2003-2018) 五.Top2 ...