上一章我们介绍statistics模块的entry.js,其中定义了路由以及对应的view页面,在view中可以依照Vue.js模块定义的data/created/computed等去书写逻辑。
本章我们介绍以下内容:
- 如何使用components来加载模块
- 如何使用echarts来展示数据,以及如何调用echarts等插件
- 如何引入vuex来管理状态
一,vuex
Vuex 是一个专门为 Vue.js 应用所设计的集中式状态管理架构。它借鉴了 Flux 和 Redux 的设计思想,但简化了概念,并且采用了一种为能更好发挥 Vue.js 数据响应机制而专门设计的实现。在构建大型应用时,不同组件,模块以及数据的管理会变得很复杂,参考介绍:
我们在单独使用 Vue.js 的时候,通常会把状态储存在组件的内部。也就是说,每一个组件都拥有当前应用状态的一部分,整个应用的状态是分散在各个角落的。然而我们经常会需要把状态的一部分共享给多个组件。一个常见的解决策略为:使用定制的事件系统,让一个组件把一些状态“发送”到其他组件中。这种模式的问题在于,大型组件树中的事件流会很快变得非常繁杂,并且调试时很难去找出究竟哪错了。
这里我们直接步入正题,这里我们安装vuex以及vue-resource(通过api获取数据):
$ cnpm install vuex vue-reource --save
在statistics目录下创建文件夹_store,并创建三个文件:
- store.js
- getters.js
- actions.js
故名思议,getters是从store中获取数据的方法,所以内容很简单:
// getters.js
// 这个 getter 函数会返回 count 的值
// 在 ES6 里你可以写成:
// export const getCount = state => state.count
// export function getCount (state) {
// return state.count
// }
export const getPostsPage = state => state.posts.page
export const getPostsList = state => state.posts.list
export const getPostsItem = state => state.posts.post
export const getChartList = state => state.chart.list
export const getChartName = state => state.chart.name
export const getChartData = state => state.chart.data
当然了,actions也就一样是很简单了:
// actions.js
// action 会收到 store 作为它的第一个参数
// 既然我们只对事件的分发(dispatch 对象)感兴趣。(state 也可以作为可选项放入)
// 我们可以利用 ES6 的解构(destructuring)功能来简化对参数的导入
// export const incrementCounter = function ({ dispatch, state }) {
// dispatch('INCREMENT', 1)
// }
export const nextPage = ({dispatch}) => {
dispatch('POSTS_NEXT', 1)
}
export const prevPage = ({dispatch}) => {
dispatch('POSTS_PREV', 1)
}
相对复杂一点是store,简介如下:
// store.js
import Vue from 'vue'
import Vuex from 'vuex'
import VueResource from 'vue-resource'
import Api from './_api'
import ChartList from './_chartList'
import ChartData from './_chartData'
import ChartSerializer from './_chartSerializer'
// 告诉 vue “使用” vuex
Vue.use(Vuex)
Vue.use(VueResource)
// 创建一个对象来保存应用启动时的初始状态
// 注意,chart必须有,不然会一开始显示的表类型不正常
// 这里我们定义的其实就是一个posts来显示文章以及charts来存储echarts数据
const state = {
posts: {
page: 1,
list: [
{ 'id': 1, 'title': 'cjb', 'content': 'first' },
{ 'id': 2, 'title': 'sb', 'content': 'second' },
{ 'id': 3, 'title': 'sb pm', 'content': 'third' }
],
post: {},
data: null
},
chart: {
list: ChartList,
name: 'pie',
data: {
tooltip: {},
xAxis: {
},
yAxis: {},
series: []
}
}
}
// 定义一个方法通过接口处理数据并更新到store
const apiQuery = (path, query) => {
Vue.http.get(Api[path].url, { params: query }).then((res) => {
// success callback
state.chart.data = ChartSerializer[Api[path].serialize](JSON.parse(res.body))
}, (res) => {
// error callback
console.log(res)
})
}
// 创建一个对象存储一系列我们接下来要写的 mutation 函数
// 这里其实是对应到actions中的各种方法
const mutations = {
POSTS_NEXT (state, offset) {
state.posts.page = state.posts.page + offset
},
POSTS_PREV (state, offset) {
state.posts.page = state.posts.page - offset
},
CHART_UPDATE (state, cname, query) {
state.chart.name = cname
if (cname === 'nano_active' || cname === 'nano_active_map') {
apiQuery(cname, query)
} else {
state.chart.data = ChartData[cname]
}
}
}
export default new Vuex.Store({
state,
mutations
})
其实简单的说,store模块,其实相当于这样:
store = {}
export default {
// getters
getPost: (id, ops) => {
// code
return store.posts[id]
}
// action
addPost: (id, ops) => {
// code
// ajax or something else
store.posts.push(...)
}
}
当然了,其核心是一种状态管理的思路以及实现方法,像上面这种简单粗暴的方法就尽量别用了~
二,使用echarts展示数据
@import "../_less/v2/base";
@import "../_less/component/animation";
.pikaday {
overflow: auto;
padding: 1em;
.mui-textfield {
margin-left: 16px;
}
}
这样呢,数据就可以显示出来了,对了,注意这里的nano和data来自于vuex:
对了,细心的童鞋们肯定发现了这里使用的chart模块,其实内容是这样:
@import '../../_less/v2/base';
@import '../../_less/component/animation';
.echart {
padding: 1em 0;
width: 100%;
height: 100%;
min-height: 700px;
}
如上,就可以将数据传入chart的prop中,并且,数据更新的时候,chart自动更新,当然,又有关联了,v-echarts其实是一个directives,我们是注册在entry.js中的:
// entry.js
import echarts from '../_directives/echarts'
Vue.directive('echarts', echarts)
那么问题来了,echart如何使用,我们继续来看Vue.js中自定义指令的方法是酱紫:
export default {
deep: true,
params: [],
paramWatchers: {
},
bind: function () {
},
update: function (val, oldVal) {
},
unbind: function () {
}
}
所以呀,其实是这样加载:
import echarts from 'echarts'
// 在bind方法中
// this.el其实就是对应的element了,至于其他的事件之类的,这里不多说
// 所以最简单的echarts引入方法是这样:
this.instance = echarts.init(this.el)
完整的简单用法是酱紫:
import Vue from 'vue'
import echarts from 'echarts'
import chinaJson from './echarts/china.json'
echarts.registerMap('china', chinaJson)
export default {
deep: true,
params: [],
paramWatchers: {
},
bind: function () {
var _this = this
Vue.nextTick(function () {
// init echarts instance
// console.error('bind')
_this.instance = echarts.init(_this.el)
})
},
update: function (val, oldVal) {
var _this = this
var options = val
Vue.nextTick(function () {
// console.error('update')
// 这里我加了dispose,否则多个chart时,数据会在原数据基本上更新
_this.instance.dispose()
_this.instance = echarts.init(_this.el)
_this.instance.setOption(options)
})
},
unbind: function () {
var _this = this
// console.error('unbind')
_this.instance.dispose()
}
}
哈哈哈,好像components被略过了,其实很简单,就是在components对象中加入一个Chart,像这个样子就可以了:
export default {
name: 'ChartView',
components: {
Chart
}
}
好了,这一张就是这样了,vue-resource的用法很简单,看看代码就懂了,直接上效果图:
参考: