Element 2 组件Progress扩展-自定义进度条渐变色

8,345 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

简介

本文将介绍如何实现进度条的自定义渐变色功能,耐心读完,相信会对您有所帮助。

属性

渐变色配置属性继续使用color属性,更新声明支持传入object

color: {
  type: [String, Array, Function, Object],
  default: ''
},

传入对象格式为 { from: string; to: string; },排序不做要求。

{
   "0%": "#afc163",
   "25%": "#66FF00",
   "50%": "#00CC00",  
   "75%": "#009900", 
   "100%": "#ffffff"
}

新增计算属性 gradientColor 将传入的 color 对象按照百分比排序并转成对象数组 [{percentage: string; color: string;}]

gradientColor() {
  if (typeof this.color !== 'object') {
    return undefined;
  }
  const color = this.color;
  const gradient = Object.keys(color)
    .sort((a, b) => this.stripPercentToNumber(a) - this.stripPercentToNumber(b))
    .map((key, index) => {
      return {
        percentage: key,
        color: color[key]
      };
    });
  return gradient;
},

// methods  排序方法  90% => 90
stripPercentToNumber(percentage) {
  return percentage.replace('%', '');
}

线性和环形进度条渐变实现原理不同:

  • 线性使用CSS的 linear-gradient()
  • 环形使用SVG的 linearGradient

环形进度条实现

SVG的linearGradient元素用来定义线性渐变,用于图形元素的填充或描边。

代码中增加 linearGradient 线性渐变声明,元素 id 为计算属性svgGradientId,id 用作颜色填充引用 stroke="url(#id)"

遍历数组 gradientColor 生成 stop元素列表,用于定义一个渐变上的颜色坡度。

<svg viewBox="0 0 100 100">
  <defs v-if="gradientColor">
    <linearGradient :id="svgGradientId" x1="100%" y1="0%" x2="0%" y2="0%"
    >
      <stop :key="index" :offset="item.percentage" :stop-color="item.color" 
             v-for="(item,index) in gradientColor"/>
    </linearGradient>
  </defs> 
  <path
    class="el-progress-circle__path" 
    :stroke="stroke"></path>
</svg>

添加组件属性 processId 记录组件实例ID。新增计算属性svgGradientId,基于processId生成linearGradient元素 id 。

<script>
  let processIdSeed = 1;
  
  export default {
    name: 'ElProgress', 
    created() {
      this.processId = processIdSeed++;
    },
    computed: { 
      svgGradientId() {
        return `el-progress--gradient-${this.processId}`;
      }
    },
  }
</script>

进度条的颜色填充使用计算属性 stroke。当自定义颜色时,调用方法 getCurrentColor,接下来改写该方法,支持返回url(#id)内容格式。

新增方法getGradientColor用于生成渐变色配置下的环形颜色属性值 url(#id)

getCurrentColor(percentage) {
  if (typeof this.color === 'function') {
    return this.color(percentage);
  } else if (typeof this.color === 'string') {
    return this.color;
  } else if (typeof this.color === 'object') {
    return this.getGradientColor();
  } else {
    return this.getLevelColor(percentage);
  }
}, 
getGradientColor() {
  if (this.type === 'circle' || this.type === 'dashboard') {
    return `url(#${this.svgGradientId})`;
  } 
},

示例代码:

<el-progress  :percentage="70"  type="circle"
  :color="{
    '0%': '#108ee9',
    '100%': '#87d068',
  }"
></el-progress>
<el-progress  :percentage="70"  type="dashboard"
  :color="{
    '0%': '#108ee9',
    '100%': '#87d068',
  }"
></el-progress>

运行效果: image.png

线性进度条实现

线性进度条将使用CSS linear-gradient()函数实现渐变色效果。

前文可知线性进度条自定义颜色使用了绑定到内联样式的计算属性barStyle,背景设置调用了方法getCurrentColor。上一章节中环形实现中已经对getCurrentColor一系列方法进行了改写,接下来继续更新支持线性进度条。

  barStyle() {
    const style = {};
    style.width = this.percentage + '%';
    style.backgroundColor = this.getCurrentColor(this.percentage);
    return style;
  },

getGradientColor()新增逻辑,线性进度条时传入的颜色设置最终生成 backgroundImage: linear-gradient(to right, #afc163 0%, #66FF00 25%,#ffffff 100%),绑定到内联样式中进行渲染。

getGradientColor() {
  if (this.type === 'circle' || this.type === 'dashboard') {
    return `url(#${this.svgGradientId})`;
  }
  // type === 'line'
  const direction = 'to right'; // 文本方向 LTR
  const linearGradients = this.gradientColor
                          .map(({ color, percentage }) => `${color} ${percentage}`).join(', ');
  return `linear-gradient(${direction}, ${linearGradients})`;
},

考虑到代码最小改动和兼容,将backgroundColor 改为background

  barStyle() {
    const style = {};
    style.width = this.percentage + '%';
    style.background = this.getCurrentColor(this.percentage);
    return style;
  },

示例代码:

<el-progress  :percentage="80"
  :color="{
    '0%': '#108ee9',
    '100%': '#87d068',
  }"
></el-progress>

运行效果: image.png

组件最终修改代码  progress_new_features gist

参考&关联阅读

"SVG/linearGradient",MDN
"CSS/linear-gradient",MDN

关注专栏

此文章已收录到专栏中 👇,可以直接关注。