服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - js教程 - JS前端模拟Excel条件格式实现数据条效果

JS前端模拟Excel条件格式实现数据条效果

2023-05-25 12:54旋涡 js教程

这篇文章主要为大家介绍了JS前端模拟Excel条件格式实现数据条效果,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

需求背景

最近业务中遇到一个有意思的需求,是要在现有的表格中实现类似 Excel 中的数据条的效果,在数据比较多的时候单纯看表格里的数字会比较密集且不容易对比,加上数据条之后就比较明显的看出数据的对比情况,也让表格看起来生动了一些,这算是融合了表格和柱状图的优点。

先来看下 Excel 的效果

JS前端模拟Excel条件格式实现数据条效果

下面记录下实现过程和原理。

需求分析

通过图片可以看出共有几种情况:

  • 只有正值:数据条全部向右
  • 只有负值:数据条全部向左
  • 正负值都有:正负值会以一个轴线做分割分布在左右两侧,根据正负值的多少轴线的位置也会相应的偏左或偏右

实现逻辑

实现这个效果的前提,我们要知道每列数据的最大值max和最小值min,最大值的数据条宽度就是100%,下面先用伪代码梳理下逻辑。

全是正值和全是负值的情况,这种情况就比较简单了,就是计算单元格的值占最大值的比例,计算公式是这样:数据条宽度 = (当前值 / max) * 100

正负值都有的情况多了一个“轴线位置“的计算和”数据条偏移量“计算

?
1
轴线位置 = (Math.abs(min) / (max - min)) * 100
?
1
数据条宽度 = (Math.abs(当前值) / (max - min)) * 100
?
1
2
3
4
5
// 当前值 < 0 时数据条在轴线左边,改变 right 值
// 数据条的总长为100%
right = 100 - 轴线位置
// 当前值 > 0 时数据条在轴线右边,改变 left 值
left = 轴线位置

轴线位置逻辑其实是 "最小值到0的距离在总长度(max-min)之间的占比",我们知道数字与0之间的距离其实就是绝对值的计算,那么转换为公式来表示就是:

数据条的宽度就是 “当前值到0的距离在总长度(max-min)之间的占比”,公式表示:

  • 数据条的偏移量,这里需要知道是向左还是向右偏移(最终是通过改变元素CSS的 left、right 属性来实现偏移)

完整代码实现

代码使用 Vue + ElementUI

template 部分

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<template>
  <el-table :data="tableData" border style="width: 100%">
    <el-table-column
      v-for="item in columns"
      sortable
      :key="item.prop"
      :prop="item.prop"
      :label="item.label"
    >
      <template slot-scope="scope">
        <!-- 数据条 -->
        <div class="data-bar" :style="renderDataBar(item, scope.row)"></div>
        <!-- 轴线 -->
        <div class="data-bar-axis" :style="renderAxis(item, scope.row)"></div>
        <!-- 当前值 -->
        <span class="cell-value">{{ scope.row[item.prop] }}</span>
      </template>
    </el-table-column>
  </el-table>
</template>

style 部分

先放 style 部分是为了让大家对基础样式有个感受,渲染函数中主要就是动态修改元素的 width、left、right 的值

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<style>
    .el-table .cell-value {
      position: relative;
    }
    .data-bar {
      position: absolute;
      top: 0;
      bottom: 0;
      margin: 5px auto;
      transition: width 0.2s;
    }
    .data-bar-axis {
      position: absolute;
      top: -1px;
      bottom: 0;
      border-right: 1px dashed #303133;
    }
</style>

