一、项目描述 (包含echarts中国地图、dataV科技炫酷边框等等)
-
一个基于 Vue、Datav、Echart 框架的 " 数据大屏项目 ",通过 Vue 组件实现数据动态刷新渲染,内部图表可实现自由替换。部分图表使用 DataV 自带组件, 组件库基于Vue (React版) ,主要用于构建大屏(全屏)数据展示页面即数据可视化,具有多种类型组件可供使用。
-
项目环境:Vue-cli、DataV、Echarts、node
友情链接:
项目展示
二、主要文件介绍
文件
作用/功能
main.js
主目录文件,引入 Echart/DataV 等文件
utils
工具函数与 mixins 函数等
components/ HomeWord.vue
项目主结构
assets
静态资源目录,放置 logo 与背景图片
三、项目注意点
引用的模块(先下载 install)
main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import * as echarts from 'echarts' //echarts 引用使用断言,否则可能报错
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import dataV from '@jiaminghi/data-view'
Vue.use(ElementUI); //部分图标使用 element-ui
Vue.use(dataV) //全局启用 dataV
Vue.prototype.$echarts=echarts //将echarts挂载到Vue原型上,全局可使用this.$echarts 调用
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
封装组件渲染图表
所有的 ECharts 图表已经对数据和屏幕改动进行了监听,能够动态渲染图表数据。在监听窗口小大的模块。
中间部分中国地图json数据来源 (地址)
我这边直接复制内容存到本地 (把复制的链接在网页打开Ctrl+A Ctrl+C 全选复制粘贴): assets > json > china.json
渲染地图的子组件
有几个注意点:
-
需要地图json文件
-
需要监听数据变化
-
tooltip: formatter 鼠标移入的提示信息框
复用图表组件(可以研究下)
更换边框 (炫酷的科技感动态边框)
边框是使用了 DataV 自带的组件,只需要去 views 目录下去寻找对应的位置去查找并替换就可以,具体的种类请去 DavaV 官网查看
如:
<dv-border-box-1> 内容撑开 </dv-border-box-1>
<dv-border-box-2> 内容撑开 </dv-border-box-2>
<dv-border-box-3> 内容撑开 </dv-border-box-3>
Mixins 解决自适应适配功能
使用 mixins 注入解决了界面大小变动图表自适应适配的功能,函数在 utils/resizeMixins.js
中,应用在 common/echart/index.vue
的封装渲染组件,主要是对 this.chart
进行了功能注入。
屏幕适配
使用更流程通用的 css3:scale
缩放方案,通过 ref
指向 主页面的元素,基准尺寸是 1980px*1080px
,所以支持同比例屏幕 100% 填充,如果非同比例则会自动计算比例居中填充,不足的部分则留白。实现代码在 `src/utils/drawMixin ,如果有其它的适配方案,欢迎交流。
src > utils > drawMixin.js
// 屏幕适配 mixin 函数
//需要先设置index.html meta 标签 user-scalable=no
//<meta name="viewport" content="width=device-width,initial-scale=1.0 ,user-scalable=no">
//并且需要绑定ref
// * 默认缩放值
const scale = {
width: '1',
height: '1',
}
// * 设计稿尺寸(px)
// 1920×1080
const baseWidth =1920
const baseHeight = 1080
// * 需保持的比例(默认1.77778)
const baseProportion = parseFloat((baseWidth / baseHeight).toFixed(5))
export default {
data() {
return {
// * 定时函数
drawTiming: null
}
},
mounted () {
this.calcRate()
window.addEventListener('resize', this.resize)
},
beforeDestroy () {
window.removeEventListener('resize', this.resize)
},
methods: {
calcRate () {
const appRef = this.$refs["appRef"]
if (!appRef) return
// 当前宽高比
const currentRate = parseFloat((window.innerWidth / window.innerHeight).toFixed(5))
if (appRef) {
if (currentRate > baseProportion) {
// 表示更宽
scale.width = ((window.innerHeight * baseProportion) / baseWidth).toFixed(5)
scale.height = (window.innerHeight / baseHeight).toFixed(5)
appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
} else {
// 表示更高
scale.height = ((window.innerWidth / baseProportion) / baseHeight).toFixed(5)
scale.width = (window.innerWidth / baseWidth).toFixed(5)
appRef.style.transform = `scale(${scale.width}, ${scale.height}) translate(-50%, -50%)`
}
}
},
resize () {
clearTimeout(this.drawTiming)
this.drawTiming = setTimeout(() => {
this.calcRate()
}, 200)
}
},
}
homeword.vue
<template>
<div id="index" ref="appRef">
...页面内容...
</div>
</template>
<script>
import drawMixin from "../utils/drawMixin";
export default {
components: {
//.....
},
mixins: [drawMixin], //混入 (保持页面缩放比例)
}
</script>
请求数据
使用 axios
进行数据请求,在 main.js
位置进行全局配置。
src > request
文件统一处理所有的请求
src > request > request.js
请求和响应拦截
// 封装axios实例的拦截器(请求, 响应)
import axios from 'axios';
// 1. 创建axios实例
const instance = axios.create({
timeout: 15000, // 超时时间15s
baseURL: '这里是你请求是ip地址', // ip+端口, 公用的前缀路径
});
// 重写实例请求前拦截器
instance.interceptors.request.use((config) => {
return config;
}, (err) => {
return Promise.reject(err);
})
// 重写实例响应后拦截器
instance.interceptors.response.use((result) => {
return result.data;
}, (err) => {
return Promise.reject(err);
})
// 导出axios实例
export default instance;
src > request > request.js
请求拼接地址
import request from './request';
// 主要指标 /mcpbd-data/data/mainIndex
export const getMainIndex= () => request.get('/mainIndex') //这里是get请求,"/mainIndex" 是接口文档的请求拼接字段
//......
在homeword.vue
引入,并发送请求数据
由于一个页面要发送多个请求,并且成功获取数据再渲染,我使用了promise.all
并发请求,但是发现请求很慢(不知道有什么方法可以优化)
<template>
...
</template>
<script>
import drawMixin from "../utils/drawMixin";
//接口
import {
getMainIndex,
} from "../request/httpApi";
export default {
components: {
//...
},
mixins: [drawMixin],
name: "HelloWorld",
props: {},
data() {
return {
//渲染子组件,还未请求到数据的时候,需要放数据的所有元素不显示
falg: false,
loading: true,
loadTimer: null,
resd: [],
realVal: 0,
MainIndicators: {
// 主要指标 默认数据
userAllCnt: "",
userNewCnt: "",
userDailyActvCnt: "",
userDailyActvRatio: "",
userMonthlyActvCnt: "",
userMonthlyActvRatio: "",
mctAllCnt: "",
},
//累计注册用户数折线
//....
mapData: {
//地图数据
mapArr: [],
},
};
},
mounted() {
this.cancelLoading();
},
filters: {
//过滤数据
numFilter(val) {
return (parseFloat(val) * 100).toFixed(1);
},
},
created() {
this.getJ();
this.getShishi();
// 实时更新数据(隔一个小时请求数据)
setInterval(() => {
this.getJ();
}, 3600000);
//左下角数据实时更新(1分钟)
setInterval(() => {
this.getShishi();
}, 60000);
},
methods: {
getShishi() {
//左下角数据 (因为这部分数据需要每分钟更新一次所以单独拎出来)
getRealTimeIndex() //发送请求
.then((res) => {
this.RealTimeIndex.newUserAllUserCnt = [];
this.RealTimeIndex.newUserAllUserDate = [];
this.resd = res;
this.resd.forEach((item) => {
this.RealTimeIndex.newUserAllUserCnt.push(
Number(item.userAllCnt).toFixed()
),
this.RealTimeIndex.newUserAllUserDate.push(
item.calTime.substring(11)
);
});
})
.catch((err) => {
return;
});
},
sortData(attr) {
return function (a, b) {
return b[attr] - a[attr];
};
},
getJ() {
// 累计注册用户
let p1 = new Promise((resolve, reject) => {
getUserAllCnt()
.then((res) => {
resolve(res);
})
.catch((err) => {
reject(err);
});
});
// 用户
let p2 = new Promise((resolve, reject) => {
//....
});
// 累计用户数
let p3 = new Promise((resolve, reject) => {
//....
});
// 日活用户数
let p4 = new Promise((resolve, reject) => {
//....
});
// 新增用户数
let p5 = new Promise((resolve, reject) => {
//....
});
// 指标排行表
let p6 = new Promise((resolve, reject) => {
//....
});
// 主要指标
let p7 = new Promise((resolve, reject) => {
getMainIndex()
.then((res) => {
setTimeout(() => {
resolve(res);
}, 700);
})
.catch((err) => {
reject(err);
});
});
// 地图数据省份
let p8 = new Promise((resolve, reject) => {
//....
});
Promise.all([p1, p2, p3, p4, p5, p6, p7, p8])
.then((res) => {
// 累计注册用户
//数据处理。。。
// 日活
//数据处理。。。
// 累计用户数 (只展示前5条数据)
//数据处理。。。
// 日活用户数
//数据处理。。。
// 新增用户数
//数据处理。。。
// 指标排行表
//数据处理。。。
// 主要指标
let mainIndex = res[6];
this.MainIndicators.userAllCnt = Number(
mainIndex.userAllCnt
).toLocaleString("en-US"); //使用千分符
this.MainIndicators.userNewCnt = Number(
mainIndex.userNewCnt
).toLocaleString("en-US");
this.MainIndicators.userDailyActvCnt = Number(
mainIndex.userDailyActvCnt
).toLocaleString("en-US");
this.MainIndicators.userDailyActvRatio = mainIndex.userDailyActvRatio;
this.MainIndicators.userMonthlyActvCnt = Number(
mainIndex.userMonthlyActvCnt
).toLocaleString("en-US");
this.MainIndicators.userMonthlyActvRatio =
mainIndex.userMonthlyActvRatio;
this.MainIndicators.mctAllCnt = Number(
mainIndex.mctAllCnt
).toLocaleString("en-US");
// 地图省份指标
let FenUserMap = res[7];
this.mapData.mapArr = FenUserMap.map((item) => ({
name: item.regionName,
value: Number(item.userAllCnt).toFixed(),
ratio: (Number(item.userActvDailyRatio) * 100).toFixed(1),
}));
//由于暂无数据隐藏南海诸岛,不太好,后面想到既然可以隐藏也可以将提示信息改成暂无数据
this.mapData.mapArr.push({
name: "南海诸岛",
value: 0,
itemStyle: { opacity: 0, label: { show: false } },
});
this.falg = true; //子组件渲染
})
.catch((err) => {});
},
cancelLoading() {
if (!this.loadTimer) {
this.loadTimer = setTimeout(() => {
this.loading = false;
}, 500);
} else {
clearTimeout(this.loadTimer);
}
},
},
destroyed() {},
};
</script>
先自我介绍一下,小编13年上师交大毕业,曾经在小公司待过,去过华为OPPO等大厂,18年进入阿里,直到现在。深知大多数初中级java工程师,想要升技能,往往是需要自己摸索成长或是报班学习,但对于培训机构动则近万元的学费,着实压力不小。自己不成体系的自学效率很低又漫长,而且容易碰到天花板技术停止不前。因此我收集了一份《java开发全套学习资料》送给大家,初衷也很简单,就是希望帮助到想自学又不知道该从何学起的朋友,同时减轻大家的负担。添加下方名片,即可获取全套学习资料哦