Today we are encapsulating a progress bar component like the one below
Functional requirements
- The total number of progress bars can be customized
- The percentage of the current number of items corresponds to the current number of blue boxes
- The blue gradient of the grid should match the UI design
Other functions are easy to do, is this gradient processing waste for a long time, the following look at my implementation ideas, god do not spray ah, behind the source code
First determine the values inside the props, which the component needs to receive
There are only names, totals, and current values
props:{
name: {type:String.default:() = >('Data name')},total: {type:Number.default:() = >(24)},value: {type:Number.default:() = >(18)}},Copy the code
Then there is the main implementation, which takes a cubeCount as an argument that defines the total number of cells
methods:{
initStatus(cubeCount){
//1. Get the width of the total grid div
let totalDomWidth=this.$refs.total.offsetWidth;
//2. Calculate the ratio of the current grid
let ratio=(this.value/this.total);
//3. Calculate the width of each grid
let cubeWidth=Math.floor((totalDomWidth/cubeCount)-1); }},Copy the code
When calculating the width of each cell, math. floor is rounded down, and -1 is the spacing between cells
Then, based on the width of each grid and the number of grids, dynamically generate the total grid and insert it into the div
for(let i=0; i<cubeCount; i++){let cubeDom=document.createElement('span');
cubeDom.style.background='#0F3D61'
cubeDom.style.width=cubeWidth+'px'
this.$refs.total.appendChild(cubeDom)
}
Copy the code
And then I’m going to figure out how many cells the current number occupies based on the ratio that I calculated before, and I’m going to round it down
let nowCubeCount=Math.floor(cubeCount*ratio);
Copy the code
Then there’s the tricky gradient treatment, where I just take the color of the first cell and the last cell, and use an array to calculate the difference
let startColor=[16.139.247]; / / RGB (16139247).
let endColor=[15.218.250]; / / RGB (15218250).
let perDiffColor=[];
/* Here we subtract the beginning color from the end color to get the total color difference and divide by the current number of cells into smaller color difference values, keeping three decimal places and converting them to numbers. Then we store the corresponding color difference value of each cell into the perDiffColor array */
for(let i=0; i<endColor.length; i++){ perDiffColor.push(Number(((endColor[i]-startColor[i])/nowCubeCount).toFixed(3)))}Copy the code
Next, set the background color to the current number of cells, that is, the original color + the subscript of the preceding cells * the color difference of each cell, and the component is nearly complete
// Get all the previous boxes
cubeDomArr=this.$refs.total.children;
// Set the color for the current grid
for(let i=0; i<nowCubeCount; i++){ cubeDomArr[i].style.background=`RGB(
${startColor[0]+i*perDiffColor[0]}.${startColor[1]+i*perDiffColor[1]}.${startColor[2]+i*perDiffColor[2]})
`
}
Copy the code
Then go to use to see, the effect is as follows:
<ioc-dataItem
name="This should be the current data name."
total=1267
value=500
></ioc-dataItem>
Copy the code
The source code is as follows (mixin. SCSS style file is not in, I believe you can write it yourself)
<template>
<div class="box">
<div class="name" >{{name}}</div>
<div class="value" >
{{value}}
<span>a</span>
</div>
<div class="total" ref="total"></div>
</div></template> <script> export default { name: "DataItem", props: {name: {type: String, the default () = > (' data name ')}, total: {type: Number, default: () = > (24)}, value:{ type:Number, default:()=>(18) }, }, data(){ return{ }; }, mounted(){ let that=this this.initStatus(16); }, updated() { this.initStatus(16); }, methods:{ initStatus(cubeCount){ let that=this; let totalDomWidth=this.$refs.total.offsetWidth; let ratio=(this.value/this.total); let cubeWidth=Math.floor((totalDomWidth/cubeCount)-1); let cubeDomArr; for(let i=0; i<cubeCount; i++){ let cubeDom=document.createElement('span'); cubeDom.style.background='#0F3D61' cubeDom.style.width=cubeWidth+'px' this.$refs.total.appendChild(cubeDom) } let nowCubeCount=Math.floor(cubeCount*ratio); cubeDomArr=this.$refs.total.children; Let startColor = [16139247]; Let endColor = [15218250]; let perDiffColor=[]; for(let i=0; i<endColor.length; i++){ perDiffColor.push( Number(((endColor[i]-startColor[i])/nowCubeCount).toFixed(3))) } for(let i=0; i<nowCubeCount; i++){ cubeDomArr[i].style.background= `RGB( ${startColor[0]+i*perDiffColor[0]}, ${startColor[1]+i*perDiffColor[1]}, ${startColor[2]+i*perDiffColor[2]}) ` } }, }, } </script> <style lang="scss" scoped> @import "./packages/common/style/mixin.scss"; .box{ width: px2vw(540); height: px2vh(58); position: relative; } .box .name{ position: absolute; font-size: px2font(23); color: #fff; left: 0; top: 0; } .box .total{ position: absolute; left: 0; bottom: 0; width: 100%; height: px2vh(15); // border-radius: px2vh(7); // background-color:#0F3F63; // border: 1px solid red; display: flex; justify-content: space-between; } .box .value{ position: absolute; color: #fff; font-size: px2font(30); right: 0; top: 0; } .box .value span{ font-size: px2font(23); } </style>Copy the code