既然已经掌握了 Highcharts-Vue 的基本使用技巧,那今明两天打算带大家来实作一个「记帐本」,用一个比较完整的应用来完结这个系列,也算是一个学习成果的回顾。
如下图所示,第一天打算先把我们记帐本的介面、图表及资料串接完成,画面大致如上,上方为新增帐目的表单元件,下方则是显示每日消费金额的柱状图,样式的话大家可以自由发挥,文章中将只会说明程序逻辑的部分。
为了可以让记帐本真的可以记帐,我们会需要资料库来纪录帐目,而我选择使用的是 Json-Server,它让我们可以用一个 Json 档来作为简易的资料库,而且内建基本的 REST API 可以使用,这样我们就不用真的架一个後端服务器了,在终端机输入下方指令就可以全域安装了。
npm install -g json-server
安装完成後新增一个 db.json
,然後可以先手动新增一笔帐目,档案内容如下:
{
"accounts": [
{
"id": 1,
"category": "伙食",
"amount": "50",
"date": 1602028800000,
"description": "早餐"
}
]
}
档案备妥後,在终端机输入以下指令就可以启动 json-server
,这时候到 http://localhost:3000/accounts
,就可以看到刚刚建立的资料了,未来只要是开启服务器的状态就可以使用 API 来读写 db.json
的资料了。
json-server db.json
资料库有了之後,接下来在专案资料夹底下输入终端机指令来安装 axios
,它可以让我们更便捷的处理 XMLHttpRequest。
npm install axios
安装好後到 main.js
添加以下程序码来引用它,这样我们就可以在元件里使用 this.axios.get()
来呼叫 API 了。
import Vue from "vue";
import axios from "axios";
Vue.prototype.axios = axios;
由於这次的应用会使用到日期座标,所以我们可以来调整一下「语言设定」,设定方法是在 main.js
引入原生 Highcharts,然後一样是呼叫 setOptions()
。
import Vue from "vue";
import Highcharts from "highcharts";
Highcharts.setOptions({
lang: {
shortMonths: ["1月", "2月", ..., "12月"],
weekdays: ["星期日", "星期一", ..., "星期六"],
},
// 也可增加其他你像要的全域设定
credits: { enabled: false },
colors: [...]
});
前置作业完成後就可以来开发元件了,首先是上方用来新增帐目的表单元件。新增一个档案内容如下的元件,其中四个表单栏位刚好对应资料库的内容,而点击按钮触发的 addItem
就是用 axios
送出 post
请求,便会在资料库添加一笔新的帐目。
对了,为了把重点放在图表的应用上,有许多部分是被我省略的:
<template>
<form>
<fieldset>
<legend>新增帐目</legend>
<div class="input-group">
<label>日期</label>
<input type="date" v-model="date">
<label>分类</label>
<select v-model="category">
<option value="伙食">伙食</option>
<option value="交通">交通</option>
<option value="生活">生活</option>
<option value="帐单">帐单</option>
<option value="娱乐">娱乐</option>
</select>
<label>金额</label>
<input type="number" v-model.number="amount">
</div>
<div class="input-group">
<label>说明</label>
<input type="text" v-model="description">
</div>
<button @click="addItem">+</button>
</fieldset>
</form>
</template>
<script>
export default {
data() {
return {
date: "",
category: "伙食",
amount: 0,
description: ""
}
},
methods: {
addItem() {
this.axios.post("http://localhost:3000/accounts", {
date: new Date(this.date).getTime(),
category: this.category,
amount: this.amount,
description: this.description
})
}
}
}
</script>
可以纪录帐目後,就要让消费记录透过图表呈现出来了,而需求规格有以下几点:
避免模糊焦点,这次图表只做到近七天的资料显示,有兴趣的话你也可以根据自己你想法改善这个范例。
根据需求,我们先准备好需要的资料,包括储存今日时间戳的 todayTimeStamp
,储存 API 资料的 fetchData
,以及图表设定 chartOptions
。
data() {
return {
todayTimeStamp: 0,
fetchData: [],
chartOptions: {
chart: { type: "column" },
title: { text: "每日消费" },
tooltip: {
shared: true,
headerFormat: "{point.key:%Y/%m/%d %A}<br/>",
valuePrefix: "NT$"
},
xAxis: {
type: "datetime",
categories: [],
labels: { format: "{value:%b%d}日" },
},
yAxis: {
title: undefined,
labels: { format: "NT$ {value}" },
},
plotOptions: {
series: { stacking: "normal" }
},
series: [],
}
};
}
而API资料我们需要再 created
时先去取得,顺便把今天的时间戳储存起来,方便我们之後计算近七天的时间。
created() {
// 取得当日的时间戳
let now = new Date().getTime();
this.todayTimeStamp = now - now % 86400000;
// call json-server api
this.axios.get("http://localhost:3000/accounts").then((response) => {
this.fetchData = response.data;
});
},
有了这些资料後,就可以透过 computed
来将资料处理成我们所需的格式了。
computed: {
// 利用当日时间戳来计算X轴所需的 categories 阵列
xAxisCategories() {
return Array(7).fill(0).map((date ,index) => {
return this.todayTimeStamp - 86400000 * index
}).reverse()
},
// 抓出所有不重复的支出类别
expendType() {
let allType = this.fetchData.map(item => item.category);
return Array.from(new Set(allType));
},
// 把 API 资料 map 成我们需要的格式
seriesData() {
return this.expendType.map(cate => {
let itemByCate = this.fetchData.filter(item => item.category === cate);
let points = this.xAxisCategories.map(date => {
return itemByCate.reduce((acc, item) => {
return item.date === date ? acc + Number(item.amount) : acc
}, 0)
})
return { name: cate, data: points };
});
},
// 将图表设定和处理完的资料合并
options() {
let options = Object.assign(this.chartOptions, {});
options.series = this.seriesData;
options.xAxis.categories = this.xAxisCategories;
return options;
}
}
最後把 options
传入图表,并且记得把今天新增的两个元件挂载到 App.vue
上,就可以看到消费纪录呈现在图表上罗。
<template>
<div class="chart-container">
<div v-if="!fetchData.length" class="noData">无任何消费记录</div>
<highcharts v-else :options="options"></highcharts>
</div>
</template>
辛苦各位了,今天的篇幅比较长,不过跟着今天一步步的流程下来,终於完成了一个比较完整的 Highcharts-Vue 应用,而明天我们将利用「事件属性」来为这个应用再添加一个小功能。
课程目标 了解软件架构师所应具备的技能与素养,分析与规划软件架构模型,撰写符合国际标准的SAD (S...
何谓渗透测试 以骇客的角度,针对企业的网路、系统、网站进行检测弱点与漏洞,并撰写一份渗透测试报告提...
今天大概会聊到的范围 Animation Modifier.graphicsLayer 上一篇讲到...
大纲 C 语言中的 if x86-64 中的 condition code MSP430 的 sta...