#vue3知识点7 vue3.0+cli4.5 vuex
Vuex 是一个专为 Vue.js 的SPA单页组件化应用程序开发的状态管理模式插件。
由于Vue SPA应用的模块化,每个组件都有它各自的数据(state)、界面(view)、和方法(actions)。这些数据、界面和方法分布在各个组件中,当项目内容变得越来越多时,每个组件中的状态会变得很难管理。
vuex是集中管理组件中可以共享的状态值 , 组件和组件之间可以共享的值放在vuex的state里 ,即定义的时候就把它定义为全局变量。
state里的值是全局的,哪个组件都可以用。
比如说之前的父传子,子传父,数值的传递比较繁琐,现在都可以用vuex实现。
或者是两个毫无关系的组件要共用一个数据,那么也可以写在vuex.
先看看项目package.json里面有没有vuex,有可能在创建的时候就指定了vuex.
如果没有,再安装。
安装命令:
npm install vuex --save
#或
npm install vuex@next
由于我在创建项目时指定安装了vuex,所以vuecli3都给配置好了,不用像cli2一样手动配置。所以我们看着理解一下就好了。
如果创建项目时没有指定,按下面的配置即可。
配置vuex和配置路由类似:在根目录下有store文件夹,里面有index.js:
index.js的内容
//引入
import { createStore } from 'vuex'
//创建并导出store实例
export default createStore({
//存储状态值
state: {
//全局状态的数据源
},
mutations: {
//提交mutations是更改Vuex状态的唯一方法
},
actions: {
//动作 什么情况下状态值要发生变化,什么情况下调用mulations
//异步调用mutations
},
modules: {
//因为项目里有很多模块,在vuex中使用同一个store会很乱,所以,modules可以分割.
}
})
main.js 的配置
import store from './store'
const app=createApp(App)
app.use(store)
app.use(router)
app.mount('#app')
state数据源写在store/index.js的state里。
state:{
price:100,
count:10
}
那组件里怎么得到state里全局的值呢?
<div>
价格: {{ $store.state.price }}
div>
console.log(this.$store.state.price)
状态值有几个,mu’tations就有几个,一个state状态值对应一个mutations。状态值修改必须通过mutations。
mutations是操作state的唯一方法,只有mutations方法能够改变state状态值。
mutations方法必须是同步方法,不能带ajax之类的。
1)mutations里的一个方法func1,里面改变state里的值count.
const store = new Vuex.Store({
state: {
count: 1
},
mutations: {
//注意方法里面必须传一个state用于接收state的数据
func1 (state) {
// 变更状态
state.count++
}
}
})
this.$store.commit('func1')
并且,mutations方法是可以传参的。
函数:
mutations: {
add(state, n) {
state.count += n
}
},
组件里调用:
通常,参数会是一个对象,方便包含多个字段的读取。
this.$store.commit('add', 10)
actions也能修改state状态值,但它是通过提交mutations方法来修改store中的状态值。
官方推荐我们使用actions来修改state的属性,当然组件中可以直接用commit调用mutations方法。
之前说mutations方法必须只能是同步方法,为了处理异步方法,actions出现了。
代表vuex实例对象,它可以通过commit触发mutations里的方法。
下面是actions的两种用法:
第一种:调用mutations。来修改值,也可以传参数。
第二种,异步处理
mutations: {
func1(state) {
state.count++
}
},
actions: {
//第一种:调用mutations。来修改值
//直接触发mutations的func1
func1 (context) {
context.commit('func1')
},
//第二种,异步处理
//异步处理让func1的调用延时
func2 (context) {
// 延时1秒
setTimeout(() => {
context.commit('func1')
}, 1000)
}
},
//不同于mutations使用commit方法,actions使用dispatch方法。
this.$store.dispatch('func2 ')
store/index.js
export default createStore({
//1.1 state里写全局变量count
state: {
count:1,
},
mutations: {
//2.2 MUTATIONS里写参数替换state的count值的func1
func1(state,otherdata){
state.count=otherdata
}
},
actions: {
//2.3 actions里面写调用mutations的函数,带参给func1
actionfunc(context,n){
context.commit("func1",n)
}
},
modules: {
}
})
vuextest.vue
<template>
<div>
<h1>vuex的使用h1>
<h4>1.state全 局变量count: {{$store.state.count}}h4>
<h4>2. actions带参改变count做法h4>
<button @click="clickfunc">点击我触发clickfuncbutton>
div>
template>
<script>
export default {
name: 'vuextest',
data() {
return {
arr:[],
}
},
created(){
console.log(this.$store.state.count)
},
methods:{
clickfunc(){
//通过提交actions来修改vuex中的count值
//参数,如果是多个参数,就定义一个对象再传
//2.4 定义代替count的参数n,并在函数里调用actions
//带参给actionfunc
let n=2
this.$store.dispatch("actionfunc",n)
}
}
}
script>
模块,在大型项目中为了方便状态的管理,将store拆分成多个子模块modules,每个子模块都有完整的store,mutation,action,getter.
比如说:大型项目要进行模块划分,针对模块进行状态值的管理,比全部写进state要好。
把仓库划分成多个模块,一个模块可以包含多个组件。
在store中创建modules文件夹,里面写js文件,每个js文件代表一个模块,js文件的内容是每个模块的index.js。每个模块导出后,在store/index.js的modules引入它们的模块名。
下面举一个例子:
需求:
vue3demo3中有helloword.vue和vuextest1.vue,假如这俩是一个模块,有公共值count, 起名为hellovuex模块,另外axios文件夹是另一个模块axios. 在vuextest1里面引用count值,并改变它的值为2。
所涉及文件:
store/modules/axios.js
store/modules/hellovuex.js
store/index.js
vuextest1.vue
所以,modules里创建hellovuex.js和axios.js。代表两个模块。
每个模块.js的内容是这样的:
hellovuex.js
创建hellovuex对象,里面写上和store/index.js一样的内容,导出hellovuex对象。
//hellovuex.js
const hellovuex={
//helloworld和vuextest1 里面共用一个值count
state: {
count:1,
},
mutations: {
//2.2 MUTATIONS里写参数替换state的count值的func1
func1(state,otherdata){
state.count=otherdata
}
},
actions: {
//2.3 actions里面写调用mutations的函数,带参给func1
actionfunc(context,n){
context.commit("func1",n)
}
},
}
export default hellovuex;
axios.js
const axios={
// ... 同上
}
export default axios;
store/index.js
store/index.js里面引入这两个模块js, 然后在modules里注册上两个模块。
导出store/index.js
// 模块化之后
import { createStore } from 'vuex'
//引入时注意 一定是这个带./的路径。相对路径,不然就是针对整个目录来说的
import hellovuex from "./modules/hellovuex.js"
import axios1 from "./modules/axios.js"
export default createStore({
modules: {
hellovuex:hellovuex,
axios1:axios1
}
})
组件中使用模块化后的值
在组件中使用模块化后的值的时候,要带上模块名。
<template>
原来是:
{{$store.state.count}}
模块化后:hellovuex是模块名
{{$store.state.hellovuex.count}}
template>
<script>
原来是:
console.log(this.$store.state.count)
模块化后:
console.log(this.$store.state.hellovuex.count)
调用模块化后的actions或者mulations的函数,则不需要改变
this.$store.dispatch("actionfunc",n)
script>
vuextest1.vue: 调用公共hellovuex.js里count值的组件
<template>
<div>
<h1>vuex 模块化的使用 helloworld 和vuex1公用h1>
<h4>1.state全 局变量count: {{$store.state.hellovuex.count}}h4>
<h4>2. actions带参改变count做法h4>
<button @click="clickfunc">点击我触发clickfunc改变countbutton>
div>
template>
<script>
export default {
name: 'vuextest1',
data() {
return {
arr:[],
}
},
created(){
console.log(this.$store.state.hellovuex.count)
},
methods:{
clickfunc(){
let n=2
// 调用函数是不用考虑模块化的,站在整个仓库的角度上调用,不用加模块名
this.$store.dispatch("actionfunc",n)
}
}
}
script>
此时会有一个问题:假如两个模块.js中有一个相同名字的actions方法,一个a.js,一个b.js, 比如他们的actions都叫“actionfunc”,所做的事情是不一样的,我在a模块下的vuextest1.vue中调用actionfunc,执行的时候会在全局找actionfunc名字,这两个都会执行。
只想执行a.js下的actions方法怎么办?此时就要用到命名空间,指定actions了。
mutation也同样适用。
命名空间用法:
//hellovuex.js
const hellovuex={
//命名空间
namespaced:true,
...
...
actions: {
actionfunc(context,n){
console.log("我是hellovuex的actions")
context.commit("func1",n)
}
},
}
export default hellovuex;
组件里调用的时候:
//vuextest1.vue
<script>
export default {
name: 'vuextest1',
data() {
return {
arr:[],
}
},
created(){
console.log(this.$store.state.hellovuex.count)
},
methods:{
clickfunc(){
let n=2
//调用的时候加上模块目录
this.$store.dispatch("hellovuex/actionfunc",n)
}
}
}
script>
效果:
基于store的派生状态,相当于组件中的计算属性computed,我们可以认为,getters是store的计算属性。当state中的值变化时,它自动更新。
getters用法:
假如我们要计算state中的price*count。
//hellovuex.js
//和state同级
getters:{
getterfunc(state){
return state.price*state.count
}
}
vuextest1.vue
<template>
<div>
<h4>3. getters的用法:h4>
<p>count*price=: {{$store.getters['hellovuex/getterfunc']}}p>
div>
template>
<script>
created(){
//原getters
console.log("--getters--"+this.$store.getters.getterfunc)
//getters命名空间 用法: this.$store.getters['模块名/属性名']
console.log("--getters--"+this.$store.getters['hellovuex/getterfunc'])
}
script>
效果: