背景
在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"/>
实现效果
总结
组件相对简单,还可以从水面波动动画、颜色渐变、点击事件等方面去优化。