做数据可视化的时候,经常碰到需要很灵活的数字形式展示。

先上个效果图:

如图包括名称,数量,别名,单位,上升下降,环比等等的复合数据展示,并且需要支持样式灵活配置。

此组件包括2个模块,父容器组件box-group,其中每一项的子组件box。

父组件 box-group

 1 <template>
2 <div class="box-group">
3 <div class="box-wrapper" v-for="(item, index) in dataProvider" :key="index" v-if="index < dataProvider.length && index % col == 0">
4 <box
5 class="item"
6 :theme="theme"
7 :style="{ marginBottom: lineGap }"
8 v-for="(bb, idx) in colArray"
9 :dataProvider="dataProvider[index + idx]"
10 :key="idx"
11 :openType="openType"
12 @selected="selected"
13 ></box>
14 </div>
15 </div>
16 </template>
17
18 <script>
19 import Box from './components/box.vue';
20
21 export default {
22 name: 'LiloBoxGroup',
23 props: {
24 col: {
25 type: Number,
26 default: 2
27 },
28 theme: {
29 type: String,
30 default: 'blue'
31 },
32 lineGap: {
33 type: String,
34 default: '10px'
35 },
36 dataProvider: {
37 type: Array,
38 default() {
39 return [
40 // { label: '总人口数', value: '123213', unit: '人', color: '#ff0000' },
41 // { label: '总户数', value: '123213', unit: '户', color: '#123312' },
42 // { label: '总人口数', value: '123213', unit: '人', color: '#235234' },
43 // { label: '总户数', value: '123213', unit: '户', color: '#444444' }
44 ];
45 }
46 },
47 openType: {
48 type: String,
49 default: 'popup'
50 }
51 },
52 data() {
53 return {};
54 },
55 components: {
56 Box
57 },
58 mounted() {},
59 computed: {
60 colArray() {
61 let result = [];
62 for (let i = 0; i < this.col; i++) {
63 result.push(i);
64 }
65 return result;
66 }
67 },
68 methods: {
69 selected(data) {
70 this.$emit('selected', data);
71 }
72 }
73 };
74 </script>
75
76 <style lang="scss" scoped>
77 .box-group {
78 .box-wrapper {
79 display: flex;
80 margin-top: 5px;
81 .item {
82 flex: 1;
83 }
84 }
85 }
86 </style>

子组件 box

  1 <template>
