JS前端模擬Excel條件格式實(shí)現(xiàn)數(shù)據(jù)條效果
需求背景
最近業(yè)務(wù)中遇到一個(gè)有意思的需求,是要在現(xiàn)有的表格中實(shí)現(xiàn)類似 Excel 中的數(shù)據(jù)條的效果,在數(shù)據(jù)比較多的時(shí)候單純看表格里的數(shù)字會(huì)比較密集且不容易對(duì)比,加上數(shù)據(jù)條之后就比較明顯的看出數(shù)據(jù)的對(duì)比情況,也讓表格看起來生動(dòng)了一些,這算是融合了表格和柱狀圖的優(yōu)點(diǎn)。
先來看下 Excel 的效果
下面記錄下實(shí)現(xiàn)過程和原理。
需求分析
通過圖片可以看出共有幾種情況:
- 只有正值:數(shù)據(jù)條全部向右
- 只有負(fù)值:數(shù)據(jù)條全部向左
- 正負(fù)值都有:正負(fù)值會(huì)以一個(gè)軸線做分割分布在左右兩側(cè),根據(jù)正負(fù)值的多少軸線的位置也會(huì)相應(yīng)的偏左或偏右
實(shí)現(xiàn)邏輯
實(shí)現(xiàn)這個(gè)效果的前提,我們要知道每列數(shù)據(jù)的最大值max和最小值min,最大值的數(shù)據(jù)條寬度就是100%,下面先用偽代碼梳理下邏輯。
全是正值和全是負(fù)值的情況,這種情況就比較簡單了,就是計(jì)算單元格的值占最大值的比例,計(jì)算公式是這樣:數(shù)據(jù)條寬度 = (當(dāng)前值 / max) * 100
正負(fù)值都有的情況多了一個(gè)“軸線位置“的計(jì)算和”數(shù)據(jù)條偏移量“計(jì)算
軸線位置 = (Math.abs(min) / (max - min)) * 100
數(shù)據(jù)條寬度 = (Math.abs(當(dāng)前值) / (max - min)) * 100
// 當(dāng)前值 < 0 時(shí)數(shù)據(jù)條在軸線左邊,改變 right 值 // 數(shù)據(jù)條的總長為100% right = 100 - 軸線位置 // 當(dāng)前值 > 0 時(shí)數(shù)據(jù)條在軸線右邊,改變 left 值 left = 軸線位置
軸線位置邏輯其實(shí)是 "最小值到0的距離在總長度(max-min)之間的占比",我們知道數(shù)字與0之間的距離其實(shí)就是絕對(duì)值的計(jì)算,那么轉(zhuǎn)換為公式來表示就是:
數(shù)據(jù)條的寬度就是 “當(dāng)前值到0的距離在總長度(max-min)之間的占比”,公式表示:
- 數(shù)據(jù)條的偏移量,這里需要知道是向左還是向右偏移(最終是通過改變?cè)谻SS的 left、right 屬性來實(shí)現(xiàn)偏移)
完整代碼實(shí)現(xiàn)
代碼使用 Vue + ElementUI
template 部分
<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"> <!-- 數(shù)據(jù)條 --> <div class="data-bar" :style="renderDataBar(item, scope.row)"></div> <!-- 軸線 --> <div class="data-bar-axis" :style="renderAxis(item, scope.row)"></div> <!-- 當(dāng)前值 --> <span class="cell-value">{{ scope.row[item.prop] }}</span> </template> </el-table-column> </el-table> </template>
style 部分
先放 style 部分是為了讓大家對(duì)基礎(chǔ)樣式有個(gè)感受,渲染函數(shù)中主要就是動(dòng)態(tài)修改元素的 width、left、right 的值
<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 部分
<script> export default { data() { return { columns: [ { prop: 'positive', label: '正值', min: 1, max: 10 }, { prop: 'negative', label: '負(fù)值', min: -1, max: -12 }, { prop: 'mixed', label: '正負(fù)值', min: -6, max: 5 } ], tableData: [] } }, created() { this.initData() }, methods: { initData() { // mock數(shù)據(jù)過程,忽略 ... this.tableData.push({...}) }, renderDataBar(column, row) { const { min, max, prop } = column // 當(dāng)前單元格值 const cellVal = row[prop] if (cellVal === 0) return { display: 'none' }; let style = { width: '0', background: '#409eff' } // 全是正值 或 全是負(fù)值 if (min >= 0 || max <= 0) { const width = ((cellVal / max) * 100).toFixed(2); style.width = `${width}%` style = min >= 0 ? { ...style, left: '0' } : { ...style, right: '0' } } // 正負(fù)值都有 if (min < 0 && max > 0) { const range = max - min; // 軸線位置 const leftOffset = Math.abs((min / range) * 100) // 數(shù)據(jù)條寬度 const width = ((Math.abs(cellVal / range) * 100)).toFixed(2) style = cellVal > 0 ? { width: `${width}%`, left: `${leftOffset.toFixed(2)}%` } : { width: `${width}%`, background: '#F56C6C', // 負(fù)值進(jìn)行顏色區(qū)分 right: `${(100 - leftOffset).toFixed(2)}%` } } return style; }, renderAxis(column) { const { min, max } = column if (min < 0 && max > 0) { // 正負(fù)值都有的情況下,顯示軸線 const range = max - min; const leftOffset = (((0 - min) / range) * 100).toFixed(2) return { left: `${leftOffset}%` } } else { return { display: 'none' } } } } } </script>
最終實(shí)現(xiàn)效果
以上就是JS前端模擬Excel條件格式實(shí)現(xiàn)數(shù)據(jù)條效果的詳細(xì)內(nèi)容,更多關(guān)于JS模擬Excel數(shù)據(jù)條的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
利用 JavaScript 構(gòu)建命令行應(yīng)用
這篇文章主要介紹了利用 JavaScript 構(gòu)建命令行應(yīng)用,下面文章圍繞如何利用JavaScript 構(gòu)建命令行應(yīng)用的相關(guān)資料炸開詳細(xì)內(nèi)容,需要的朋友可以參考一下2021-11-11TypeScript新語法之infer?extends示例詳解
這篇文章主要為大家介紹了TypeScript新語法之infer?extends示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08JavaScript編程中實(shí)現(xiàn)對(duì)象封裝特性的實(shí)例講解
JavaScript可以在一定程度上以面向?qū)ο蠓绞竭M(jìn)行編程,而封裝是面向?qū)ο笾械囊粋€(gè)重要特性,本文就來分享阮一峰老師對(duì)JavaScript編程中實(shí)現(xiàn)對(duì)象封裝特性的實(shí)例講解2016-06-06微信小程序 頁面跳轉(zhuǎn)如何實(shí)現(xiàn)傳值
這篇文章主要介紹了微信小程序 頁面跳轉(zhuǎn)如何實(shí)現(xiàn)傳值的相關(guān)資料,需要的朋友可以參考下2017-04-04