1. 为什么要用 vuex ?
在vue
开发当中需要使用数据管理,数据管理的目的是什么呢? <=> React中使用是Redux
首先,需要清楚为什么要用 vuex ,当我们的应用遇到 多个组件共享状态 时
- 多层级父子组件状态传递会特别繁琐
- 非嵌套父子组件状态传递也会特别繁琐(如几个组件非嵌套关系,而是平级关系)
- 视图之间的数据传递也是非常繁琐
2. vuex 是什么?
Vuex
是一个专为 Vue.js
应用程序开发的 状态管理模式,类似 redux
它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex
也集成到Vue
的官方调试工具 devtools extension,提供了诸如零配置的time-travel
调试、状态快照导入导出等高级调试功能。
这种状态管理模式包含:
- State : 状态数据源
- View : 使用状态数据源的视图
- Actions : 修改更新数据源的操作
这种模式遵循的是 单向数据流 模式
2.1 单向数据流
以下是一个表示“单向数据流”理念的简单示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
对于问题一
,传参的方法对于多层嵌套
的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
对于问题二
,我们经常会采用父子组件
直接引用或者通过事件来变更和同步状态的多份拷贝。
以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式
管理呢?
在这种模式下,我们的组件树构成了一个巨大的“视图”
,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
通过定义和隔离状态管理中的各种概念并通过强制规则维持视图和状态间的独立性,我们的代码将会变得更结构化且易维护。
这就是 Vuex
背后的基本思想,借鉴了 Flux、Redux 和 The Elm Architecture。与其他模式不同的是,Vuex
是专门为 Vue.js
设计的状态管理库,以利用 Vue.js
的细粒度数据响应机制来进行高效的状态更新。
2.1.1 单向数据流小结
单向数据流 模式 <=> 与Redux
一致
数据存储在仓库当中,仓库中提供了数据的存储和数据的修改方式,那么这个时候(视图
)消费者去使用仓库中的数据。
State
是流向视图的(State => View
),View
需要修改数据的话,不能直接操作State
,而是通过提交Actions
或者Mutations
来操作State
,这就是整个循环的单向数据流。
实际这里单向数据流的概念与Redux
的一致,但Vuex
封装的更简单一些。
3. vuex 的工作流
- State : 存储应用状态数据(
Redux
中的State
) - Vue Component : 消费 State
- Actions : 提交修改 State 的动作(包括异步行为)(
Redux
中的action
) - Mutations : 唯一更改 State 的位置(
Redux
中的Reducer
)
4. 安装 vuex
npm i vuex
// or
yarn add vuex
5. 引入 vuex
通过 <script> 引入
<script src="vue.js"></script>
<script src="vuex.js"></script>
通过 <script> 方式引入,vuex 会自动安装(也就是主动调用 Vue.use(Vuex)
)
通过 import
引入
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
通过 import
方式引入,需要手动安装(手动调用 Vue.use(Vuex)
)
6. 从 Store 开始
每一个 Vuex
应用的核心就是 store
(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex
和单纯的全局对象有以下两点不同:
Vuex
的状态存储是响应式的。当Vue
组件从store
中读取状态的时候,若store
中的状态发生变化,那么相应的组件也会相应地得到高效更新。- 你不能直接改变
store
中的状态。改变store
中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。
Store
就是仓库,我们前面提到的 state
就存储在 store
中,同时提交动作、修改状态的方法也都由 store
提供和管理。
6.1 创建一个 Store
Vuex
之后,让我们来创建一个 store。
创建过程直截了当——仅需要提供一个初始 state
对象和一些 mutation
(其他参数可选)
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
let store = new Vuex.Store({
state: {
},
getters: {
},
mutations: {
},
actions: {
}
})
必须在
Vue.use(Vuex)
之后创建store
6.2 实例
6.2.1 初始化
我们暂时用小迪 Vue 0基础学习路线(27)案例代码
首先精简一下 => 初始化
\app\src\App.vue
<template>
<div id="app">
<h1>我的主页</h1>
<div id="nav">
<router-link to="/">Home</router-link>
<span> | </span>
<router-link to="/about">About</router-link>
<span> | </span>
<router-link to="/view">Detail</router-link>
</div>
<hr />
<!--满足当前url的路由组件将被显示在 router-view 的位置-->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
.router-link-exact-active {
color: red;
}
#nav {
padding: 10px 0;
position: fixed;
width: 100%;
left: 0;
top: 0;
background: rgba(0,255,0,.3);
}
</style>
\app\src\views\Home.vue
<template>
<div>
<h2>商品列表</h2>
<ul class="item-list">
<li class="head">
<span>名称</span>
<span>价格</span>
<span>操作</span>
</li>
<li v-for="item of items" :key="item.id">
<span>
<router-link :to="{name: 'view', params: {id: item.id}}">{
{item.name}}</router-link>
</span>
<span>{
{item.price|RMB}}</span>
<span>
<button>添加到购物车</button>
</span>
</li>
</ul>
</div>
</template>
<script>
import * as apis from '@/apis'
import {
RMB} from "@/filters/RMB";
export default {
name: "Home",
data() {
return {
sort: 'desc',
items: []
}
},
filters: {
RMB
}
}
</script>
<style>
ul {
margin: 0;
padding: 0;
}
li {
list-style: none;
}
.item-list li {
padding: 10px;
display: flex;
justify-content: space-between;
height: 30px;
line-height: 30px;
border-bottom: 1px dotted #333;
}
.item-list li.head {
font-weight: bold;
}
.item-list li span {
min-width: 200px;
}
</style>
\app\src\router\index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
const Home = () => import('@/views/Home');
// 执行 VueRouter 的 install
Vue.use(VueRouter);
// 创建一个具体的路由对象,该对象就是我们应用中需要使用到的路由相关配置
let router = new VueRouter({
mode: 'history', // hash \ history
// 存放了 url 与 组件的映射关系
routes: [
// 每一个对象就是一组url与组件的对应
{
path: '/',
name: 'home',
component: Home
}
]
});
export default router;
参考:https://github.com/6xiaoDi/blog-Vuex-Novice/tree/a0.01
Branch: branch01commit description:a0.01(初始化)
tag:a0.01
6.2.2 example01
6.2.2.1 example01-1
安装
yarn add vuex
新建一个store
仓库目录 =>index
引入Vue
和Vuex
,第一步将vuex
丢到use
中,它里面会提供一个类Store
。
它是通过配置参数来使用 =>
state
=> 存数据 => 我们准备一个item
数组,存到这里
暂时先把数据写死,存到全局变量 => 存入仓库
然后再把我们创建的仓库对象导出去
\app\src\store\index.js
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
let items = [{
"id":3,"name":"Macbook Pro 15.4","vendor":"Apple","price":1949900},{
"id":4,"name":"Apple iMac","vendor":"Apple","price":1629900},{
"id":9,"name":"游戏本2019款","vendor":"XiaoMi","price":879900},{
"id":6,"name":"Apple Watch Series 4","vendor":"Apple","price":599900},{
"id":1,"name":"iPhone XR","vendor":"Apple","price":