3.21 Progress 进度条

简介

组件 Progress 用于展示操作的当前进度,告知用户当前状态和预期。本文将深入分析组件源码,剖析其实现原理,耐心读完,相信会对您有所帮助。

组件源码文件 packages/progress/src/progress.vue。 🔗gitee repo 🔗组件文档 Progress

更多组件剖析详见 👉 📚 Element 2 源码剖析组件总览

源码实现

Props

组件prop声明如下:

<script>
  export default {
    name: 'ElProgress',
    props: {
      type: {
        type: String,
        default: 'line',
        validator: val => ['line', 'circle', 'dashboard'].indexOf(val) > -1
      },
      percentage: {
        type: Number,
        default: 0,
        required: true,
        validator: val => val >= 0 && val <= 100
      },
      status: {
        type: String,
        validator: val => ['success', 'exception', 'warning'].indexOf(val) > -1
      },
      strokeWidth: {
        type: Number,
        default: 6
      },
      strokeLinecap: {
        type: String,
        default: 'round'
      },
      textInside: {
        type: Boolean,
        default: false
      },
      width: {
        type: Number,
        default: 126
      },
      showText: {
        type: Boolean,
        default: true
      },
      color: {
        type: [String, Array, Function],
        default: ''
      },
      format: Function
    },
  };
</script>

各属性功能说明。

参数
说明
类型
可选值
默认值

percentage

百分比(必填)

number

0-100

0

type

进度条类型

string

line/circle/dashboard

line

stroke-width

进度条的高度,单位 px

number

6

text-inside

进度条显示文字内置在进度条内(只在 type=line 时可用)

boolean

false

status

进度条当前状态

string

success/exception/warning

color

进度条背景色(会覆盖 status 状态颜色)

string/function/array

''

width

环形进度条画布宽度(只在 type 为 circle 或 dashboard 时可用)

number

126

show-text

是否显示进度条文字内容

boolean

true

stroke-linecap

circle/dashboard 类型路径两端的形状

string

butt/round/square

round

format

指定进度条文字内容

function(percentage)

typepercentagestatus 供了自定义验证函数,验证属性值是否符合可选值或者可选范围。 当验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。

Template

组件根节点一个类名el-progress<div>元素 ,根据组件设定的属性值动态绑定组件样式:

  • 进度条类型 el-progress--[line/circle/dashboard]

  • 进度条状态 is-[success/exception/warning]

  • 不显示进度条文字 el-progress--without-text

  • 显示文字内置在进度条内 el-progress--text-inside

属性 rolearia-valueminaria-valuenowaria-valuemax 实现 ARIA 无障碍网页应用, 更多内容详见 "ARIA",MDN

根节点下包含 3 个子节点:

  • 类名el-progress-bar<div>元素用于渲染线形进度条功能。

  • 类名el-progress-circle<div>元素用于渲染环形/仪表盘进度条功能。

  • 类名el-progress__text<div>元素渲染外显文字内容。

到此组件主要实现结构已经介绍完毕,接下来将分析各功能源码实现逻辑。

线形进度条

线形进度条,提供了进度百分比显示、文字内显/外显、文字内容格式化、自定义颜色等功能。

组件 DOM 结构如下图: image.png

  • 1️⃣ el-progress 组件根节点

  • 2️⃣ el-progress-bar 线形进度条节点

    • 3️⃣ el-progress-bar__outer 进度条背景

    • 4️⃣ el-progress-bar__inner 进度显示

    • 5️⃣ el-progress-bar__innerText 内显文字

  • 6️⃣ el-progress__text 外显文字

1️⃣

根据组件设定的属性值绑定组件样式: 进度条类型、进度条状态 、不显示进度条文字、文字显示位置(内置/外部)。

2️⃣

当传入type值为line或不设置 type时,组件渲染成线形进度条。

3️⃣

属性strokeWidth用于设置进度条背景的高度。

4️⃣

计算属性barStyle用于控制进度条进度和颜色。

barStyle根据 percentage 属性值动态生成样式对象 { width: "80%" , backgroundColor: "" }。 进度显示通过宽度百分比控制,此处的 backgroundColor 为自定义颜色值(会覆盖 status 状态颜色),默认情况为空。


自定义颜色

方法 getCurrentColor用于自定义进度条颜色,通过判断属性 color 值的类型实现各自逻辑处理。

color 可以接受颜色字符串,函数和数组。

  • 若值为函数,函数第一参数应传入 percentage 属性值 (格式function(percentage)),直接调用函数即可this.color(percentage)

  • 若值为字符串,直接返回属性值 this.colorcolor 默认值为"", 不设置该属性,默认情况下执行此逻辑。

  • 若值为数组(字符串或对象数组),根据 percentage 所属范围,返回对应颜色。