2 <div class="box">
3 <div class="icon-wrapper"><div class="icon" :style="iconStyle" v-if="dataProvider"></div></div>
4 <div class="box-wrapper" v-if="dataProvider">
5 <div class="label" :style="labelStyle">{{ dataProvider.label }}</div>
6 <div @click="goTo">
7 <span class="value" :style="valueStyle" v-if="valueShow">{{ dataProvider.value | toThousandFilter }}</span>
8 <span class="alias" :style="aliasStyle">{{ dataProvider.alias }}</span>
9 </div>
10 <div class="unit" :style="unitStyle" v-if="valueShow">
11 {{ dataProvider.unit }}
12 <span v-if="dataProvider.hasOwnProperty('percent') && dataProvider.percent"
13 class="percent" :style="percentStyle" v-html="percentFormatter"></span>
14 <span v-if="dataProvider.hasOwnProperty('trend') && dataProvider.trend"
15 class="trend" :style="trendStyle" v-html="trendFormatter"></span>
16 </div>
17 </div>
18 <!-- <component ref="component" :is="openType" /> -->
19 </div>
20 </template>
21
22 <script>
23 import variables from '../../../../src/styles/variables.scss';
24 // import Popup from './popup.vue';
25 // import Drawer from './Drawer.vue';
26 export default {
27 name: 'LiloBox',
28 // components: {
29 // Popup,
30 // Drawer
31 // },
32 props: {
33 dataProvider: {
34 type: Object,
35 default() {
36 return null;
37 }
38 },
39 theme: {
40 type: String,
41 default: 'blue'
42 },
43 openType: {
44 type: String,
45 default: 'popup'
46 }
47 },
48 computed: {
49 themeObject() {
50 return {
51 icon: variables[this.theme],
52 label: variables[this.theme],
53 value: variables[this.theme],
54 alias: variables[this.theme],
55 unit: variables[this.theme]
56 };
57 },
58 valueShow() {
59 if (this.dataProvider.hasOwnProperty('show')) {
60 return this.dataProvider.show;
61 } else {
62 return true;
63 }
64 },
65 iconStyle() {
66 return {
67 'background-color': this.dataProvider.iconColor || this.dataProvider.color || this.themeObject.icon
68 };
69 },
70 labelStyle() {
71 return {
72 color: this.dataProvider.labelColor || this.dataProvider.color || this.themeObject.label,
73 fontSize: (this.dataProvider.labelSize || 1) + 'rem'
74 };
75 },
76 valueStyle() {
77 return {
78 color: this.dataProvider.valueColor || this.dataProvider.color || this.themeObject.value,
79 fontSize: (this.dataProvider.valueSize || 1.5) + 'rem'
80 };
81 },
82 aliasStyle() {
83 return {
84 color: this.dataProvider.aliasColor || this.dataProvider.color || this.themeObject.alias,
85 fontSize: (this.dataProvider.aliasSize || 1) + 'rem'
86 };
87 },
88 unitStyle() {
89 return {
90 color: this.dataProvider.unitColor || this.dataProvider.color || this.themeObject.unit,
91 fontSize: (this.dataProvider.unitSize || 1) + 'rem'
92 };
93 },
94 percentStyle() {
95 return {
96 color: this.dataProvider.percent > 0 ? variables.red : variables.deepGreen
97 };
98 },
99 trendStyle() {
100 return {
101 color: this.dataProvider.trend > 0 ? variables.red : variables.deepGreen
102 };
103 },
104 percentFormatter() {
105 const _percent = this.dataProvider.percent;
106 if (!_percent || _percent === 0) {
107 return '';
108 }
109 if (_percent > 0) {
110 return '<i class="el-icon-caret-top" style="margin-right:3px;"></i>' + Math.abs(_percent) + '%';
111 // return "" + Math.abs(_percent) + "%"
112 } else {
113 return '<i class="el-icon-caret-bottom" style="margin-right:3px;"></i>' + Math.abs(_percent) + '%';
114 // return "" + Math.abs(_percent) + "%"
115 }
116 },
117 trendFormatter() {
118 const _trend = this.dataProvider.trend;
119 if (!_trend || _trend === 0) {
120 return '';
121 }
122 if (_trend > 0) {
123 return '<i class="el-icon-caret-top" style="margin-right:3px;"></i>' + Math.abs(_trend);
124 // return "" + Math.abs(_trend) + "%"
125 } else {
126 return '<i class="el-icon-caret-bottom" style="margin-right:3px;"></i>' + Math.abs(_trend);
127 // return "" + Math.abs(_trend) + "%"
128 }
129 }
130 },
131 methods: {
132 goTo() {
133 // if (this.dataProvider.href) {
134 // this.$refs.component.show(this.dataProvider);
135 // }
136 this.$emit('selected', this.dataProvider);
137 }
138 }
139 };
140 </script>
141
142 <style lang="scss" scoped>
143 $blue: #0058a5;
144 $grey : #585858;
145
146 .box {
147 display: flex;
148 .icon-wrapper {
149 flex: 0 0 20px;
150 display: flex;
151 align-items: center;
152 justify-content: center;
153 .icon {
154 width: 5px;
155 height: 50%;
156 background-color: $blue;
157 }
158 }
159 .box-wrapper {
160 flex: 1;
161 display: flex;
162 flex-direction: column;
163 }
164 .label {
165 color: $grey;
166 // font-size: 1rem;
167 }
168 .value {
169 color: $blue;
170 // font-size: 1.5rem;
171 font-weight: 550;
172 cursor: pointer;
173 }
174 .alias {
175 color: $blue;
176 // font-size: 1rem;
177 font-weight: 550;
178 cursor: pointer;
179 margin-left: 5px;
180 }
181 .percent {
182 color: $blue;
183 // font-size: 1rem;
184 font-weight: 550;
185 cursor: pointer;
186 }
187 .trend {
188 color: $blue;
189 // font-size: 1rem;
190 font-weight: 550;
191 cursor: pointer;
192 }
193 .unit {
194 color: $blue;
195 // font-size: 1rem;
196 }
197 }
198 </style>

调用案例:

<lilo-box-group :dataProvider="boxData" theme="blue" :col="6" lineGap="10px" @selected="boxGroupSelected"></lilo-box-group>
 1 boxData: [
2 {
3 label: '初等教育',
4 value: 12447,
5 unit: '人',
6 alias: '1.5%',
7 // percent: 0.3,
8 trend: -120,
9 valueSize: 0.9,
10 aliasSize: 0.7
11 },
12 {
13 label: '中等教育',
14 value: 579160,
15 unit: '人',
16 alias: '69.6%',
17 percent: 5.8,
18 valueSize: 0.9,
19 aliasSize: 0.7
20 },
21 {
22 label: '高等教育',
23 value: 66622,
24 unit: '人',
25 alias: '8%',
26 // percent: -8.6,
27 trend: -86,
28 valueSize: 0.9,
29 aliasSize: 0.7
30 },
31 {
32 label: '研究生教育',
33 value: 3734,
34 unit: '人',
35 alias: '0.4%',
36 // percent: -0.2,
37 trend: 189,
38 valueSize: 0.9,
39 aliasSize: 0.7
40 },
41 {
42 label: '有房',
43 value: 459386,
44 unit: '人',
45 alias: '55.2%',
46 percent: -5,
47 valueSize: 1.2,
48 aliasSize: 0.9
49 },
50 {
51 label: '有车',
52 value: 63210,
53 unit: '人',
54 alias: '7.6%',
55 percent: -6.3,
56 valueSize: 1.2,
57 aliasSize: 0.9
58 }
59 ]

1 boxGroupSelected(val) { 2 console.log(val); 3 }

附录:variables.scss

// base color

// $blue: #324157;
// $menuBg: #304156;
// $menuHover: #263445;
// $subMenuBg: #1f2d3d;
// $subMenuHover: #001528; $color-background-s: rgba(0, 0, 0, 0.9); $blue: #00417a;
$commonBlue: #0000ff;
// $menuBg: #00417a;
$menuBg: #ffffff;
// $menuHover: #00355e;
$menuHover: #f4f4f4;
// $subMenuBg: #003462;
$subMenuBg: #ffffff;
// $subMenuHover: #002546;
$subMenuHover: #e7e7e7;
$menuBorderRight: 1px solid #c5c1c1; $light-blue: #1890ff;
$red: #f56c6c;
$deep-red: #ff0000;
$blood-red: #d50000;
$pink: #dc67ce;
$green: #0bbd87;
$tiffany: #4ab7bd;
$yellow: #e6a23c;
$deep-yellow: #d69737;
$panGreen: #30b08f;
$purple: #6771dc;
$grey: #585858;
$light-grey: #f0f0f0;
$orange: #ff8037;
$deep-green: #07885f;
$light-green: #0bbd8722;
$light-purple: #6771dc22;
// sidebar
// $menuText: #bfcbd9;
$menuText: #002546;
// $menuActiveText: #409eff;
$menuActiveText: #08ac76;
// $subMenuActiveText: #f4f4f5;
$subMenuActiveText: #00417a; $sideBarWidth: 230px;
$headerHeight: 54px; // the :export directive is the magic sauce for webpack
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
:export {
blue: $blue;
commonBlue: $commonBlue;
lightBlue: $light-blue;
red: $red;
deepRed: $deep-red;
bloodRed: $blood-red;
pink: $pink;
green: $green;
deepGreen: $deep-green;
lightGreen: $light-green;
lightPurple: $light-purple;
tiffany: $tiffany;
yellow: $yellow;
deepYellow: $deep-yellow;
orange: $orange;
panGreen: $panGreen;
purple: $purple;
grey: $grey;
lightGrey: $light-grey;
menuText: $menuText;
menuActiveText: $menuActiveText;
subMenuActiveText: $subMenuActiveText;
menuBg: $menuBg;
menuHover: $menuHover;
subMenuBg: $subMenuBg;
subMenuHover: $subMenuHover;
sideBarWidth: $sideBarWidth;
}

