您的位置:首页 > 产品设计 > UI/UE

[Vue.js启航]——使用Vuex进行状态管理

2017-08-04 23:05 1071 查看

Vue.js启航——英雄编辑器(五)

简介

这一篇博客将是这一系列博客的最终篇,主要探讨的是Vuex插件的使用。先介绍一下Vuex。Vuex是Vue框架的状态管理插件,采用集中式存储管理应用的所有组件的状态。状态通俗来讲就是组件中的数据,状态的管理也就是各个组件中数据的管理。当你的应用足够简单的话,我们可以使用中央事件总线的方式来实现简单的管理,具体可以参考 [Vue.js启航]——多组件应用构建 ,当我们要构建中大型的单页应用的时候我们才会考虑使用Vuex来集中管理组件的状态。这篇文章我们会继续 [Vue.js启航]——多组件应用构建,去掉中央事件总线,采用Vuex进行改造。

使用Vuex的多组件英雄编辑器

使用Vuex的多组件英雄编辑器和使用时间总线的多组件英雄编辑器实现出来的效果是一样的



最主要的改造就是将
bus
换成Vuex.Store实例,将
hero
Vue实例中的
computed
选项作一些调整。

Vuex.Store实例

跟中央时间总线一样,使用Vuex管理状态也需要一个额外的组件实例,在中央时间总线中是一个Vue实例,而在Vuex中则是Vuex.Store实例。最简单的Vuex.Store应该包括
state
mutations
选项,其中
state
选项存储的是需要管理的状态,而
mutations
则是控制状态转变的一些方法,例如在官方指南中,
mutations
中有一个改变
state
count
的方法

var store=new Vuex.Store({
state:..
mutations:{
increment (state){
state.count++;
}
}
})


当我们的组件需要使用
mutations
的方法更改
state
的状态时只需要调用

store.commit('increment')


使用载荷传递参数

在我们的例子中需要将选中的英雄作为参数传递给
mutations
中的方法。在这里就直接拿我们的代码举例子了,使用载荷的
mutations
的写法是这样的

//...
mutations:{
selectHero(state,selectedHero){
state.hero=selectedHero
}
}


在英雄列表中的调用方式是

store.commit('selectHero',this.selectedHero)


但这并不是官方推荐的写法,官方的规范中要求,载荷应该是一个对象,这样可以包含多个字段并且记录的
mutation
更加易读,我们继续使用载荷对象进行改造

//...
mutations:{
selectHero(state,payload){
state.hero=payload.selectedHero;
}
}


然后在英雄列表中的调用方式是

store.commit({
type:'selectHero',
selectedHero:this.selectedHero
})


组件或者实例获取状态

当我们把Vuex.Stroe实例编写好之后,已经把状态和改变状态的方法都集中起来进行管理了,那接下来我们就要获取状态的值了。获取状态值的一般方法是
return store.state.xxx
xxx为状态值,例如我们在这里需要获取
hero
的状态值就写
return sotre.state.hero
,在这个例子中,我们只需要在
hero
实例中的
computed
选项中返回状态值就好

//..
computed:{
hero:function(){
return store.state.hero;
}
}


到这里我们就完成了从中央事件总线到Vuex的转变。

模块化的Sotre

其实一些有经验的人到这里可能就会问,我们把所有的组件的状态都交由一个Store管理,那么,当我们要管理的状态很多,那Store不就会膨胀了吗?其实Vuex的设计者早就想到了这一点,所以Vuex允许使用模块化管理Store。每一个模块其实就是拥有
state
mutations
,
actions
,
getters
中的一个或多个选项的JS对象,这里我们只使用了
state
mutations
。构建模块化Store的代码如下:

var moduleA={
state:{...},
mutations:{...},
...
}

var moduleB={
state:{...},
mutations:{...},
...
}


然后在Store实例中将各个模块组装起来

var store=new Vuex.Store({
modules:{
a:moduleA,
b:moduleB
}
})


获取状态的话使用

store.state.a.state.xxxx


总结

这篇文章主要是介绍了Vuex的简单使用,配合Vue-Router,和Vue本身组成了Vue的核心部分。Vuex当然不止文章中用到的
state
mutations
还有包含异步操作的
actions
以及用于筛选数据或者格式化输出的
getters
。模块化系统还有命名空间等内容。在这里接触到关于Vuex的内容其实差不多,就不多详述了。

这一系列的文章也就结束了,接下来会新开一系列的文章,主要关于模块化构建系统构建Vue应用,使用单文件组件,和Vue-Router、Vuex的进阶使用和Vue的核心概念等。

可运行代码

hero.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="hero.css">
</head>
<body>

<div id="hero">
<hero-list v-bind:heroes="heroes"
v-bind:title="title"></hero-list>
<hero-detail v-bind:hero="hero"></hero-detail>
</div>

</body>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vuex@2.3.1"></script>
<script src="hero.js"></script>
</html>


