原文地址:应用Vue+DataV+Echarts打造新冠肺炎疫情数据大屏(可动静刷新)

源码

查看:https://blog.lanweihong.com/posts/29267/

效果图

演示

仅适配 1080P 屏幕,应用浏览器拜访后按 F11 进入全屏可看最佳显示成果。

  1. 疫情实在数据演示地址:演示地址-实在数据
  2. 模仿数据演示地址:演示地址-模仿数据

前端框架和类库

  • 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.jsindex.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                              # 视图

具体构造:

总结

  1. 采纳组件化封装各个展现图表,能更好的图表展现及复用;
  2. 应用 axios 申请后盾服务或本地 mock 服务获取数据,而后从新赋值图表中指定的数据;

我的项目源码:本我的项目源码已上传至 Github,在我的博客中可查看到地址:应用Vue+DataV+Echarts打造新冠肺炎疫情数据大屏(可动静刷新)

这个我的项目是集体学习作品,能力无限,难免会有 BUG 和谬误,敬请体谅。如有更好的倡议或想法,请指出,谢谢