1.1-vuex介绍
回顾组件关系和通信方案
序号 | 组件关系 | 数据通信 |
---|---|---|
1 | 父子关系 | 子传父:$emit ; 父传子:props |
2 | 非父子关系 | eventBus: $on + $emit |
3 | 非父子关系 | vuex |
和我们已经学过的父子通信和兄弟通信类似,vuex也是一种组件通信解决方案
1.1.1-组件传值的几种方式
1.1.2-为什么要有vuex
-
1.vuex的作用是解决多组件状态共享的问题,在大型的项目中,组件通讯会变得很混乱,使用vuex可以统一管理组件之间的通讯
-
它是
独立于组件
而单独存在的,所有的组件都可以把它当作一座桥梁来进行通讯。
-
-
2.使用vuex好处
-
响应式
: 只要vuex中的数据变化,对应的组件会自动更新(类似于vue数据驱动) -
操作更简洁 : 类似于sessionStorage,只有几个方法
-
1.1.3-vuex使用场景
实际开发中,组件传值大多数情况下还是使用 父子组件传值
少部分情况下会用vuex. (数据需要在非常多的页面使用,比如用户头像,好几个页面都要显示那种)
-
1.不是所有的场景都适用于vuex,只有在必要的时候才使用vuex,如果
不必要,尽量别用
-
使用了vuex之后,会一定程度上增加了项目的复杂度
-
-
2.适合使用vuex场景
-
这个数据需要在
很多个地方使用
,如果采用组件传值方式,写起来很麻烦,而且多个地方都要写-
例如:用户信息(姓名,头像),可能会在很多个地方使用(个人页面,评论页面等)
-
-
-
3.不适合使用vuex场景
-
这个数据
不需要多个地方使用
,如果某个数据仅仅只是在两个组件之间通讯
,优先使用props或$emit
-
-
4.vuex特点
-
(1)所有组件数据共享
-
(2)响应式: 一旦vuex数据修改,所有使用的地方都会自动更新
-
-
1.vuex作用
-
所有组件,共享数据
-
-
2.vuex场景 : (思考:是不是有了vuex,以前的父子组件传值就没有用呢?)
-
vuex会增加项目复杂程度,如果不需要使用,尽量不要用
-
vuex使用场景 : (1)多个组件都需要使用的数据:
共享
(2)组件传值比较麻烦(不是父子关系) -
vuex不推荐场景 : (1)数据不需要在多个组件使用:
不共享
(2)组件传值比较容易(父子传值)
-
1.2-vuex使用流程
使用步骤:
-
vue-cli
中整合==(如果使用vue ui创建创建,直接勾选vuex,会自动帮我们完成配置)==-
vue add vuex
-
如果提示,选择
y
-
创建了
/src/store/index.js
-
main.js
导入并挂载到Vue
实例上
-
-
state
中定义数据
-
-
任意组件中
-
this.$store.state.xxx
即可取值
和改值
-
template
中可以不用写this
-
可以通过计算属性简化编码
-
-
.js
文件中-
导入
store
对象即可获取属性
-
注意:
-
在
vue-cli
创建的项目中如何整合vuex
-
vue add vuex
-
-
vuex
的数据定义在哪里?-
state
-
-
组件中如何获取
vuex
中的数据?-
this.$store.state.xxx
-
html结构中
this
可以省略
-
1.3-vuex核心概念-state
state作用: 存储公共数据
1.4-getters派生状态(计算属性)
.使用getter中的计算属性
$store.getters.getter的名字
1.5-vuex核心概念- Mutations
1.Mutation作用:更新state中的数据
-
疑问?: 既然可以直接通过
this.$store.state
来修改,为什么不能这么写呢? -
原因: 在组件中直接state,我们的
vue tools
不会追踪数据的修改,这样不便于维护(不知道这个全局数据什么时候被修改了,再加上vuex是全局响应式的,一旦修改所有使用的地方全部修改。非常不便于维护)-
另外:在严格模式下,直接修改state会报错
-
2.Mutation语法如下:
-
分两个格式: 注册的格式,调用的格式
-
定义格式: 如下
new Vue.store({
// 省略其他...
mutations:{
// 每一项都是一个函数,可以声明两个形参
mutation名1:function(state [, 载荷]) {
},
mutation名2:function(state [, 载荷]) {
},
}
})
每一项都是一个函数,可以声明两个形参:
-
第一个参数是必须的,表示当前的state。在使用时不需要传入
-
第二个参数是可选的,表示载荷,是可选的。在使用时要传入的数据
-
专业术语载荷:表示额外的参数
-
使用格式
this.$store.commit('mutation名', 载荷实参 )
这个事件名就是Mutation中的函数名。(类似于$emit的一种事件通知机制)
Vuex-mutaions拓展理解
问:为啥是$store.commit('mutations的名字')
而不是$store.mutations的名字()?
答:Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数。
问:数据不可以该在组件内部直接修改吗?
答:不能。虽然语法上不报错,也有响应式的特点。但是不推荐。特别是在严格模式下会报错。若将vue创建 store 的时候传入 strict: true, 开启严格模式,那么任何修改state的操作,只要不经过 mutation的函数,vue就会报错
问:可以传递多个数据吗?
答:参数只能有一个:下面的写法是不对的:
this.$store.commit('setUser', name, age) // age这个参数将无法被接收到
如果希望传递复杂的数据,第二个参数可以是对象,例如下面的写法
this.$store.commit('setUser', { name, age} )
问:等价写法 this.$store.comit({type: 'mutations的名字'})
1.6-vuex辅助函数-mapState
-
官网文档:vuex辅助函数-mapState
-
1.mapState作用: 将vuex中的数据
映射
到组件的计算属性
中-
我们在组件中访问vuex数据,需要通过
this.$store.state.属性名
,单词太常,写起来很麻烦。 -
通过mapState函数,可以在组件中直接通过
this.属性名
来访问vuex中的数据
-
2.mapState语法
-
2.1 在要使用的组件中导入mapState辅助函数:
import { mapState } from 'vuex'
-
2.2 在这个组件的computeds中来映射计算属性
...mapState( ['属性名a' , '属性名b'] )
-
这行代码相当于自动帮你生成一个对应的计算属性
属性名(){ return this.$store.state.属性名 }
1.7-vuex核心概念:actions
1.1.1-actions介绍
-
1.actions与mutations相同点 :都是修改state数据
-
2.actions与mutations不同点
-
mutations:同步更新
-
actions: 异步更新(例如你的数据来源于ajax)
-
为什么要有actions, 假如你有一个数据,需要通过ajax请求来获取。然后你想存入vuex,应该怎么做?
方案一:
1.在组件的created钩子中发送ajax请求
2.服务器响应数据之后,调用$store.commit()提交给mutations更新(手动挡)
方案二:
1.直接在actions中发送ajax请求
2.actions会自动帮你把数据提交到mutations更新(自动挡)
你会选择手动更新?还是自动更新呢?
一定要记住
:只有你的ajax数据需要存入vuex,才需要在actions中发送ajax请求。 如果不想存入vuex,还是在组件的created钩子中发送。(vuex说:你又不用我,你想干啥与我何干?)
1.8-vuex核心概念modules
-
modules作用:模块化处理vuex数据
为什么要有vuex? 假设你的项目非常的复杂,分为四个大模块:首页、个人中心、订单列表、设置中心
每一个模块有10个数据需要使用vuex,那么你的vuex的state中就需要声明40个属性。(是不是非常麻烦呢?)
当vuex中需要存储的数据很多的时候,就需要使用moudles进行模块化处理
一般实际开发中moudles使用不多哈。 只有那种特别复杂,庞大的项目才可能用到
使用modules语法如下
export default new Vuex.Store({
// state: 用来保存所有的公共数据
state: {},
getters: {},
mutations: {},
actions: {},
modules: {
模块名1: {
// namespaced为true,则在使用mutations时,就必须要加上模块名
namespaced: true,
state: {},
getters: {},
mutations: {},
actions: {},
modules: {}
},
模块名2: {
// namespaced不写,默认为false,则在使用mutations时,不需要加模块名
state: {},
getters: {},
mutations: {},
actions: {},
modules: {}
}
}
})
访问数据和修改数据的调整
-
访问模块中的数据,要加上模块名
获取数据项: {{$store.state.模块名.数据项名}} 获取getters: {{$store.getters['模块名/getters名']}}
-
访问模块中的mutations/actions:
-
如果namespaced为true,则需要额外去补充模块名
-
如果namespaced为false,则不需要额外补充模块名
$store.commit('mutations名') // namespaced为false $store.commit('模块名/mutations名') // namespaced为true
-
Vuex-map函数用法汇总
如何使用全局state
-
直接使用: this.$store.state.xxx;
-
map辅助函数:
computed: { ...mapState(['xxx']), ...mapState({'新名字': 'xxx'}) }
如何使用modules中的state
-
直接使用: this.$store.state.模块名.xxx;
-
map辅助函数:
computed: { ...mapState('模块名', ['xxx']), ...mapState('模块名', {'新名字': 'xxx'}) }
如何使用全局getters
-
直接使用:
this.$store.getters.xxx
-
map辅助函数:
computed: { ...mapGetters(['xxx']), ...mapGetters({'新名字': 'xxx'}) }
如何使用modules中的getters
-
直接使用:
this.$store.getters.模块名.xxx
-
map辅助函数:
computed: { ...mapGetters('模块名', ['xxx']), ...mapGetters('模块名',{'新名字': 'xxx'}) }
如何使用全局mutations
-
直接使用:
this.$store.commit('mutation名', 参数)
-
map辅助函数:
methods: { ...mapMutations(['mutation名']), ...mapMutations({'新名字': 'mutation名'}) }
如何使用modules中的mutations(namespaced:true)
-
直接使用:
this.$store.commit('模块名/mutation名', 参数)
-
map辅助函数:
methods: { ...mapMutations('模块名', ['xxx']), ...mapMutations('模块名',{'新名字': 'xxx'}) }
如何使用全局actions
-
直接使用:
this.$store.dispatch('action名', 参数)
-
map辅助函数:
methods: { ...mapActions(['actions名']), ...mapActions({'新名字': 'actions名'}) }
如何使用modules中的actions(namespaced:true)
-
直接使用:
this.$store.dispatch('模块名/action名', 参数)
-
map辅助函数:
methods: { ...mapActions('模块名', ['xxx']), ...mapActions('模块名',{'新名字': 'xxx'}) }