Vuex 是什么?
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。Vuex 也集成到 Vue 的官方调试工具 devtools extension,提供了诸如零配置的 time-travel 调试、状态快照导入导出等高级调试功能
这个状态自管理应用包含以下几个部分:
- state,驱动应用的数据源;
- view,以声明方式将 state 映射到视图;
- actions,响应在 view 上的用户输入导致的状态变化。
以下是一个表示“单向数据流”理念的极简示意:
但是,当我们的应用遇到多个组件共享状态时,单向数据流的简洁性很容易被破坏:
- 多个视图依赖于同一状态。
- 来自不同视图的行为需要变更同一状态。
对于问题一,传参的方法对于多层嵌套的组件将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。对于问题二,我们经常会采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。以上的这些模式非常脆弱,通常会导致无法维护的代码。
因此,我们为什么不把组件的共享状态抽取出来,以一个全局单例模式管理呢?在这种模式下,我们的组件树构成了一个巨大的“视图”,不管在树的哪个位置,任何组件都能获取状态或者触发行为!
另外,通过定义和隔离状态管理中的各种概念并强制遵守一定的规则,我们的代码将会变得更结构化且易维护。
这就是 Vuex 背后的基本思想,借鉴了 Flux、Redux 和 The Elm Architecture。与其他模式不同的是,Vuex 是专门为 Vue.js 设计的状态管理库,以利用 Vue.js 的细粒度数据响应机制来进行高效的状态更新。
如果你想要以交互式的方式学习Vuex,快来看看在Scrimba上的这门Vuex课程。
#什么情况下我应该使用 Vuex?
虽然 Vuex 可以帮助我们管理共享状态,但也附带了更多的概念和框架。这需要对短期和长期效益进行权衡。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的。确实是如此——如果您的应用够简单,您最好不要使用 Vuex。一个简单的 store 模式就足够您所需了。但是,如果您需要构建一个中大型单页应用,您很可能会考虑如何更好地在组件外部管理状态,Vuex 将会成为自然而然的选择。引用 Redux 的作者 Dan Abramov 的话说就是:
Flux 架构就像眼镜:您自会知道什么时候需要它。
下面来一则实例
上文我们已经学习了如何通过vue从内部传递资料和从外部传递资料
下面我们使用vuex
还是在我们的项目工程下 安装
npm install vuex --save
新建目录和文件
H:\vue\vue_webback\src\store\index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
status:'线上',
username:'Caps',
}
const getters = {}
const actions = {}
const mutations = {}
export default new Vuex.Store({
state,
getters,
actions,
mutations
})
H:\vue\vue_webback\src\components\ListVuex.vue
<template>
<div class="hello container mt-5">
<div>
状态:{{showStatus}}
</div>
<div class="form-inline mb-3">
<input type="text" class="form-contarol" v-model="username">
<button class="btn btn-primary" @click="updateUsername">更新姓名</button>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
<th>Username</th>
</tr>
</thead>
<tbody>
<tr v-for="(item,i) in listData" :class="{'bg-info':item.selected}">
<th scope="row">{{i+1}}</th>
<td><img :src="item.picture.medium" alt=""></td>
<td>{{item.name.first}} {{item.name.last}}</td>
<td>{{item.email}}</td>
<td>
<button class="btn btn-outline-primary" @click="clickMe(item)">点我</button>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
// props: ['status'],
data() {
return {
msg: 'Welcome to Your Vue.js App',
listData: [],
username: 'Cap',
vuexStatus:this.$store.state.status
}
},
methods: {
getData() {
let vm = this;
// Make a request for a user with a given ID
vm.axios.get('https://randomuser.me/api/?results=50')
.then(function (response) {
vm.listData = response.data.results;
// console.log(vm.listData);
vm.listData.forEach(function (item) {
vm.$set(item, 'selected', false);
})
})
.catch(function (error) {
// console.log(error);
});
},
updateUsername() {
this.$store.state.username=this.username;
},
clickMe(item) {
console.log(item)
item.selected = !item.selected
console.log(item.selected)
}
},
mounted() {
this.getData()
},
computed:{
showStatus(){
return this.$store.state.status;
}
}
}
</script>
H:\vue\vue_webback\src\App.vue
<template>
<div id="app">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<!--<a class="nav-link" href="#">Hello 1</a>-->
<router-link class="nav-link" :to="'/'">Hello 1</router-link>
</li>
<li class="nav-item">
<!-- 不写 v-bind 也可以,就像绑定别的属性一样 -->
<router-link class="nav-link" :to="'hello2'">Hello 2</router-link>
</li>
<li class="nav-item">
<router-link class="nav-link" :to="'pages'">List</router-link>
</li> <li class="nav-item">
<router-link class="nav-link" :to="'pagesVuex'">ListVuex</router-link>
</li>
</ul>
<div class="form-inline mr-3">
<select name="" id="" class="form-control" @change="changeStatus" v-model="status">
<option value="线上">线上</option>
<option value="线下">线下</option>
</select>
</div>
<div class="navbar-text">
Hi,{{username}}|{{showUsername}}
</div>
</div>
</nav>
<router-view :status="myStatus" @pushNewName="getNewName"></router-view>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
status: "线上",
myStatus: "线上",
username:'',
vuexStatus:this.$store.state.status
}
},
methods: {
changeStatus() {
this.myStatus = this.status;
},
getNewName(newName) {
let vm = this
vm.username = newName;
}
},
computed:{
showUsername(){
return this.$store.state.username
}
}
}
</script>
<style lang="scss">
@import "~bootstrap/scss/bootstrap.scss";
</style>