Vuex
安装
npm install vuex --save
或者
yarn add vuex
使用
在src目录下新建一个store的文件夹,在store里面创建一个index.js文件:
import Vue from 'vue'
import Vuex from 'vuex' //引入vuex
Vue.use(Vuex) //注册插件
const store = new Vuex.Store({ //new 一个 Vuex仓库
state: { //state里面放置的是要共享的数据
count: 5
},
actions: { //actions 是异步操作时候用到的
},
mutations: { //如果没有异步操作,就可以直接调用mutations更改数据
increment(state) {
state.count++
},
decrement(state) {
state.count--
}
}
})
export default store
在mian.js中引入Vuex:
import Vue from 'vue'
import App from './App'
import store from './store'
Vue.config.productionTip = false
/* eslint-disable no-new */
new Vue({
el: '#app',
store,
render: h => h(App)
})
这样就可以在组件内使用Vuex共享的数据了:
App.vue:
<template>
<div id="app">
<h1>APP的内容</h1>
<h1>父组件的count:{{$store.state.count}}</h1> //获取vuex中的count
<button @click="increment">++</button>
<button @click="decrement">---</button>
<HelloVuex/>
</div>
</template>
<script>
import HelloVuex from './components/HelloVuex'
export default {
name: 'App',
components: {
HelloVuex
},
methods:{
increment(){ //点击的时候触发这个事件。用commit发送这个事件,这样 vuex中的mutations就能监听到这个事件,改变vuex中数据
this.$store.commit('increment')
},
decrement(){
this.$store.commit('decrement')
}
}
}
</script>
<style>
</style>
Getters基本使用
在store中加入一个对象:getters,getters相当于我们普通组件中的计算属性
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 5,
students: [
{ name: '小红', age: 22 },
{ name: '小燕', age: 23 },
{ name: '小明', age: 12 }
]
},
actions: {
},
mutations: {
increment(state) {
state.count++
},
decrement(state) {
state.count--
}
},
getters: {
powerCount(state) { //定义计算函数,并把结果返回去
return state.count * state.count
},
getStud20(state) { //定义计算函数,并把结果返回去
return state.students.filter(s => s.age > 20)
}
}
})
export default store
在组件中使用:
HelloVuex.vue:
<template>
<div>
<h2>hellow的内容----</h2>
<h2>helloVuex的count:{{$store.state.count}}</h2>
<h2>{{$store.getters.powerCount}}</h2> //拿到计算属性
<h2>大于20岁的学生{{$store.getters.getStud20}}</h2> //拿到计算属性
</div>
</template>
<script>
export default {
name: 'HelloWorld',
}
</script>
<style scoped>
</style>
把Getters作为参数
getters: {
powerCount(state) {
return state.count * state.count
},
getStud20(state) {
return state.students.filter(s => s.age > 20)
},
getStud20Length(state, getters) { //这段代码的意思就是,把getters作为参数传递进去,这样就可以在里面使用getters.xxx 方法,前提是这个方法必须存在getters里面,这样就不用重复计算了
return getters.getStud20.length
}
},
如果想在Getters里面传递参数
如果要在Getters里面接收传递过来的参数,就必须要返回一个函数,这样才能传递自己的参数
getters: {
powerCount(state) {
return state.count * state.count
},
getStud20(state) {
return state.students.filter(s => s.age > 20)
},
getStud20Length(state, getters) {
return getters.getStud20.length
},
getAgeStu(state) {
return (age) => { //在这里,返回的是一个函数,接收参数
return state.students.filter(s => s.age > age) //返回年龄大于传递过来参数的学生
}
}
在组件中调用的时候也有一点不一样:
<h2>大于20岁的学生人数{{$store.getters.getStud20Length}}</h2> //普通的getters
<h2>---------------------分割----------</h2>
<h2>找到年龄大于13的学生{{$store.getters.getAgeStu(13)}}</h2> //可以传递参数的getters,因为返回的是一个函数,所以要加圆括号调用,并传递参数
Mutation状态更新
Vuex的store状态的更新唯一方式:提交Mutation
Mutation主要包括两部分:
● 字符串的事件类型(type)
● 一个回调函数(handler),该回调函数的第一个参数就是state。
Mutation传递参数
store:
mutations: {
increment(state) {
state.count++
},
decrement(state) {
state.count--
},
incrementCount(state, count) { //定义一个函数,第一个参数是state,第二个是传递过来的参数
state.count += count
}
}
参数的传递:
<template>
<div id="app">
<button @click="addCount(5)">++5</button>
<button @click="addCount(10)">++10</button>
</div>
</template>
<script>
export default {
name: 'App',
methods:{
addCount(count){ //点击事件
this.$store.commit('incrementCount',count) //发送事件,并带上参数
}
}
}
</script>
以对象的风格提交,并带上参数
组件提交部分:
methods:{
addCount(count){
this.$store.commit({ //提交过去后,Mutation会自动识别对应的函数
type: 'incrementCount',
count
})
}
}
store处理部分:
mutations: {
incrementCount(state, payload) { //这个时候拿到的payload是一个对象了
state.count += payload.count //所以要打点获取参数
}
}
Mutation响应规则
Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新
这就要求我们必须遵守一些Vuex对应的规则:
- 提前在store中初始化好所需的属性.
- 当给state中的对象添加新属性时, 使用下面的方式:
- 方式一: 使用Vue.set(obj, 'newProp', 123)
- 方式二: 用新对象给旧对象重新赋值
const store = new Vuex.Store({
state: {
count: 5,
students: [
{ name: '小红', age: 22 },
{ name: '小燕', age: 23 },
{ name: '小明', age: 12 }
],
info:{
name:'小燕',
age:22
}
},
mutations: {
updataInfo(state){
//设置
错误 state.info['sex'] = '女' //这种方式不是响应式的,设置了页面不会跟着改变
正确 Vue.set(state.info,'sex','女') //这种办法是响应式的,页面会跟着改变
//删除
错误 delete state.info.age //这种方式不是响应式的,设置了页面不会跟着改变
正确 Vue.delete(state.info,age) //这种方式不是响应式的,设置了页面不会跟着改变
}
}
})
把mutations的类型抽离成常量
在store文件夹下创建一个mutations-types.js文件:
export const INCREMENT = 'increment' //定义一个常量并导出
在store中使用:
import Vue from 'vue'
import Vuex from 'vuex'
import { INCREMENT } from './mutations-types'; //引入常量
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
count: 5,
students: [
{ name: '小红', age: 22 },
{ name: '小燕', age: 23 },
{ name: '小明', age: 12 }
],
info: {
name: '小燕',
age: 22
}
},
mutations: {
[INCREMENT](state) { //使用常量 用[]包裹,里面是常量,同样被解析成一个函数
state.count++
},
decrement(state) {
state.count--
},
incrementCount(state, payload) {
state.count += payload.count
}
}
})
export default store
组件中使用:
<script>
import HelloVuex from './components/HelloVuex'
import {INCREMENT} from './store/mutations-types'; //导入
export default {
name: 'App',
components: {
HelloVuex
},
methods:{
increment(){
this.$store.commit(INCREMENT) //使用
}
}
</script>
Action
不要在Mutation中进行异步操作,所以要进行异步的话,就要用到Action
Action的普通用法:
context是和store对象具有相同方法和属性的对象. 也就是说, 我们可以通过context去进行commit相关的操作, 也可以获取context.state等.
const store = new Vuex.Store({
state: {
count: 5,
students: [
{ name: '小红', age: 22 },
{ name: '小燕', age: 23 },
{ name: '小明', age: 12 }
],
info: {
name: '小燕',
age: 22
}
},
mutations: {
updataInfo(state,data) { //调用参数之后,更改数据
state.info = data
}
},
actions: {
getInfo(context,payload){
$.ajax({url,success:(data)=>{ //发送请求,拿到数据
context.commit('updataInfo',data) //拿到数据之后通过commit调用mutations里面的方法,并传入参数
console.log(payload)
}})
}
}
})
组件调用:
methods:{
getInof(){
this.$store.dispatch('getInfo','我是自带的参数')
}
}
Action配合Promise,拿到数据的用法
action:
actions: {
getInfo(context, payload) {
return new Promise((resolve) => { //返回一个Promise对象
setTimeout(() => { //这里进行异步操作
console.log('异步完成,返回参数')
resolve('11111') //拿到data后,resolve(data) 返回data
}, 1000)
})
}
}
组件调用事件:
methods:{
getInof(){
this.$store.dispatch('getInfo').then(res=>{ //调用dispatch触发事件,会返回一个Promise对象,用 .then方法就可以接收返回来的参数
console.log(res)
})
}
}
Module
用法:
import Vue from 'vue'
import Vuex from 'vuex'
import { INCREMENT } from './mutations-types';
Vue.use(Vuex)
const moduleA = { //新定义一个模块
state: {
name: '三哥'
},
mutations: {
},
getters: {
}
}
const store = new Vuex.Store({
state: {
count: 5,
students: [
{ name: '小红', age: 22 },
{ name: '小燕', age: 23 },
{ name: '小明', age: 12 }
],
info: {
name: '小燕',
age: 22
}
},
mutations: {
updataInfo(state, data) {
state.info = data
},
[INCREMENT](state) {
state.count++
},
decrement(state) {
state.count--
},
incrementCount(state, payload) {
state.count += payload.count
}
},
modules: { //在modules这里把模块加进来
a: moduleA
}
})
export default store
组件使用:
<h1>模块A的name:{{$store.state.a.name}}</h1> //在state.后面跟上模块名,然后就是内容了
模块中的mutations和getters用法是和原来的一样的:
模块A:
const moduleA = {
state: {
name: '三哥'
},
mutations: {
updataName(state, data) {
state.name = data
}
},
getters: {
fullname(state) {
return state.name + '1111'
}
}
}
组件中调用和显示:
<template>
<div id="app">
<h1>模块A的name:{{$store.state.a.name}}</h1>
<h1>模块A的getters:{{$store.getters.fullname}}</h1> //获取模块A的getters
<button @click="updataName">模块A的mutations</button>
</div>
</template>
<script>
import HelloVuex from './components/HelloVuex'
import {INCREMENT} from './store/mutations-types';
export default {
name: 'App',
components: {
HelloVuex
},
methods:{
updataName(){
this.$store.commit('updataName','四哥') //调用模块A的Mutations
}
}
}
</script>
getters补充
getters的第二第三个参数
import Vue from 'vue'
import Vuex from 'vuex'
import { INCREMENT } from './mutations-types';
Vue.use(Vuex)
const moduleA = {
state: {
name: '三哥'
},
mutations: {
updataName(state, data) {
state.name = data
}
},
getters: {
fullname(state) {
return state.name + '1111'
},
fullname2(state, getters) { //第二个参数,getters,代表模块本身的getters,所以可以调用自己的方法
return getters.fullname + '222'
},
fullname3(state, getters, rootState) { //第三个参数,rootState, 这个参数可以拿到根模块的state里面的参数
return getters.fullname2 + rootState.count
}
}
}
const store = new Vuex.Store({
state: {
count: '纳尼',
students: [
{ name: '小红', age: 22 },
{ name: '小燕', age: 23 },
{ name: '小明', age: 12 }
],
info: {
name: '小燕',
age: 22
}
}
modules: {
a: moduleA
}
})
export default store
子模块的actions补充
const moduleA = {
state: {
name: '三哥'
},
mutations: {
updataName(state, data) {
state.name = data
}
},
getters: {
fullname(state) {
return state.name + '1111'
},
fullname2(state, getters) {
return getters.fullname + '222'
},
fullname3(state, getters, rootState) {
return getters.fullname2 + rootState.count
}
},
actions: {
aupdataName(context) {
//这里的context.commit只能调用自己模块的方法,访问不到根模块的方法的
//如果想用根模块的方法,就要:
// context.rootGetters('xxx') //这样才能访问根的方法
// 我们可以打印context来看一下
console.log(context)
/**
* dispatch: ƒ boundDispatch(type, payload)
commit: ƒ boundCommit(type, payload, options)
getters: {…}
state: {__ob__: Observer}
rootGetters: {…}
rootState: {__ob__: Observer}
__proto__: Object
*/
setTimeout(() => {
context.commit('updataName')
}, 2000)
}
}
}