若值为数组,则调用方法 getLevelColor

方法 getColorArray,返回对象数组,定义不同数值范围的背景颜色。若字符串数组,方法根据数组长度,自动切分构建成对象数组 [{ color: "#f56c6c", percentage: 20 }]。 若传入对象数组,对象格式应为 { color: string, percentage: number }

方法 getLevelColor中调用方法getColorArray并排序,比对percentage属于哪一区间,返回对应的背景颜色。

因为比较使用了>,例如 percentage 值 100 时, 就会执行return colorArray[colorArray.length - 1].color; 返回数组最后对象的颜色。


5️⃣

内显内容计算属性 content。默认按照 [percentage]%格式显示进度百分比。 若设置了属性format,则使用函数处理返回文字内容。

组件通过属性 showTexttextInside 控制文字显示状态和位置。

6️⃣

外显内容跟内显一样,计算属性content。若设置了进度条状态status,则显示图标。

计算属性 iconClass 返回不同状态 success/exception/warning的 icon, 不同类型下success/exception 对应图标有所区别。

使用计算属性progressTextSize控制字体大小。 当类型为line时,基于进度条高度-属性strokeWidth;当类型为circle/dashboard时,基于环形进度条画布宽度-属性width

自定义文字格式

image.png

组件样式

组件样式源码 packages\theme-chalk\src\progress.scss 使用 scss 的混合指令 bemwhen 嵌套生成组件样式。

在类.el-progress-bar__inner 定义了默认进度条颜色 background-color: #409eff;

若指定了组件状态,会生成样式覆盖掉默认颜色。同时制定了外显文本的字体图标颜色。

若是使用属性color自定义颜色,会生成内联样式,会覆盖 status 状态颜色。

内显文本居右对齐,属性是在.el-progress-bar__inner的定义的。

环形/仪表盘进度条

环形/仪表盘进度条实现主要使用了<svg>元素,会另开篇幅进行详细介绍。

容器/画布

类名el-progress-circlediv元素创建环形进度条画布宽度(基于属性width)。

环形/仪表盘进度条使用了<svg>元素,元素的viewBox 属性允许指定一个给定的一组图形伸展以适应特定的容器元素。viewBox 属性的值是一个包含 4 个参数的列表 min-x, min-y, widthheight, 以空格或者逗号分隔开, 在用户空间中指定一个矩形区域映射到给定的元素,不允许宽度和高度为负值,0 则禁用元素的呈现。 此属性绝非三言两语能说清楚,在此不过多详述,推荐阅读 理解 SVG viewport,viewBox,preserveAspectRatio 缩放

<svg>元素实现,使用了两个 path 元素创建背景环el-progress-circle__track和进度环el-progress-circle__path

svg中的元素在浏览器渲染时会遵守 html 中有固定的排列顺序。先出现的元素会先绘制层级较低,而后绘制的元素层级依次增高,如果元素间的位置有重叠,则会现后绘制的元素会遮盖住先出现的元素(层级高遮盖层级低元素)。 渲染后图形叠加就实现了进度环效果。

image.png

对比可知环形/仪表盘的背景环、以及进度环起始都不一样,组件使用了功能更加强大灵活 <path> 标签来实现,但理解起来有点难度。若只是环形进度条可以使用<circle>标签实现会更加简单。

image.png

背景环 Path

接下先介绍几个基础且重要的计算属性。

属性 relativeStrokeWidth是圆形轮廓的宽度,值类型为 percentage, 是进度条的宽度跟画布宽度的百分比。 strokeWidth 默认值 6 , width 默认值 12, 所以 relativeStrokeWidth 默认值为 4.8 。

属性 radius 是绘制圆形的半径,值类型为 percentage

属性 radius 是圆形的周长。

属性 rate 表示绘制圆形的弧长,类型 dashboard时只会绘制 3/4 周长长度的轮廓,也就是仪表盘进度条为什么有缺口。

背景环 <path> 元素中属性d创建一个圆形;属性stroke-width指定了圆形的轮廓的宽度,绑定计算属性relativeStrokeWidth ;属性stroke定义了给定图形元素的外轮廓的颜色#e5e9f2;属性 fill 用于填充轮廓内的形状的颜色,值为none无填充;计算属性 trailPathStyle 会生成 stroke-dasharraystroke-dashoffset等属性用于设置描边的显示和偏移错位。

fill 属性填充效果如下:

image.png

d 属性

属性d使用计算属性trackPath,返回创建圆环的一系列路径描述。

不同类型对应的路径描述。

路径描述中用到了MovetoArcto这两个指令。

