原文地址:应用Vue+DataV+Echarts打造新冠肺炎疫情数据大屏(可动静刷新)
源码
查看:https://blog.lanweihong.com/posts/29267/
效果图
演示
仅适配 1080P 屏幕,应用浏览器拜访后按 F11 进入全屏可看最佳显示成果。
- 疫情实在数据演示地址:演示地址-实在数据
- 模仿数据演示地址:演示地址-模仿数据
前端框架和类库
- Vue.js
- Apache ECharts
- DataV
- axios
- Element
- Mock
代码实现
创立我的项目
应用 Vue Cli 创立 Vue 我的项目,没有 Vue Cli 的应用以下命令装置:
npm install -g @vue/cli
创立我的项目:
vue create datav-covid-19
装置依赖
# 装置 DataVnpm install @jiaminghi/data-view# 装置 echartsnpm install echarts -S# 装置 element-uinpm i element-ui -S# 装置 vue-routernpm install vue-router# 装置 mockjsnpm install mockjs --save-dev# 装置 axiosnpm install axios# 装置 echarts-liquidfillnpm i echarts-liquidfill
引入注册
在我的项目中引入,编辑 main.js
:
import Vue from 'vue'import App from './App.vue'import dataV from '@jiaminghi/data-view'import * as echarts from 'echarts'import 'element-ui/lib/theme-chalk/index.css';import axios from 'axios'// 引入 echarts 水球图import 'echarts-liquidfill'import VueRouter from 'vue-router'import { Icon, Row, Col, Table, TableColumn, Button, Dialog, Link} from 'element-ui';// 注册 echartsVue.prototype.$echarts = echartsVue.config.productionTip = false// 注册 axiosVue.prototype.axios = axios// 注册 dataVVue.use(dataV)// 注册路由Vue.use(VueRouter)// 按需注册其余 element-ui 组件Vue.use(Icon)Vue.use(Row)Vue.use(Col)Vue.use(Table)Vue.use(TableColumn)Vue.use(Button)Vue.use(Dialog)Vue.use(Link)new Vue({ render: h => h(App),}).$mount('#app')
编写组件
因为篇幅无限,为了浏览体验,这里以 累计排名 组件为例,其余的组件请看 Github 上的代码。
累计排名组件
效果图
累计排名组件采纳 ECharts 的柱状图来显示,实现代码如下:
<template> <div ref="provinceRankingBarChart" style="width: 100%; height: 100%" /></template><script>import * as echarts from 'echarts'let chart = nullexport default { props: { data: { type: Object, default () { return { provinceList: [], valueList: [] } } } }, methods: { initChart () { if (null != chart && undefined != chart) { chart.dispose() } chart = this.$echarts.init(this.$refs.provinceRankingBarChart) this.setOptions() }, setOptions() { var salvProValue = this.data.valueList; var salvProMax = []; for (let i = 0; i < salvProValue.length; i++) { salvProMax.push(salvProValue[0]) } let option = { grid: { left: '2%', right: '2%', bottom: '2%', top: '2%', containLabel: true }, tooltip: { trigger: 'axis', axisPointer: { type: 'none' }, formatter: function (params) { return params[0].name + ' : ' + params[0].value } }, xAxis: { show: false, type: 'value' }, yAxis: [{ type: 'category', inverse: true, axisLabel: { show: true, textStyle: { color: '#fff' }, }, splitLine: { show: false }, axisTick: { show: false }, axisLine: { show: false }, data: this.data.provinceList }, { type: 'category', inverse: true, axisTick: 'none', axisLine: 'none', show: true, axisLabel: { textStyle: { color: '#ffffff', fontSize: '12' }, }, data: salvProValue }], series: [{ name: '值', type: 'bar', zlevel: 1, itemStyle: { normal: { barBorderRadius: 30, color: new echarts.graphic.LinearGradient(0, 0, 1, 0, [{ offset: 0, color: 'rgb(2,163,254,1)' }, { offset: 1, color: 'rgb(125,64,255,1)' }]), }, }, barWidth: 20, data: salvProValue }, { name: '背景', type: 'bar', barWidth: 20, barGap: '-100%', data: salvProMax, itemStyle: { normal: { color: 'rgba(24,31,68,1)', barBorderRadius: 30, } }, }, ] } chart.setOption(option) } }, watch: { data: { handler(newList, oldList) { if (oldList != newList) { this.setOptions() } }, deep: true } }}</script>
在页面中引入应用:
<template> <div class="demo"> <province-ranking-bar-chart ref="rankChart" :data="dataList" style="width: 100%; height: 380px" /> </div></template><script>// 引入组件import ProvinceRankingBarChart from '../components/ProvinceRankingBarChart'export default { components: { ProvinceRankingBarChart }, data () { return { // 定义数据 dataList: { provinceList: ['湖北', '台湾'], valueList: [68188, 15379] } } }, mounted() { // 创立图表并初始化 this.$refs.rankChart.initChart() }}</script><style>.demo { width: 500px; height: 600px;}</style>
其余组件的代码就不在这里写了,残缺代码已上传 Github ,须要的能够去查看。
残缺的组件构造如下:
筹备模仿数据
我的项目中提供了两种数据提供形式,一是申请实在后盾地址,返回的数据格式参考 data
目录下的 json 文件;二是在本地应用 Mock 生成模仿数据。这里仅介绍应用 Mock 生成模仿数据形式。
应用 Mock 生成模仿数据
在我的项目根目录下创立文件夹 mock
,别离创立 covid19.js
和 index.js
;
编写 mock 服务
covid19.js
代码如下,代码中应用到一些 Mock 的语法,具体应用办法请查看 Mock 的文档。
// 从本地读取 json 数据const provinceData = require('../data/covid19-province.json')const dailyData = require('../data/covid19-daily-list.json')// 引入 mockjsconst Mock = require('mockjs')// 应用 mockjs 的 Random 生成随机数据const Random = Mock.Randommodule.exports = [ { url: '/api/covid-19/overall', type: 'get', response: config => { return { success: true, code: 200, message: "操作胜利", data: { confirmedCount: Random.integer(110000, 120000), confirmedIncr: 72, curedCount: Random.integer(100000, 110000), curedIncr: 173, currentConfirmedCount: Random.integer(3000, 4000), currentConfirmedIncr: -110, deadCount: Random.integer(4000, 6000), deadIncr: 12, importedCount: Random.integer(6000, 8000), importedIncr: 23, noInFectCount: Random.integer(400, 600), noInFectIncr: 8, suspectIncr: 0, suspectCount: 2, updateTime: "2021-07-15 20:39:11", curedRate: Random.float(90, 95, 0, 9), deadRate: Random.float(1, 5, 0, 9) } } } }, { url: '/api/covid-19/area/latest/list', type: 'get', response: config => { return provinceData } }, { url: '/api/covid-19/list', type: 'get', response: config => { return dailyData } }]
注册 mock 服务
编辑 index.js
,这里次要是注册 mock 服务,调用办法 initMockData()
实现注册;
const Mock = require('mockjs')// 引入写好的 mock 服务const covid19 = require('./covid19')const mocks = [ ...covid19]function param2Obj(url) { const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') if (!search) { return {} } const obj = {} const searchArr = search.split('&') searchArr.forEach(v => { const index = v.indexOf('=') if (index !== -1) { const name = v.substring(0, index) const val = v.substring(index + 1, v.length) obj[name] = val } }) return obj}const initMockData = () => { Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send Mock.XHR.prototype.send = function() { if (this.custom.xhr) { this.custom.xhr.withCredentials = this.withCredentials || false if (this.responseType) { this.custom.xhr.responseType = this.responseType } } this.proxy_send(...arguments) } function XHR2ExpressReqWrap(respond) { return function(options) { let result = null if (respond instanceof Function) { const { body, type, url } = options result = respond({ method: type, body: JSON.parse(body), query: param2Obj(url) }) } else { result = respond } return Mock.mock(result) } } for (const i of mocks) { Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) }}module.exports = { mocks, initMockData}
应用 mock 服务
在 main.js
中引入:
const { initMockData } = require('../mock')// 实现注册initMockData()
而后在页面中应用 request.get('/api/covid-19/list')
就能申请获取到数据,这里的 request.get()
是我用 axios
封装写的办法。
封装数据接口
封装 axios
我的项目中的数据申请都是应用 axios
为方便使用,我简略封装了一个工具类 request.js
:
import axios from "axios"import sysConst from '../libs/const'const fetch = (method = 'GET', url, param = '') => { // 解决 url url = `${sysConst.baseUrl}${url}` return new Promise((resolve, reject) => { axios({ method: method, url: url, changeOrigin: true, data: JSON.stringify(param) }).then((res) => { resolve(res.data) }, error => { reject(error) }).catch((error) => { reject(error) }) })}const get = (url) => { return fetch('GET', url)}const post = (url, data) => { return fetch('POST', url, data)}const put = (url, data) => { return fetch('PUT', url, data)}const remove = (url, data) => { return fetch('DELETE', url, data)}export { get, post, put, remove}
这里引入的 const.js
代码如下:
let baseUrl = ''if (process.env.NODE_ENV === 'development') { // 批改你的 API 地址 baseUrl = ''} else { // 你的 API 地址 baseUrl = ''}export default { baseUrl}
封装数据接口
在我的项目根目录下新建文件夹 api
,用于保留编写数据接口,在该目录下新增文件 covid19.js
,用于封装申请获取数据:
import * as request from '@/utils/request'/** * 接口封装 */export default { getOverall() { let url = `/api/covid-19/overall?_=${Math.random()}` return request.get(url) }, getProvinceDataList() { let url = `/api/covid-19/area/latest/list?_=${Math.random()}` return request.get(url) }, getDailyList() { let url = `/api/covid-19/list?t=${Math.random()}` return request.get(url) }}
调用数据接口获取数据并更新图表展现
// 引入import covid19Service from '../api/covid19'// 应用let self = thiscovid19Service.getOverall().then((res) => { if (!res.success) { console.log('谬误:' + res.info) return } // 批改数据,图表组件检测到数据变动会触发 setOptions() 办法更新显示( setOptions() 在图表组件中已定义好) self.basicData = res.data})
我的项目构造
残缺的我的项目构造如下:
├─build├─data # 本地模仿数据目录├─mock # mock 配置├─public└─src ├─api # 接口封装目录 ├─assets ├─components # 组件目录 │ ├─About # 对于 │ ├─BasicDataItemLabel # 根本数据显示标签 │ ├─BasicProportionChart # 占比图表 │ ├─BasicTrendChart # 趋势图表 │ ├─ChartCard # 图表面板 │ ├─CuredAndDeadRateChart # 治愈率和死亡率图表 │ ├─CurrentConfirmedCompareBarChart # 最近一周累计治愈图表 │ ├─DataMap # 数据地图 │ └─ProvinceRankingBarChart # 累计排名图表 ├─libs # 一些罕用的配置 ├─router # 路由配置 ├─utils # 工具类 └─views # 视图
具体构造:
总结
- 采纳组件化封装各个展现图表,能更好的图表展现及复用;
- 应用
axios
申请后盾服务或本地 mock 服务获取数据,而后从新赋值图表中指定的数据;
我的项目源码:本我的项目源码已上传至 Github,在我的博客中可查看到地址:应用Vue+DataV+Echarts打造新冠肺炎疫情数据大屏(可动静刷新)
这个我的项目是集体学习作品,能力无限,难免会有 BUG 和谬误,敬请体谅。如有更好的倡议或想法,请指出,谢谢