script 部分

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<script>
export default {
  data() {
    return {
      columns: [
        {
          prop: 'positive',
          label: '正值',
          min: 1,
          max: 10
        },
        {
          prop: 'negative',
          label: '负值',
          min: -1,
          max: -12
        },
        {
          prop: 'mixed',
          label: '正负值',
          min: -6,
          max: 5
        }
      ],
      tableData: []
    }
  },
  created() {
    this.initData()
  },
  methods: {
    initData() {
      // mock数据过程,忽略 ...
      this.tableData.push({...})
    },
    renderDataBar(column, row) {
      const { min, max, prop } = column
      // 当前单元格值
      const cellVal = row[prop]
      if (cellVal === 0) return { display: 'none' };
      let style = {
        width: '0',
        background: '#409eff'
      }
      // 全是正值 或 全是负值
      if (min >= 0 || max <= 0) {
        const width = ((cellVal / max) * 100).toFixed(2);
        style.width = `${width}%`
        style = min >= 0 ? { ...style, left: '0' } : { ...style, right: '0' }
      }
      // 正负值都有
      if (min < 0 && max > 0) {
        const range = max - min;
        // 轴线位置
        const leftOffset = Math.abs((min / range) * 100)
        // 数据条宽度
        const width = ((Math.abs(cellVal / range) * 100)).toFixed(2)
        style = cellVal > 0 ? {
          width: `${width}%`,
          left: `${leftOffset.toFixed(2)}%`
        } : {
          width: `${width}%`,
          background: '#F56C6C', // 负值进行颜色区分
          right: `${(100 - leftOffset).toFixed(2)}%`
        }
      }
      return style;
    },
    renderAxis(column) {
      const { min, max } = column
      if (min < 0 && max > 0) {
        // 正负值都有的情况下,显示轴线
        const range = max - min;
        const leftOffset = (((0 - min) / range) * 100).toFixed(2)
        return {
          left: `${leftOffset}%`
        }
      } else {
        return {
          display: 'none'
        }
      }
    }
  }
}
</script>

最终实现效果

JS前端模拟Excel条件格式实现数据条效果

以上就是JS前端模拟Excel条件格式实现数据条效果的详细内容,更多关于JS模拟Excel数据条的资料请关注服务器之家其它相关文章!

原文链接:https://juejin.cn/post/7204825838537261111

延伸 · 阅读

精彩推荐
  • js教程确保JavaScript 安全的五大做法

    确保JavaScript 安全的五大做法

    如果你运行交互式网站或应用程序,JavaScript 安全性是重中之重。 从程序错误和不安全的用户输入到恶意攻击,有很多事情可能会出错。...

    粤嵌教育8982022-01-11
  • js教程详解JavaScript错误捕获

    详解JavaScript错误捕获

    这篇文章主要介绍了JavaScript错误捕获的相关资料,帮助大家更好的理解和学习使用JavaScript,感兴趣的朋友可以了解下...

    如沐春风x7112022-03-09
  • js教程一篇文章教会你使用 JavaScript 创建对象

    一篇文章教会你使用 JavaScript 创建对象

    本文基于JavaScrip基础,介绍如何去创建一个对象,通过从最基础的对象属性,对象方法,使用new Object()创建构造方法,最后介绍了对象的可变性,比较对象...

    前端进阶学习交流8392021-12-28
  • js教程微信小程序弹窗禁止页面滚动的实现代码

    微信小程序弹窗禁止页面滚动的实现代码

    这篇文章主要介绍了微信小程序弹窗禁止页面滚动的实现代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需...

    任我行RQ5632021-12-23
  • js教程如何用CocosCreator实现射击小游戏

    如何用CocosCreator实现射击小游戏

    这篇文章主要介绍了如何用CocosCreator实现射击小游戏,此游戏难度不大,仅作为入门的练手小游戏,一小时就能完成,里面用到的知识很常用,喜欢游戏的...

    战 胜5062022-03-01
  • js教程整理CocosCreator常用知识点

    整理CocosCreator常用知识点

    这篇文章主要介绍了整理CocosCreator常用知识点,这些知识点,平时几乎都能用到,希望同学们看完后,可以自己去试一下,加深印象...

    代码猴儿5522022-03-01
  • js教程js仿淘宝放大镜效果

    js仿淘宝放大镜效果

    这篇文章主要为大家详细介绍了js仿淘宝放大镜效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    屈小康11352021-12-21
  • js教程JS实现选项卡插件的两种写法(jQuery和class)

    JS实现选项卡插件的两种写法(jQuery和class)

    这篇文章主要为大家详细介绍了JS实现选项卡插件的两种写法:jQuery和class,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参...

    南柯Seven12282021-12-22