背景
在echarts沒發現有可以直接使用的展示百分比的柱形圖,只好自己封裝一個組件使用
實現思路
一、圖形拆解
要實現的組件是一個 可配置的圓柱形液柱圖組件,常用于展示比例進度,比如任務完成度、指標達成率等。把圖拆成最小單元然后拼接起來,如下表:
功能點 | 描述 |
---|---|
1. 顯示進度柱 | 高度隨 num / target 變化的水柱視覺效果 |
2. 圓柱外形 | 頂部、底部使用橢圓(border-radius)構造立體感 |
3. 自定義樣式 | 寬高、顏色可配置 |
4. 百分比顯示 | 可選是否顯示進度數值 |
5. 動畫過渡 | 數值變化時水柱高度平滑變化 |
二、結構設計
<div class="lui-column-bg"> <!-- 圓柱容器 --><div class="lui-inner"> <!-- 動態高度水柱 --><div class="lui-inner-text"> <!-- 可選百分比文字 -->{{ validPercentage }}%</div></div>
</div>
.lui-column-bg
是整個圓柱容器,帶有頂部/底部的圓帽(偽元素::before/::after
).lui-inner
是內部水柱塊,其height
是根據 num/target 實時計算的.lui-inner-text
是可選顯示的百分比數值
三、 計算邏輯
validPercentage() {if (this.target <= 0) return 0;const percent = (this.num / this.target) * 100;return Math.min(Math.round(percent), 100);
}
- 避免除以 0 的錯誤
- 保證水柱最大不超過 100%
Math.round
取整更簡潔美觀(頁面不出現小數點)
四、關鍵樣式
1. .lui-column-bg
.lui-column-bg {background-color: #2a4d5e; // 水柱外殼背景色position: relative;border-radius: 50px;overflow: hidden;
}
overflow: hidden
確保內部液面圓帽不溢出容器邊界- 使用
::before
和::after
構建頂部與底部的圓帽
2、 .lui-inner
.lui-inner {position: absolute;bottom: 0;transition: height 0.5s ease-in-out;
}
bottom: 0
讓水面從底部“漲”起來transition
讓數值變化動畫流暢過渡
3、.lui-inner::before / ::after
-
::before
是水柱頂部的圓形高光 -
::after
是底部的白色圓邊,用來模擬“液面”
4、.lui-inner-text
.lui-inner-text {color: white;font-size: 14px;font-weight: bold;position: relative;z-index: 2;
}
顯示中間百分比文字,保持在水柱內層上方,不被遮擋
五、可配置參數說明
參數 | 類型 | 說明 |
---|---|---|
num | Number | 當前數值 |
target | Number | 目標數值 |
width | Number | 圓柱寬度(單位:px) |
height | Number | 圓柱高度 |
innerColor | String | 水柱顏色 |
topColor | String | 圓柱頂部顏色(備用) |
bottomColor | String | 圓柱底部顏色(備用) |
showPercent | Boolean | 是否顯示百分比文字 |
完整代碼
<template><divclass="lui-column-bg":style="{ width: width + 'px', height: height + 'px' }"><divclass="lui-inner":style="{height: validPercentage + '%',backgroundImage: `linear-gradient(to top, ${innerColor}, ${innerColor})`}"><div class="lui-inner-text" v-if="showPercent">{{ validPercentage }}%</div></div></div>
</template><script>
export default {name: 'LiquidColumn',props: {num: { type: Number, default: 0 },target: { type: Number, default: 0 },width: { type: Number, default: 100 },height: { type: Number, default: 190 },innerColor: { type: String, default: '#28b0bd' },topColor: { type: String, default: '#54d8de' },bottomColor: { type: String, default: '#54d8de' },showPercent: { type: Boolean, default: true },},computed: {validPercentage() {if (this.target <= 0) return 0;const percent = ((this.num / this.target) * 100).toFixed(2);return Math.min(Math.round(percent), 100); // 取整,防止超過 100%},},
};
</script><style lang="scss" scoped>
.lui-column-bg {position: relative;width: 100px;height: 190px;margin: 30px auto;background-color: transparent;background-color: #2a4d5e;
}
.lui-column-bg:before {position: absolute;content: "";display: block;height: 20px;width: 100%;border-radius: 50%;top: -10.5px;z-index: 1;background-color: rgb(101 221 197);
}.lui-column-bg:after {position: absolute;content: "";display: block;height: 15px;width: 100%;border-radius: 50%;bottom: -10px;background-color: #54d8de;
}.lui-inner {position: absolute;bottom: 0;width: 100%;height: 50%;background-image: linear-gradient(to top, #28b0bd, #28b0bd);text-align: center;
}
.lui-inner::before {position: absolute;content: "";display: block;height: 20px;width: 100%;background-color: #54d8de;border-radius: 50%;top: -10.5px;z-index: 1;
}
.lui-inner:after {position: absolute;content: "";display: block;height: 15px;width: 100%;border-radius: 50%;background-color: white;bottom: -10px;
}
.lui-inner-text {color: white;position: absolute;top: 10px;width: 100%;font-size: 18px;font-weight: bold;
}
</style>
使用實例
1、引入組件
import LiquidColumn from "../components/LiquidColumn";
2、注冊組件
<script>
export default {components: { LiquidColumn },}
</script>
3、調用組件
<!-- 具體參數自行添加 -->
<liquid-column :num="50" :target="100" :showPercent="false"/>
實現效果
總結
組件相對簡單,還可以從水面波動動畫、顏色漸變、點擊事件等方面去優化。