前言前端
其实我已经用过vuex一段时间了,最近又有一段时间没有用,结果今天又生疏了。为此,我决定再入门下。vue
首先vuex是啥?vuex是vue的一个状态管理器。何为状态管理器?状态管理器能够理解为一个小型的前端数据库。用来实现各个页面之间的数据共享。java
那为啥不用sessionStorge和localStorage共享数据呢。由于这里涉及到状态更新。当你在a页面更新了数据后,使用vuex的话,b页面数据就会自动更新。而使用sessionStorage或者localStorage就没有这种效果。node
1.使用vuex程序员
1.1 安装vuexvuex
vuex跟vue是分开的,使用vuex还须要安装,可使用npm也可使用yarn。代码以下:vue-cli
npm install vuex -S
或者
yarn add vuex
复制代码
1.2 引用vuex数据库
通过上面一个步骤已经安装了vuex,如今就是咱们使用vuex的时候。使用很简单,vue的src目录下新建store文件夹,在store文件夹下新建index.js文件。其实在其余地方建也能够,不过这不太符合规范,若是有人改你的代码的时候就能够找不到你的store放哪里。目录结构以下:npm
|-src
|- App.vue
|- assets
| |-logo.png
|-components
| |-HelloWorld.vue
|-main.js
|-store
| |-index.js
复制代码
1.3 引入vuexjson
在咱们新建的index.js中引入vue和vuex,而且使用vue调用vuex组件,这样咱们就能够在index中写vuex的程序了。
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
复制代码
写一个简单vuex程序。
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment (state) {
state.count++
}
}})
export default store
复制代码
在这个程序中,咱们在store中定义了一个字段count,初始值为0。咱们还定义了一个方法increment,每次调用increament,count值都会加1.
1.4 使用vuex中的数据
1.4.1 注入store
为了方便咱们使用vuex中的数据,咱们将store加入vue中,这样之后不管在那里均可以经过this.$store访问vuex了。
修改main.js,在new Vue的构造函数中加入store
import Vue from 'vue'
import App from './App.vue'
// 引入store
import store from './store'
Vue.config.productionTip = false
new Vue({
store,
render: h => h(App),
}).$mount('#app')
复制代码
1,4,2 使用stroe
假设咱们要在组件helloworld中使用store(vuex)中的数据。就可使用this.$store.state.字段名来获取store中存放的数据。使用store中的数据也是有要求的——“要放vue的computed属性中”,你放在其余地方好比created也行,或者直接赋值给data对象对应的属性。可是这样谁有个问题,就是当store中的数据更新的时候,页面数据不能自动更新。
<template>
<div class="contain">
<div class="title">{{name}}</div>
<p>
动物园里单身狗的数量为:
<span>{{count}}</span>只
</p>
<button @click="addCount">拆散一对情侣</button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
},
data() {
return {
name: 'hello world'
}
},
computed: {
count() {
return this.$store.state.count
}
},
methods: {
addCount() {
this.$store.commit('increment')
this.$store.commit('increment')
console.log('this.$store.state.count:', this.$store.state.count);
}
},
}
</script>
<style scoped>
.title {
font-size: 28px;
text-align: center;
margin: 10px;
}
</style>
复制代码
上面的程序初始的时候,页面显示“动物园里单身狗的数量为:0”。当咱们点击“拆散一对情侣”按钮时,“动物园里单身狗的数量为:”就变成了2.
若是咱们把count放在data对象中,好比把js改为下面这样子。点击“拆散一对情侣”按钮时,store中的count值变了,可是页面上“动物园里单身狗的数量”不会变。
export default {
name: 'HelloWorld',
props: {
msg: String
},
data() {
return {
name: 'hello world',
count: this.$store.state.count
}
},
methods: {
addCount() {
this.$store.commit('increment')
this.$store.commit('increment')
console.log('this.$store.state.count:', this.$store.state.count);
}
},
}
复制代码
1.5 插播一个广告
使用vue-cli3开发的时候,有时候由于eslint的限制很严格,因此致使编译不经过。能够修改package.json中eslint的rules。
好比在我项目中,eslint限制我不能写console,这致使我开发的时候很不方便。我在package.json中把no-console改成0,就去掉了这种限制
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {
"no-console": 0
},
"parserOptions": {
"parser": "babel-eslint"
}
}
复制代码
以上就是vuex的简单入门,如下咱们将更加深刻的讲解下vuex。
2.vuex的组成
vuex其实很简单,我之前学习vuex的时候,感受好高深,如今看来仍是蛮简单的。vuex只由4部分组成,这四部分分别负责不一样的功能,就至关于游戏中的4个不一样的角色吧。4个分别为:
vuex是单一状态树的,就是在整个vue程序中只有一个vuex实例(store)。单一状态树可让咱们很容易的定位代码的执行状况。
2.1 state
咱们通常获取store对象中的数据都是经过this.$store.state.key获取的。好比咱们获取count属性,咱们是这样获取的。
this.$store.state.count
复制代码
2.1.1 mapState函数
咱们获取state上的值,通常都是放在computed属性中的,若是state中有不少值,那么咱们就要在computed中写不少计算属性。为了介绍代码量,vuex提供了一个mapState函数。
咱们能够把程序改为以下这样子。注意这里引入了mapState,在computed中咱们也使用了mapState
import { mapState } from 'vuex'
export default {
name: 'HelloWorld',
props: {
msg: String
},
data() {
return {
name: 'hello world'
}
},
computed: mapState([
'count'
]),
methods: {
addCount() {
this.$store.commit('increment')
this.$store.commit('increment')
console.log('this.$store.state.count:', this.$store.state.count);
}
},
}
复制代码
实现的功能跟以前是同样的。
computed: mapState([
'count'
])
// 至关于咱们以前的
computed: {
count() {
return this.$store.state.count
}
}
复制代码
使用mapState更简便的方法是使用对象展开符....
computed: {
...mapState([
'count'
])
},
复制代码
若是想重命名,能够把mapState的参数改为对象格式
computed: {
...mapState({
count2: 'count'
})
},
复制代码
2.2 Getters
咱们有时候须要store中state的值进行计算,若是一个组件或者两个组件的话,咱们能够直接把属性放在computed中。可是若是多个组件都须要进行相同的计算的话。咱们代码就会很冗余。解决办法就是在store就对state的值进行计算。所以就要用到store的getters属性。
在咱们的案例中count表明单身狗的数量,初始值为0,这个世界是没有单生狗的。可是某天突然咱们要在vue里增长一个程序员组件(It.vue)。程序员这个群体,你们都懂的,单生狗特别多,假设比平均值count多10个,那么咱们能够在store中定义一个itDogs的属性,这个属性比count值多10。
修改store代码以下:
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++
}
},
getters: {
itDogs: state => {
return state.count + 10
}
}
})
export default store
复制代码
那么咱们该怎么获取呢?
获取getters中数据能够经过属性访问,也能够经过方法访问
2.2.1 经过属性访问
经过属性访问代码以下:this.$store.getters.健名,在这个需求中就是:
this.$store.getters.itDogs
复制代码
It.vue 中获取itDogs代码以下:
computed: {
itDogs: function () {
return this.$store.getters.itDogs
}
}
复制代码
2.2.2 经过方法访问
要想经过方法访问,那么getters中的属性,在定义的时候必须返回一个函数,而不是直接返回值
假设咱们的需求改变了,在程序员的世界里,使用不一样语言的单身狗的数量是不同的。好比使用js的就是在平均单身狗的数量上加10,使用java的就是平均的基础上加100
那么能够把getters里写itDogs写成一个函数,根据不一样的语言传入不一样的值,而后返回对应的结果。(固然也能够用其余方法)
store修改以下:
getters: {
itDogs: state => (num) => {
return state.count + num
}
}
复制代码
获取方法以下:
computed: {
itDogs: function () {
return this.$store.getters.itDogs(100)
}
},
复制代码
**经过属性方法访问getters中的值,这个值会被缓存起来。下次须要时能够直接从缓存中拿。经过方法访问的话,每次都要调用函数从新计算
2.2.3 访问其余getter
getter也能够接受其余getter做为第二个参数。好比男程序员单身狗的数量在通常的程序员单身狗的数量上又加100.
getters: {
itDogs: state => (num) => {
return state.count
},
manItDogs: (state, getters) => {
return getters.itDogs + 100
}
}
复制代码
2.2.4 mapGetters函数
mapGetters函数将store中getter映射到局部计算属性,好比getter是以下:
getters: {
itDogs: state => {
return state.count
},
manItDogs: (state, getters) => {
return getters.itDogs + 100
}
}
复制代码
获取的代码咱们修改以下:
computed: {
...mapGetters([
'itDogs',
'manItDogs'
])
},
复制代码
若是要重命名,能够把mapGetters的参数改为对象
computed: {
...mapGetters({
itDogs2: 'itDogs',
manItDogs2: 'manItDogs'
})
},
复制代码
2.3 Mutation
更改 Vuex 的 store 中的数据的惟一方法是提交 mutation。须要如今store中注册事件,后面才能调用。mutation中定义的函数必须是同步的。
好比咱们以前定义的
mutations: {
increment(state) {
state.count++
}
},
复制代码
咱们想要count的数量加1,咱们就调用
this.$store.commit('increment')
复制代码
2.3.1 传参
咱们以前定义了一个按钮叫“拆散一对情侣”。点击这个按钮咱们就把count的数量加2,咱们以前是这样调用的。
methods: {
addCount() {
this.$store.commit('increment')
this.$store.commit('increment')
}
},
复制代码
咱们调用了两次commit,这显得很奇怪,其实mutations中的函数是能够传参的。咱们修改increment函数。
mutations: {
increment(state, num) {
state.count += num
}
},
复制代码
state.count再也不是加1了,而是加上num。这样好了,不管是3p的仍是百人斩的,咱们均可以拆散了。
修改调用函数以下:
methods: {
addCount() {
this.$store.commit('increment', 2)
}
},
复制代码
2.3.2 对象参数
有时候咱们参数不少怎么办?咱们能够把第二个参数改为对象。
修改increment
mutations: {
increment(state, obj) {
state.count += obj.num
}
},
复制代码
修改调用
methods: {
addCount() {
this.$store.commit('increment', {
num: 2
})
}
},
复制代码
2.3.3 mapMutations
mapMutations能够将store中mutation中的方法映射为vue组件中methods的方法
methods: {
...mapMutations([
'increment'
])
},
复制代码
这样咱们调用组件的increment方法,就至关于调用stroe中mutation的increment方法
调用以下
<button @click="increment({num:2})">拆散一对情侣</button>
复制代码
2.4 Action
Action 相似于 mutation,不一样在于:
一个简单的action以下
actions: {
increment: (context, obj) => {
setTimeout(() => {
context.commit('increment', obj)
}, 5000);
}
}
复制代码
action 函数接受一个与 store 实例具备相同方法和属性的 context 对象,所以你能够调用 context.commit 提交一个 mutation,或者经过 context.state 和 context.getters 来获取 state 和 getters
如何调用action呢?咱们可使用dispatch来调用
this.$store.dispatch('increment')
复制代码
完整代码:
methods: {
increment: function () {
this.$store.dispatch('increment', { num: 2 })
}
},
复制代码
actions函数跟mutation函数同样都是能够传参的。
2.4.1 mapActions
mapActions将action中的方法,映射到vue实例methods方法上。
methods: {
...mapActions([
'increment'
])
},
复制代码
调用
<button @click="increment({num:2})">5秒后拆散一对情侣</button>
复制代码
2.4.2 组合多个action
store.dispatch能够处理被触发的 action 的处理函数返回的 Promise,而且 store.dispatch 仍旧返回 Promise
假设咱们的action以下
actions: {
actionA ({ commit }) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('someMutation')
resolve()
}, 1000)
})
}
}
复制代码
那么咱们在组件里能够这样处理:
store.dispatch('actionA').then(() => {
// ...
})
复制代码
在另外一个action里的话,能够这样调用
actions: {
// ...
actionB ({ dispatch, commit }) {
return dispatch('actionA').then(() => {
commit('someOtherMutation')
})
}
}
复制代码
总结:以上咱们vuex的基本用法都讲完了,以上知识点基本上能够解决咱们工做中面临的问题了。可是vuex还有些更加高深的用法,咱们下一节再讲