指令是大小写敏感的;一个大写的命令指明它的参数是绝对位置,而小写的命令指明相对于当前位置的点。可以指定一个负数值作为命令的参数:负角度将是逆时针的,绝对 x 和 y 位置将视为负坐标。负相对 x 值将会往左移,而负相对 y 值将会向上移。

Moveto 命令用作开始一个路径。可以被想象成拎起绘图笔,落脚到另一处。在上一个点和这个指定点之间没有线段绘制。

  • M x,y 在这里 x 和 y 是绝对坐标,分别代表水平坐标和垂直坐标。

  • m dx,dy 在这里 dx 和 dy 是相对于当前点的距离,分别是向右和向下的距离。

Arcto 命令用作绘制椭圆弧(圆是特殊的椭圆)。 指令格式 A/a (rx ry x-axis-rotation large-arc-flag sweep-flag x y)

  • A (绝对)| a (相对)

  • rx ry是椭圆的两个半轴的长度。

  • x-axis-rotation 是椭圆相对于坐标系的旋转角度,角度数而非弧度数。

  • large-arc-flag 是标记绘制大弧(1)还是小弧(0)部分。

  • sweep-flag 是标记向顺时针(1)还是逆时针(0)方向绘制。

  • x y 是圆弧终点的坐标。 关于 large-arc-flagsweep-flag参数对应的绘制情况。因为绘制的是半圆,参数large-arc-flag的绘制大小弧对组件没有影响。

image.png

circle 路径图解

circle类型的路径指令解读如下:

  1. M 50 50 绘制从点位 1️⃣ 也就是圆心开始,绝对坐标 (50,50)

  2. m 0 47 从点位 1️⃣ 沿 y 轴下移 47,也就是圆的半径长度,移动到点位 2️⃣。

  3. a 47 47 0 1 1 0 -94 从点位 2️⃣ 到点位 3️⃣ 绘制一个半圆弧,从点位 2️⃣ 沿 y 轴上移 94(圆直径长度)就到点位 3️⃣。

  4. a 47 47 0 1 1 0 94 从点位 3️⃣ 到点位 4️⃣(也就是点位 2️⃣)绘制一个半圆弧,从点位 3️⃣ 沿 y 轴下移 94 就到点位 4️⃣,形成一个闭合圆。

image.png

dashbord 路径图解

dashbord类型的路径指令解读如下:

  1. M 50 50 绘制从点位 1️⃣ 也就是圆心开始,绝对坐标 (50,50)

  2. m 0 -47 从点位 1️⃣ 沿 y 轴上移 47,也就是圆的半径长度,移动到点位 2️⃣。

  3. a 47 47 0 1 1 0 94 从点位 2️⃣ 到点位 3️⃣ 绘制一个半圆弧,从点位 2️⃣ 沿 y 轴下移 94(圆直径长度)就到点位 3️⃣。

  4. a 47 47 0 1 1 0 -94 从点位 3️⃣ 到点位 4️⃣(也就是点位 2️⃣)绘制一个半圆弧,从点位 3️⃣ 沿 y 轴上移 94 就到点位 4️⃣,形成一个闭合圆。

image.png

不同类型的图形绘制起点(点位 2️⃣),决定了进度条进度起点。当然dashbord类型到此还没有结束,它的缺口处理还没有。

缺口实现

stroke-dasharraystroke-dashoffset等属性可以直接用作一个 CSS 样式表内部的属性。 计算属性 trailPathStyle 会生成一个样式对象,用于设置描边的显示和偏移错位。

stroke-dasharray第一个属性值表是轮廓显示长度,circleperimeter 圆的周长,dashbord0.75*perimeter

image.png

计算属性strokeDashoffset用于起点的偏移,正数为 x 值向左偏移,负数为 x 值向右偏移。

相当于顺时针旋转圆,旋转缺口弧度的一半,形成一个对称结构。 image.png

进度环 Path

相较于背景环,进度环代码多了 stroke-linecap属性。

跟背景环一样路径创建,不同之处进度展示通过stroke-dasharray 第一个属性值进行控制,通过绘制圆弧长度*percentage来显示进度。同时加入了transition缓动效果,使视感更加真实。

属性 stroke-linecap 进度条边缘的形状为方形; image.png

进度环的颜色使用计算属性stroke,支持自定义颜色、状态颜色,默认进度条背景色为#20a0ff

percentage 值为 0 时,stroke-width属性值为 0,元素将不绘制轮廓。

外显文本

由前文可知,环形的内容显示为外显内容元素el-progress__text,计算属性content。若设置了进度条状态status,则显示图标。计算属性 iconClass 返回不同状态 success/exception/warning的 icon, 不同类型下success/exception 对应图标有所区别。

外显文本样式使用绝对定位,在画布水平垂直居中。

📚 参考&&关联阅读

"SVG/Element/path",MDN "SVG/Attribute",MDN

最后更新于