概念
Vuex是一个专为Vue.js应用程序开发的状态管理模式。当项目比较庞大的时候,每个组件的状态很多,为了方便管理,需要把组件中的状态抽取出来,放入Vuex中进行统一管理。
每一个 Vuex 应用的核心就是store(仓库)。"store"基本上就是一个容器,它包含着你的应用中大部分的状态(state)。Vuex 和单纯的全局对象有以下两点不同:
Vuex的状态存储是响应式的。当 Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会相应地得到高效更新。
你不能直接改变store中的状态。改变store中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
简单应用
构建vue工程vue init webpack vuexStudy
构建后目录结构
其中:
index.js
import Vue from 'vue'
import Vuex from 'vuex'
//如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)
Vue.use(Vuex);
export default new Vuex.Store({
state: {
//存放组件之间共享的数据
//在组件通过this.$store.state.count获取
count: 0
},
mutations: {
//显式的更改state里的数据,不能用于处理异步事件
//组件中通过this.$store.commit('incrementByStep');调用
incrementByStep(state) {
state.count++;
}
},
getters:{
//如vue中的计算属性一样,基于state数据的二次包装,常用于数据的筛选和多个数据的相关性计算
},
actions:{
//类似于mutation,用于提交mutation来改变状态,而不直接变更状态,可以包含任意异步操作
}
});
new Vuex.Store({}) 表示创建一个Vuex实例,通常情况下,他需要注入到Vue实例里。 Store是Vuex的一个核心方法,字面上理解为“仓库”的意思。Vuex Store是响应式的,当Vue组件从store中读取状态(state选项)时,若store中的状态发生更新时,他会及时的响应给其他的组件而且不能直接改变store的状态,改变状态的唯一方法是显式地提交更改。
main.js引入vuex
import Vue from 'vue'
import App from './App'
//vuex文件
import store from './store'
Vue.config.productionTip = false;
/* eslint-disable no-new */
new Vue({
el: '#app',
//引入
store,
components: { App },
template: '<App/>'
})
APP.vue引用了counter这个组件
<div id="app">
<!--<img src="./assets/logo.png">-->
<!--<HelloWorld/>-->
<counter/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld'
import counter from './components/counter'
export default {
name: 'App',
components: {
//HelloWorld
counter
}
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
counter.vue定义counter组件
<template>
<div id="counterContent">
<div>{{ count }}</div>
<button v-on:click="addCount">请点击</button>
</div>
</template>
<script>
export default {
name: "counter",
computed: {
count () {
return this.$store.state.count
}
},
methods:{
addCount(){
debugger;
this.$store.commit('incrementByStep');
}
}
}
</script>
<style scoped>
#counterContent{
background-color: blue;
width:200px;
height:50px;
}
</style>
通过npm run dev
启动项目,最终的结果如图:
源码解读
node添加Vuex依赖下载的vuex文件(node_modules目录下)如下:
其中vuex.common.js在预编译调试时,CommonJS规范的格式,可以使用require("")引用的NODEJS格式。
vuex.esm.js在预编译调试时, EcmaScript Module(ES MODULE),支持import from 最新标准的。
vuex.js直接用在<script>标签中的,完整版本,直接就可以通过script引用。
而vuex的源码托管在https://github.com/vuejs/vuex,这里研究git上的源码。
入口
Vuex 源码的入口是 src/index.js。
import { Store, install } from './store'
import { mapState, mapMutations, mapGetters, mapActions, createNamespacedHelpers } from './helpers'
export default {
Store,
install,
version: '__VERSION__',
mapState,
mapMutations,
mapGetters,
mapActions,
createNamespacedHelpers
}
这是Vuex对外暴露的API。其中, Store是Vuex提供的状态存储类,通常我们使用Vuex就是通过创建 Store的实例。接着是install方法,这个方法通常是我们编写第三方Vue插件的时候使用。
install
install是在store.js内暴露的方法
当Vue通过npm安装到项目中的时候,我们在代码中引入第三方Vue插件需要添加下列代码
import Vue from 'vue'
import Vuex from 'vuex'
//如果在模块化构建系统中,请确保在开头调用了 Vue.use(Vuex)
Vue.use(Vuex);
执行Vue.use(Vuex)的时候,其实就是调用了install的方法并传入Vue的引用。
Vue.use
Vue.use = function (plugin) {
var installedPlugins = (this._installedPlugins || (this._installedPlugins = []));
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
// additional parameters
var args = toArray(arguments, 1);
args.unshift(this);
if (typeof plugin.install === 'function') {
//调用vuex的install
plugin.install.apply(plugin, args);
} else if (typeof plugin === 'function') {
plugin.apply(null, args);
}
installedPlugins.push(plugin);
return this
};
}
install
//判断Vue是否已存在,保证install方法只执行一次
if (Vue && _Vue === Vue) {
if (process.env.NODE_ENV !== 'production') {
console.error(
'[vuex] already installed. Vue.use(Vuex) should be called only once.'
)
}
return
}
//赋值给Vue变量,index.js文件的其它地方使用Vue这个变量
Vue = _Vue
//调用了 applyMixin 方法,给 Vue 的实例注入一个 $store 的属性
applyMixin(Vue)
}
plugin参数:
args参数:
var applyMixin = function (Vue) {
//获取版本信息,这里是2
var version = Number(Vue.version.split('.')[0]);
if (version >= 2) {
//调用vuexInit
Vue.mixin({ beforeCreate: vuexInit });
} else {
var _init = Vue.prototype._init;
Vue.prototype._init = function (options) {
if ( options === void 0 ) options = {};
options.init = options.init
? [vuexInit].concat(options.init)
: vuexInit;
_init.call(this, options);
};
}
//给Vue实例注入$store 的属性,可以通过this.$store.xxx访问
function vuexInit () {
var options = this.$options;
// store injection
if (options.store) {
this.$store = typeof options.store === 'function'
? options.store()
: options.store;
} else if (options.parent && options.parent.$store) {
this.$store = options.parent.$store;
}
}
};
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。