[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实例,将
heroVue实例中的
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.xxxxxx为状态值,例如我们在这里需要获取
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; }
相关文章推荐
- 在Vue中使用Vuex进行状态管理指南
- Vue之Vuex管理状态的使用
- Vuex内容解析和vue cli项目中使用状态管理模式Vuex
- vue 2 使用Bus.js进行兄弟(非父子)组件通信 简单案例
- Vue.js数据状态管理-Vuex(二)
- 21、vue.js 之vuex安装及使用
- Vue 状态管理 Vuex
- vue 2 使用Bus.js进行兄弟(非父子)组件通信 简单案例
- vue.js学习10之动手使用vue-cli搭建项目及生成的代码进行修改练手
- vue的状态管理模式vuex
- 理解Vue的状态管理模式Vuex
- 一次性比较目前前端最流行的状态管理,mobx,vuex,redux-saga使用方式用方式
- Vue 2.X的状态管理vuex记录详解
- [置顶] React 项目中使用 MobX 进行状态管理
- 详解使用vuex进行菜单管理
- [2014-12-29]使用Enum位模式进行多重状态(或权限)管理
- vue状态管理vue-vux使用
- 详解Vue中状态管理Vuex
- [Vue.js启航]——Vue-Router的使用
- vue 2 使用Bus.js进行兄弟(非父子)组件通信 简单案例