需求是构建一个上传进度的圆圈。
圆饼图
首先构建一个圆饼图。
border-radius: 50%
构建一个圆形,然后conic-gradient
构建一个圆饼出来。
.pie-chart {
width: 100px;
height: 100px;
background: conic-gradient(#4352f3 0deg, #e52c5c 360deg);
border-radius: 50%;
}
内嵌一个圆形
再在中间嵌一个圆形。
.inner-circle {
width: calc(160px - 8px);
height: calc(160px - 8px);
border-radius: 50%;
background-color: white;
display: flex;
align-items: center;
justify-content: center;
}
50%
动态更新进度
写一段 Javascript 去更新进度
export const updateProgressRing = (progressRing, percent) => {
if (progressRing === null) {
return;
}
const roundPercent = Number.parseInt(percent * 100);
const processValue = progressRing.querySelector(".percentage");
processValue.textContent = `${roundPercent}%`;
progressRing.style.background = `conic-gradient(#0d6efd ${
roundPercent * 3.6
}deg, white 0deg)`;
};
跟踪进度
这里用了阿里云的 OSS 上传文件。
如果单纯上传一个文件,进度可以通过回调函数参数 progress 跟踪,然后再更新进度就行了。 如果是上传多个文件,那么需要先构建一个数组,记录每个文件的上传进度,然后再算出整体进度。
代码如下。
const uploadFile = async (key, file, idx, progressArray) => {
const store = new OSS({});
const options = {
meta: { type: object_type },
progress: (p, cpt, res) => {
if (progressArray && progressArray.length > 0) {
progressArray[idx] = p;
totalProcent =
progressArray.reduce((sum, e) => sum + e, 0) / progressArray.length;
updateProgressRing(progressRing, totalProcent);
}
},
};
const result = await store.multipartUpload(object_key, data, options);
};
const uploadFiles = async (files) => {
const progressArray = Array(files.length).fill(0);
const promises = Array.from(files).map(async (file, idx) => {
const file_suffix = file.name.split(".").slice(-1)[0];
const timestamp = Math.floor(Date.now());
const file_key = `file_${timestamp}.${file_suffix}`;
const isUploaded = await uploadFile(file_key, file, progressArray, idx);
return file_key;
});
const file_keys = await Promise.all(promises);
};
SVG
另外一种实现方式是用 SVG。关键点是stroke-dasharray
,第一个参数是虚线宽度,第二个参数是虚线间隔。将虚线间隔设置为大于圆圈周长,虚线宽度设置为进度长度,就可以表示进度了。
<svg
width="440"
height="440"
style="
transform: rotate(-90deg);
"
>
<circle
cx="220"
cy="220"
r="170"
stroke-width="8"
stroke="#D1D3D7"
fill="none"
></circle>
<circle
cx="220"
cy="220"
r="170"
stroke-width="8"
stroke="#00A5E0"
fill="none"
stroke-dasharray="534 1069"
></circle>
</svg>