关于vue.js:使用VueDataVECharts打造新冠肺炎疫情数据大屏可动态刷新

96次阅读

共计 7871 个字符,预计需要花费 20 分钟才能阅读完成。

原文地址:应用 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

装置依赖

# 装置 DataV
npm install @jiaminghi/data-view

# 装置 echarts
npm install echarts -S

# 装置 element-ui
npm i element-ui -S

# 装置 vue-router
npm install vue-router

# 装置 mockjs
npm install mockjs --save-dev

# 装置 axios
npm install axios

# 装置 echarts-liquidfill
npm 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';

// 注册 echarts
Vue.prototype.$echarts = echarts
Vue.config.productionTip = false

// 注册 axios
Vue.prototype.axios = axios

// 注册 dataV
Vue.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 = null
export 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')
// 引入 mockjs
const Mock = require('mockjs')
// 应用 mockjs 的 Random 生成随机数据
const Random = Mock.Random

module.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 = this
covid19Service.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 和谬误,敬请体谅。如有更好的倡议或想法,请指出,谢谢

正文完
 0