totalAge(state) {
return state.users.reduce((preValue, item) => {
return preValue + item
}, 0)
}
}
})
* **拿到结果进行展示**
{{ $store.getters.doubleCounter }}
{{ $store.getters.totalAge }}
**getters可以接收第二个参数getters**
>
> 例如返回一个name并且拼接上users的年龄总和
>
>
>
const store = createStore({
state: () => ({
name: “lin yj”,
counter: 100,
users: [
{id: 111, name: “chenyq”, age: 19},
{id: 112, name: “kaisa”, age: 20},
{id: 113, name: “vn”, age: 21}
]
}),
// getters对应一个对象
getters: {
// 1.将counter的两倍返回
doubleCounter(state) {
return state.counter * 2
},
// 2.将users中的年龄总和返回
totalAge(state) {
return state.users.reduce((preValue, item) => {
return preValue + item.age
}, 0)
},
// 3.name并且拼接上年龄总和
message(state, getters) {
// 由于年龄前面已经计算过一次了, 我们无需重新计算, 通过参数getters可以拿到
return ${state.name}: ${getters.totalAge}
}
}
})
* **拿到结果进行展示**
---
**getters的返回函数**
>
> getters中的函数本身,可以返回一个函数,那么在使用的地方相当于可以调用这个函数
>
>
> 例如上面代码中在getters中实现一个根据id返回用户信息的函数
>
>
>
const store = createStore({
// state函数要求返回一个对象
state: () => ({
name: “lin yj”,
counter: 100,
users: [
{id: 111, name: “chenyq”, age: 19},
{id: 112, name: “kaisa”, age: 20},
{id: 113, name: “vn”, age: 21}
]
}),
// getters对应一个对象
getters: {
getUserById(state) {
// 返回一个函数
return function(id) {
const user = state.users.find(item => item.id === id)
return user
}
}
}
})
* **在使用的地方可以调用getUserById函数**
{{ $store.getters.getUserById(111) }}
{{ $store.getters.getUserById(112) }}
{{ $store.getters.getUserById(113) }}
#### 🍧getter辅助函数
>
> 和state类似, getters也有一个辅助函数mapGetters
>
>
>
**Options API中使用辅助函数: 方便获取多个getters**
>
> 使用方法基本上和mapState相似, 大家看看就行, 不再过多介绍
>
>
>
{{ message }}
{{ totalAge }}
{{ meMessage }}
{{ usersAge }}
>
> **在setup中使用mapGetters就像使用mapState一样, 是非常繁琐的, 不推荐使用;**
>
>
> **使用的方法和mapState一样, 同样不再多说, 大家可以自行尝试**
>
>
>
**和state一样, setup中不推荐使用mapGetters**
>
> 使用computd单独获取每一个元素
>
>
>
{{ message }}
{{ totalAge }}
{{ getUserById(111) }}
### 核心概念Mutation
#### 🧁Mutation基本使用
**更改 Vuex 的 store 中的状态的唯一方法是提交 mutation**:
>
> 比如, 我们如果想要修改store中的state中的counter属性, 我们并不能直接通过`store.state.counter`修改
>
>
> 我们必须通过commit提交mutation, 在mutation中进行修改
>
>
>
const store = createStore({
state: () => ({
counter: 100,
}),
// commit提交到mutations
mutations: {
increment(state) {
state.counter++
},
decrement(state) {
state.counter–
}
}
})
当前计数: {{ counter }}
#### 🧁Mutation携带数据
**很多时候我们在提交mutation的时候,会携带一些数据,这个时候我们可以使用参数**:
>
> 例如修改state中的name属性时, 可以将修改的内容通过传递参数传出
>
>
>
const store = createStore({
state: () => ({
name: “lin yj”,
}),
// commit提交到mutations
mutations: {
// payload接收传入的参数
changeName(state, payload) {
state.name = payload
}
}
})
{{ $store.state.name }}
{{ $store.state.age }}
{{ $store.state.height }}
>
> **payload也可以传入为对象类型**
>
>
>
const store = createStore({
state: () => ({
name: “lin yj”,
age: 18,
height: 1.88,name: “lin yj”,
}),
// commit提交到mutations
mutations: {
// payload接收对象类型
changeInfo(state, payload) {
state.name = payload.name
state.age = payload.age
state.height = payload.height
}
}
})
{{ $store.state.name }}
{{ $store.state.age }}
{{ $store.state.height }}
#### 🧁Mutation常量类型
**我们发现, commit提交和mutation中的名称是需要保持一致的, 由于这个名称又不会更改, 所在开发中, 我们通常会给这些名称定义一个常量, 并将它放到独立的js文件中去**
* **定义常量:mutation\_type.js**
export const CHANGE_INFO = “CHANGE_INFO”
* **使用常量定义mutation**
// 导入常量
import { CHANGE_INFO } from “./mutation_types”;
const store = createStore({
state: () => ({
name: “lin yj”,
age: 18,
height: 1.88,name: “lin yj”,
}),
mutations: {
// 使用常量定义mutation
[CHANGE_INFO](state, payload) {
state.name = payload.name
state.age = payload.age
state.height = payload.height
}
}
})
**使用常量提交mutation**
// 导入常量
import { CHANGE_INFO } from “./store/mutation_types”
function changeInfo() {
// 参数传入一个对象
store.commit([CHANGE_INFO], {
name: “王老五”,
age: 20,
height: 1.58
})
}
---
#### 🧁Mutation辅助函数
**我们也可以借助于辅助函数,帮助我们快速映射到对应的方法中**:
* **Options API中的使用**
当前计数: {{ counter }}
{{ $store.state.name }}
{{ $store.state.age }}
{{ $store.state.height }}
* **Setup中同样不推荐使用mapMutation**
---
#### 🧁mutation重要原则
**Mutation有一条重要的原则就是: mutation中必须是同步函数**
>
> 这是因为devtool工具会记录mutation的日记;
>
>
> 每一条mutation被记录,devtools都需要捕捉到前一状态和后一状态的快照;
>
>
> 但是在mutation中执行异步操作,就无法追踪到数据的变化;
>
>
>
**所以Vuex的重要原则中要求 mutation必须是同步函数;**
**但是如果我们希望在Vuex中发送网络请求的话需要如何操作呢?**
>
> 有事时候我们确实想要在Vuex中发送网络请求, 比如发送网络请求得到的数据是一些状态, 我们没必要在组件中发送网络请求再放到store中, 我们可以直接在store中发送网络请求
>
>
> 那么遇到这种情况, 就是我们接下来要学习的Actions核心, Actions是专门处理异步操作的地方, 我们的异步代码都需要在Actions中处理
>
>
>
---
### 核心概念Actions
#### 🍸Actions基本使用
**Action类似于Mutation,不同在于**:
>
> Action提交的是Mutation,而不是直接变更状态;也就是说, Action中想要修改state的话, 也需要提交Mutation, 不允许直接修改
>
>
> Action可以包含任意异步操作, Mutation中只能进行同步操作;
>
>
>
mutations: {
increment(state) {
state.counter++
}
},
actions: {
incrementAction(context) {
// action中修改state需要提交mutation
context.commit(“increment”)
}
}
**我们发现这里有一个非常重要的参数context**:
>
> context是一个和store实例均有相同方法和属性的context对象;
>
>
> 所以我们可以从其中获取到commit方法来提交一个mutation,或者通过 `context.state` 和 `context.getters` 来获取 state 和 getters;
>
>
>
actions: {
incrementAction(context) {
// 提交mutation
context.commit(“increment”)
// 获取state中的状态
context.state.name
// 获取getter中的数据
context.getters.doubleCounter
}
}
**相信大家很疑惑为什么它不是store对象呢?这个在下面讲核心概念Modules时再具体来说**
#### 🍸Actions分发操作
**Options中Action的分发**
**如何使用action呢?进行action的分发**:
>
> 分发使用的是 store 上的`dispatch函数`;
>
>
>
{{ counter }}
**同样的,它也可以携带我们的参数, 例如修改我们刚刚的Info**
* 定义Action
actions: {
// 接收参数payload提交到mutation
changeNameAction(context, payload) {
context.commit(“changeName”, payload)
}
}
* 携带参数分发
{{ name }}
**也可以以对象的形式进行分发**:
* 定义Action
actions: {
// 接收参数payload提交到mutation
changeInfoAction(context, payload) {
context.commit(CHANGE_INFO, payload)
}
}
* 分发时传递对象作为参数
{{ name }}
{{ age }}
{{ height }}
**setup函数中Action分发**
#### 🍸Actions辅助函数
**action也有对应的辅助函数**:
>
> 对象类型的写法;
>
>
> 数组类型的写法;
>
>
>
* **数组类型的写法**
{{ counter }}
* 对象类型的写法
{{ counter }}
**Setup中同样不推荐使用mapAction**
---
#### 🍸Actions异步操作
**Action 通常是异步的,那么如何知道 action 什么时候结束呢?**
>
> 我们可以通过让action返回Promise,在Promise的then中来处理完成后的操作;
>
>
>
**演示代码**:
* **将网络请求的数据请求到vuex中**
const store = createStore({
state: () => ({
// 1.用于存放网络请求的数据
banners: [],
recommends: []
}),
mutations: {
// 2.定义mutation用于修改state的banners和recommends
changeBanners(state, payload) {
state.banners = payload
},
changeRecommends(state, payload) {
state.recommends = payload
}
},
actions: {
// 3.定义发生网络请求的Action
fetchHomeMulitidataAction(context) {
// 发生网络请求
fetch(“http://123.207.32.32:8000/home/multidata”).then(res => {
return res.json()
}).then(data => {
// 修改state中banner的数据, 提交mutation
context.commit(“changeBanners”, data.data.banner.list)
// 修改state中recommends的数据, 提交mutation
context.commit(“changeRecommends”, data.data.recommend.list)
})
}
}
})
* **请求到数据后可以获取vuex中的数据进行展示**
- {{ item.title }}
### 核心概念Module
#### 🥃module基本使用
**什么是Module?**
>
> 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,store 对象就有可能变得相当臃
> 肿, 例如刚刚我们发送了一个网络请求存放Home的数据, 如果还有很多个组件需要在vuex中发送网络请求, 这个时候store对象就会越来越臃肿;
>
>
> 为了解决以上问题,Vuex 允许我们将 store `分割成模块`(module);
>
>
> 每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块;
>
>
>
**演示代码**
* **将刚刚home组件请求的数据单独抽离到一个home.js文件中, js文件返回一个对象**
export default {
state: () => ({
// 网络请求的数据
banners: [],
recommends: []
}),
mutations: {
// 定义mutation用于修改state的状态
changeBanners(state, payload) {
state.banners = payload
},
changeRecommends(state, payload) {
state.recommends = payload
}
},
actions: {
fetchHomeMulitidataAction(context) {
fetch(“http://123.207.32.32:8000/home/multidata”).then(res => {
return res.json()
}).then(data => {
// 修改state中banner的数据, 提交mutation
context.commit(“changeBanners”, data.data.banner.list)
// 修改state中recommends的数据, 提交mutation
context.commit(“changeRecommends”, data.data.recommend.list)
})
}
}
}
* **再将抽离出去的模块导入store对象**
// 1.导入抽离出去的模块
import HomeModule from “…/module/home”
const store = createStore({
state: () => ({}),
getters: {},
mutations: {},
actions: {},
modules: {
//模块名: 模块对象
home: HomeModule
}
})
* **展示state状态时, 要从模块中获取; 而getter、mutation、action不需要, 因为他们默认会被合并到根模块中去, 一般情况下都可以直接获取**
- {{item.title}}
**对于模块内部的 mutation 和 getter,接收参数的state或getters是模块的局部状态对象**
* **还可以接收第三个参数rootState, 通过rootSate可以拿到根模块中的状态对象**
---
#### 🥃module命名空间
**默认情况下,模块内部的getter、action和mutation仍然是注册在`全局的命名空间`中的**:
>
> 这样使得多个模块能够对同一个 action 或 mutation 作出响应, 这并不是我们想要的结果, 导致在模块中我们取名需要非常小心避免重复;
>
>
> Getter 同样也默认注册在全局命名空间;
>
>
>
**如果我们希望模块具有更高的封装度和复用性, 解决这个尴尬的问题**
**web浏览器中的javascript**
* 客户端javascript
* 在html里嵌入javascript
* javascript程序的执行
* 兼容性和互用性
* 可访问性
* 安全性
* 客户端框架
* **[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**
![](https://img-blog.csdnimg.cn/img_convert/ed2c4f9602fb053965a21c047d1291e6.png)
**window对象**
* 计时器
* 浏览器定位和导航
* 浏览历史
* 浏览器和屏幕信息
* 对话框
* 错误处理
* 作为window对象属性的文档元素
![](https://img-blog.csdnimg.cn/img_convert/81adbbfdefca6b401d7dc4e6acd9207d.png)