需求
UI图中有需要斜切图样的需求,一个进度条,并且进度项不定,是一个list类型。效果如图,以下就是一个三个元素的数组遍历生成的进度条:
第一次尝试
首先写进度条并不难,只需要以下结构:
// html
<div class="progress-outer">
<div v-for="(item,key) in items" :key="index" class="progress-inner" :style={'width': item.percent + '%','left': getLeft(index)}></div>
</div>
// css
.progress-outer {
position: relative;
width: 100%;
height: 30px;
}
.progress-inner {
position: absolute;
top: 0;
bottom: 0;
}
这里的getLeft函数是对前面元素的百分比进行累加。进度条的部分就完成了。现在主要是斜切样式部分的的难点。
首先想到的是使用过transform的skew对中间模块进行倾斜,空出来的部分进行遮盖。
skew() 函数定义了一个元素在二维平面上的倾斜转换
属性的传参参考这里。
中间元素设置一下样式:
transform: skew(-20deg);
border-width: 0;
border-left-width: 5px;
border-right-width: 5px;
border-color: #e9e9e9;
border-style: solid;
设置倾斜后会有倾斜的缝隙露出,我的解决办法是把中间元素的宽度调宽,并设置left的迁移量。
但我很快发现这个做法是不适用的,原因是当我的list数组是两个的时候,这时候没有中间元素来做分割,所以无法实现效果。
第二次尝试
skew无法实现单边斜切的效果,思路是除最后一个元素不加,给每个进度条加一个5px的子元素span绝对定位最右边,并进行rotate旋转,如下:
<div class="progress-outer">
<div v-for="(item,key) in items" :key="index" class="progress-inner" :style={'width': item.percent + '%','left': getLeft(index)}>
<span v-if="index !== items.length - 1" class="progress-inner_hr"></span>
</div>
</div>
// css
.progress-outer {
position: relative;
width: 100%;
height: 30px;
}
.progress-inner {
position: absolute;
top: 0;
bottom: 0;
}
.progress-inner_hr {
display: block;
width: 5px;
position: absolute;
top: 0;
bottom: 0;
left: 0;
background: #e9e9e9;
transform: rotate(-20deg);
}
但很快发现,只有一条斜线,并形成了一个直角三角形形状未遮盖。
第三次尝试
在第二次尝试的基础上发现,只需要有两个直角三角形组成的平行四边形就可以遮盖住左右两边多余的位置。
我们知道使用border可以实现三角形,那就比较好解决这种斜切问题了。
代码如下:
<div class="progress-outer">
<div v-for="(item,key) in items" :key="index" class="progress-inner" :style={'width': item.percent + '%','left': getLeft(index)}>
<span v-if="items.length > 1 && index !== 0" class="progress-inner_hr progress-inner_hr_left"></span>
<span v-if="items.length > 1 && index !== items.length - 1" class="progress-inner_hr progress-inner_hr_right"></span>
</div>
</div>
// css
.progress-outer {
position: relative;
width: 100%;
height: 30px;
}
.progress-inner {
position: absolute;
top: 0;
bottom: 0;
}
.progress-inner_hr {
position: absolute;
top: 0;
display: block;
width: 0;
height: 0;
// 边框实现直角三角形
border-style: solid;
}
.progress-inner_hr_left {
left: 0;
border-width: 0 0 30px 10px;
border-color: transparent transparent transparent #e9e9e9;
}
.progress-inner_hr_right {
right: 0;
border-width: 30px 10px 0 0;
border-color: transparent #e9e9e9 transparent transparent;
}
这样使用两个直角三角形组成的斜切解决了我想要的斜切,且兼容性高。
另外
在做这个样式的过程中了解到有一个新属性可以像svg那样设置坐标值来实现斜切效果:clip-path,使用polygon定义坐标实现单边斜切效果,但其兼容性差,慎重选择。
另外还可以使用background的渐变值来模拟实现斜切的效果。
这里对于这两种属性的实现代码就不多说了,我这里并未使用。
总结
方法千万种,实现斜切效果还是走了弯路才实现。这里记录下来为后面的人减少时间成本吧。