参数解释:

col:每行的列数

theme:主题,这个是我的整个插件有个variables.scss,里面有很多主题色

lineGap:行间距

dataProvider:

[{

label: '初等教育', //标题
value: 12447, //主数值
unit: '人', //单位
alias: '1.5%', //别名
percent: 0.3, //百分比
trend: -120, //趋势值
labelSize: 1, //标题字体大小 rem
valueSize: 0.9, //主数值字体大小 rem
aliasSize: 0.7, //别名字体大小 rem
unitSize: 1, //单位字体大小 rem
color: '#000000', //所有文字颜色,颜色优先级为 具体子项颜色(下面的颜色参数)> color > theme
iconColor: '#000000', //左边边框颜色
labelColor: '#000000', //标题文字颜色
valueColor: '#000000', //主数值文字颜色
aliasColor: '#000000', //别名文字颜色
unitColor: '#000000', //单位文字颜色

}]

数据可视化【原创】vue复合数字形式展示的更多相关文章

  1. 查询表格——建立动态表格,使用ajax输入查询条件将后台数据查询出来以表格的形式展示出来

    建立动态表格,使用ajax将前台查询条件传给后台,并将查询结果以表格的形式展示出来. 页面的展示效果如下图所示: 第一步:查询条件的部分: 代码如下: <div class="text ...

  2. Python实现汉诺塔问题的可视化(以动画的形式展示移动过程)

    学习Python已经有一段时间了,也学习了递归的方法,而能够实践该方法的当然就是汉诺塔问题了,但是这次我们不只是要完成对汉诺塔过程的计算,还要通过turtle库来体现汉诺塔中每一层移动的过程. 一.设 ...

  3. Matplotlib数据可视化(7):图片展示与保存

    In [1]: import os import matplotlib.image as mpimg from PIL import Image import matplotlib.pyplot as ...

  4. 数据可视化界面UI设计大屏展示

  5. Excel数据可视化图表设计需要注意的几个问题

    ​大数据发展迅速的时代,数据分析驱动商业决策.对于庞大.无序.复杂的数据要是没经过合适的处理,价值就无法体现. 可以想象一本没有图片的教科书.没有图表.图形或是带有箭头和标签的插图或流程图,那么这门学 ...

  6. 最棒的7种R语言数据可视化

    最棒的7种R语言数据可视化 随着数据量不断增加,抛开可视化技术讲故事是不可能的.数据可视化是一门将数字转化为有用知识的艺术. R语言编程提供一套建立可视化和展现数据的内置函数和库,让你学习这门艺术.在 ...

  7. EasyNVR摄像机网页无插件直播方案H5前端构建之:使用BootstrapPagination以分页形式展示数据信息

    背景介绍 EasyNVR核心在于摄像机的音视频流的获取.转换.转码与高性能分发,同时同步完成对实时直播流的录像存储,在客户端(PC浏览器.Android.iOS.微信)进行录像文件的检索.回放和下载. ...

  8. 基于echarts 24种数据可视化展示,填充数据就可用,动手能力强的还可以DIY(演示地址+下载地址)

    前言 我们先跟随百度百科了解一下什么是"数据可视化 [1]". 数据可视化,是关于数据视觉表现形式的科学技术研究. 其中,这种数据的视觉表现形式被定义为,一种以某种概要形式抽提出来 ...

  9. redis 一二事 - 设置过期时间,以文件夹形式展示key显示缓存数据

    在使用redis时,有时回存在大量数据的时候,而且分类相同,ID相同 可以使用hset来设置,这样有一个大类和一个小分类和一个value组成 但是hset不能设置过期时间 过期时间只能在set上设置 ...

  10. EasyNVR RTSP转RTMP-HLS流媒体服务器前端构建之:使用BootstrapPagination以分页形式展示数据信息

    上一篇介绍通过接口来获取数据,本篇将介绍如何以分页形式展示出接口获取到的数据 获取到的数据往往会很多,为了追去页面的美观和方便用户的检索,需要进行分页的展示: EasyNVR可接如多通道,当我们的通道 ...

