一、vuex用来做什么
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。其实就是vue的内存持久化的管理。
首先我们需要来通过npm安装vuex
npm install vuex --save
安装完成以后,在进行全局的注册这样使用起来会更方便, 如果不注册这样也不会影响任何东西,只是这样更简便。
// main.js
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store' // 引入store
Vue.config.productionTip = false
new Vue({
el: '#app',
router,
store, // 进行注册,这样就能通过this.$store进行调用到
components: { App },
template: '<App/>'
})
ps: 使用vuex好还是localstorage好?
两者应用场景不同。vuex是当前vue项目的全局状态对象,存放在内存中,一旦当前vue项目刷新,vuex的数据也将恢复默认值;而localstorage是当前域下可以永久存放在浏览器中的对象,即使刷新数据也仍然存在,只要在当前域中即可获取到存放在localStorage中的数据。
二、vuex重要的五个属性
- state,用于存放状态,就是store对象的全部属性。
- mutations ,每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。只能通过mutation来修改state的属性。
- actions,用于存放异步操作,Action 提交的是 mutation,而不是直接变更状态。
- getters , 加工state成员给外界,可以在这里进行对数据的组装等操作。
- modules ,模块化管理,解决了store属性太多导致的臃肿问题。
-
三、如何使用vuex
1. state
import Vue from 'vue'
import Vuex from 'vuex' // 导入vuex
// 显示的声明使用vuex
Vue.use(Vuex)
const store = new Vuex.Store({
// state用于存放状态
state: {
count: 0
}
})
// 对外暴露store对象
export default store
为了方便使用store变量的一些属性,vuex提供了混入变量的语法
<template>
<div>
<div>{{msg}}</div>
</div>
</template>
<script>
import store from '../store'
// mapState在computed里面去使用里面的参数是state中的变量名称,...是混入到当前变量中也就是可以在当前组件相当于data中的直接使用
import { mapState } from 'vuex'
export default {
name: 'start',
data () {
return {
msg: store.state.count, // 获取store对象的属性
}
},
computed: {
...mapState(['name', 'des']) // 在这里就将当前的state的属性进行了导入
}
}
</script>
增加和删除state中的成员变量
Vue.set(state,"age",15) // Vue.set 为某个对象设置成员的值,若不存在则新增
Vue.delete(state,'age') // Vue.delete 删除成员
2. mutations
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0
},
// 通过mutations来修改state的状态,这个里面必须都是同步函数
mutations: {
increment (state) {
state.count++
console.log(state.count)
}
}
})
export default store
在mutations里面的函数只能是同步函数不能是异步的
<template>
<div>
<div>{{msg}}</div>
<button @click="incr">click me</button>
<!-- 当点击button以后触发函数,对state的状态进行了修改,就会触发count进行重新读取值 -->
<h1>{{count}}</h1>
<!-- 如果mutation的函数需要入参必须在这里进行传递 -->
<button @click="clicked(2)">clicked</button>
</div>
</template>
<script>
import store from '../store'
import {mapMutations} from 'vuex'
export default {
name: 'start',
data () {
return {
msg: store.state.count,
}
},
methods: {
incr: function () {
// 通过提交触发increment进行变量的修改
store.commit('increment')
}
},
// 在这里重新计算值
computed: {
count () {
return this.$store.state.count
},
...mapMutations(['clicked']) // // 在这里就将当前的mutation的属性进行了导入
}
}
</script>
3. getters
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0,
todos: [
{ id: 1, text: '刘硕是我儿', done: true },
{ id: 2, text: '我是刘硕爹', done: false }
]
},
// getter 加工state给外界
getters: {
// 在这个箭头函数的参数里可以进行传递参数,
dochange: (state) => {
// 在这里是返回了item.done为true的元素
return state.todos.filter(item => item.done)
},
// 这个id是传进来的参数
getChange: (state) => (id) => {
// 在这里是返回了item.done为true的元素
return state.todos.find(item => item.id === id)
}
}
})
export default store
vuex对getters也提供了辅助函数
<template>
<div>
<h1>{{doTodosByAttr}}</h1>
<h1>{{doTodosByMethod}}</h1>
</div>
</template>
<script>
import store from '../store'
import { mapGetters } from 'vuex'
export default {
name: 'start',
data () {
return {
msg: store.state.count,
}
},
methods: {
incr: function () {
store.commit('increment')
}
},
// 在这里重新计算值
computed: {
// 去调用getters方法,这种是相当于属性去调用getters,会被缓存
doTodosByAttr () {
return this.$store.getters.dochange
},
// 这种是相当于方法去调用getters,不会被缓存
doTodosByMethod () {
return this.$store.getters.getChange(2)
},
...mapGetters(['dochange']),
}
}
</script>
4. actions
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 0,
todos: [
{ id: 1, text: '刘硕是我儿', done: true },
{ id: 2, text: '我是刘硕爹', done: false }
]
},
mutations: {
increment (state) {
state.count++
console.log(state.count)
},
docrazy (state) {
console.log('****')
},
docry (state) {
console.log('I am Crying')
}
},
// actions 异步操作 提交的是 mutation,而不是直接变更状态。
actions: {
// context 是一个和store拥有相同方法和属性的一个对象,但是并不是store的实例
increment (context) {
context.commit('increment')
},
// 进行分发以后会返回一个promise对象
incrementAsync ({commit}) {
// 在这里去提交mutations
commit('docrazy')
},
// 通过promise可以,这是正确处理异步的方式
actionA ({commit}) {
return new Promise((resolve, reject) => {
setTimeout(() => {
commit('docry')
resolve()
}, 1000)
})
}
}
})
export default store
<template>
<div>
<h1>{{doCrazy}}</h1>
<h1>{{doActionA}}</h1>
</div>
</template>
<script>
import store from '../store'
import {mapActions} from 'vuex'
export default {
name: 'start',
data () {
return {
msg: store.state.count,
}
},
computed: {
// 进行action的分发
doCrazy () {
this.$store.dispatch('incrementAsync')
},
doActionA () {
// 通过promise进行任务的返回
this.$store.dispatch('actionA').then(() => {
console.log('执行成功')
})
},
...mapActions(['clicked']) // 快速对actions进行导入
}
}
</script>
※:使用mapMutations、mapActions暴露的函数,需要手动传值,否则传入默认的事件对象。
5. modules:
import Vuex from 'vuex'
const moduleA = {
namespaced: true, // 开启命名空间,这样才能获取
state: {name: 'my name is liushuo'},
actions:{},
mutations:{},
getters:{}
}
const moduleB = {
namespaced: true,
state: {name: 'liushuo sha bi'},
actions:{},
mutations:{},
getters:{}
}
// 可以将每个属性定义成为好几个模块这样解决了非常臃肿的问题
const self = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
export default self
// 提交或者dispatch某个方法和以前一样,会自动执行所有模块内的对应type的方法
this.$store.commit('editKey')
this.$store.dispatch('aEditKey')
// 模块中mutations和getters中的方法接受的第一个参数是自身局部模块内部的state
// getters中方法的第三个参数是根节点状态
// actions中方法获取局部模块状态是context.state,根节点状态是context.rootState
此时通过快速获取的方式不会变:
computed:{
// 可以指定哪个模块下的某个state
...mapState('b', ['message']),
...mapMutations('b', ['clicked']),
...mapActions('b', ['doThink']),
...mapGetters('b', ['getThink']),
}
通过$store方式获取就会出现问题
$store.state.b.message // 多指定一层是哪个module
$store.getters['a/getThink'] // 需要通过中括号进行获取,因为含有斜杠
this.$store.commit("a/doThink")
this.$store.dispatch("a/makeThink")
※:为什么会有斜杠的出现:因为定义就是带斜杠的。