hero.js
//十位英雄数据
const HEROES=[
{ id: 11, name: 'Mr. Nice' },
{ id: 12, name: 'Narco' },
{ id: 13, name: 'Bombasto' },
{ id: 14, name: 'Celeritas' },
{ id: 15, name: 'Magneta' },
{ id: 16, name: 'RubberMan' },
{ id: 17, name: 'Dynama' },
{ id: 18, name: 'Dr IQ' },
{ id: 19, name: 'Magma' },
{ id: 20, name: 'Tornado' }
];

//Vuex.Store实例
var store=new Vuex.Store({
state:{
hero:""
},
mutations:{
selectHero(state,payload){
state.hero=payload.selectedHero;
}
}
})

//多个组件

//英雄详情组件
Vue.component("hero-detail",{
props:["hero"],
template:'\
<div v-if="hero">\
<h2>{{hero.name}}</h2>\
<div><label>id:</label>{{hero.id}}</div>\
<div>\
<label>name:</label>\
<input v-model="hero.name" placeholder="name"/>\
</div>\
</div>\
',
})

//英雄列表组件
Vue.component("hero-list",{
props:["title","heroes"],
template:'\
<div>\
<h1>{{title}}</h1>\
<h2>My Heroes</h2>\
<ul class="heroes">\
<li v-for="hero in heroes"\
v-on:click="onSelect(hero)"\
v-bind:class="{selected:hero===selectedHero}">\
<span class="badge">{{hero.id}}</span>{{hero.name}}\
</li>\
</ul>\
</div> \
',
methods:{
onSelect:function(hero){
this.selectedHero=hero
//bus.$emit("selectHero",this.selectedHero);
store.commit({ type:'selectHero', selectedHero:this.selectedHero })}
},
data:function(){
return {selectedHero:""};
}
})

var hero=new Vue({
el:"#hero",
data:{
heroes:HEROES,
title:"Tour of Heroes",
},
computed:{
hero:function(){
return store.state.hero;
}
},
})


hero.css

h1 {
color: #369;
font-family: Arial, Helvetica, sans-serif;
font-size: 250%;
}
h2, h3 {
color: #444;
font-family: Arial, Helvetica, sans-serif;
font-weight: lighter;
}
.selected {
background-color: #CFD8DC !important;
color: white;
}
body {
margin: 2em;
}
body, input[text] {
color: #888;
font-family: Cambria, Georgia;
}
.heroes {
margin: 0 0 2em 0;
list-style-type: none;
padding: 0;
width: 15em;
}
.heroes li {
cursor: pointer;
position: relative;
left: 0;
background-color: #EEE;
margin: .5em;
padding: .3em 0;
height: 1.6em;
border-radius: 4px;
}
.heroes li.selected:hover {
background-color: #BBD8DC !important;
color: white;
}
.heroes li:hover {
color: #607D8B;
background-color: #DDD;
left: .1em;
}
.heroes .text {
position: relative;
top: -3px;
}
.heroes .badge {
display: inline-block;
font-size: small;
color: white;
padding: 0.8em 0.7em 0 0.7em;
background-color: #607D8B;
line-height: 1em;
position: relative;
left: -1px;
top: -4px;
height: 1.8em;
margin-right: .8em;
border-radius: 4px 0 0 4px;
}
[class*='col-'] {
float: left;
padding-right: 20px;
padding-bottom: 20px;
}
[class*='col-']:last-of-type {
padding-right: 0;
}
a {
text-decoration: none;
}
h3 {
text-align: center; margin-bottom: 0;
}
h4 {
position: relative;
}
.grid {
margin: 0;
}
.col-1-4 {
width: 23%;
}
.module {
padding: 20px;
text-align: center;
color: #eee;
max-height: 120px;
min-width: 120px;
background-color: #607D8B;
border-radius: 2px;
}
.module:hover {
background-color: #EEE;
cursor: pointer;
color: #607d8b;
}
.grid-pad {
padding: 10px 0;
}
.grid-pad > [class*='col-']:last-of-type {
padding-right: 20px;
}
@media (max-width: 600px) {
.module {
font-size: 10px;
max-height: 75px; }
}
@media (max-width: 1024px) {
.grid {
margin: 0;
}
.module {
min-width: 60px;
}
}
nav a {
padding: 5px 10px;
text-decoration: none;
margin-top: 10px;
display: inline-block;
background-color: #eee;
border-radius: 4px;
}
nav a:visited, a:link {
color: #607D8B;
}
nav a:hover {
color: #039be5;
background-color: #CFD8DC;
}
nav a.router-link-active {
color: #039be5;
}
button {
margin-top: 20px;
font-family: Arial;
background-color: #eee;
color: #888888;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer; cursor: hand;
}
button:hover {
background-color: #cfd8dc;
}
button:disabled {
background-color: #eee;
color: #ccc;
cursor: auto;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息