随机推荐

  1. 8张图带你全面了解kafka的核心机制

    前言 kafka是目前企业中很常用的消息队列产品,可以用于削峰.解耦.异步通信.特别是在大数据领域中应用尤为广泛,主要得益于它的高吞吐量.低延迟,在我们公司的解决方案中也有用到.既然kafka在企业中 ...

  2. CogSci 2017-Learning to reinforcement learn

    Key 元学习系统(监督+从属)扩展于RL设置 LSTM用强化学习算法进行训练,可以使agent获得一定的学习适应能力 解决的主要问题 DRL受限于特定的领域 DRL训练需要大量的数据 作者参考了Ho ...

  3. 一个.Net开发的功能强大、易于使用的流媒体服务器和管理系统

    推荐一个视频管理系统,非常适合个人或者公司打造视频网站. 项目简介 这是基于.Net Core开发的,跨平台的开源项目:支持多种音视频格式,如MP3.MP4.AVI.WMV.FLV等:支持本地管理与远 ...

  4. 2019年蓝桥杯C/C++大学B组省赛真题(特别数的和)

    题目描述: 小明对数位中含有2.0.1.9 的数字很感兴趣(不包括前导0) 在1到40中这样的数包括1.2.9.10 至32.39 和40,共28 个,他们的和是574. 请问,在1到n 中,所有这样 ...

  5. 最全面的Mybatis面试八股文

    Mybatis是什么? MyBatis框架是一个开源的数据持久层框架. 它的内部封装了通过JDBC访问数据库的操作,支持普通的SQL查询.存储过程和高级映射,几乎消除了所有的JDBC代码和参数的手工设 ...

  6. Kubernetes(k8s)定时任务:CronJob

    目录 一.系统环境 二.前言 三.Kubernetes CronJob简介 四.kubernetes CronJob和Linux crontab对比 五.CronJob表达式语法 六.创建CronJo ...

  7. hosts文件妙用,提升网站访问速度!

    一.背景 在讲解hosts文件之前,我们先了解下IP地址与域名的关系. 1.IP地址与域名的关系 IP(Internet Protocol)是一种规定互联网中数据传输的协议,每台连接到互联网中的计算机 ...

  8. 如何取消Blazor Server烦人的重新连接?

    如何取消Blazor Server烦人的重新连接? 相信很多Blazor的用户在开发内部系统上基本上都选择速度更快,加载更快的Blazor Server模式. 但是Blazor Server由于是Si ...

  9. 前端Vue自定义加载中loading加载结束end组件 可用于分页展示 页面加载请求

    前端Vue自定义加载中loading加载结束end组件 可用于分页展示 页面加载请求, 请访问uni-app插件市场地址:https://ext.dcloud.net.cn/plugin?id=132 ...

  10. 如何让一句话木马绕过waf ?

    一.什么是一句话木马? 一句话木马就是只需要一行代码的木马,短短一行代码,就能做到和大马相当的功能.为了绕过waf的检测,一句话木马出现了无数中变形,但本质是不变的:木马的函数执行了我们发送的命令. ...