基于vue+ts的平行四边形进度条
// 子组件部分
<template>
<div style="position: relative">
<!-- 带正负 -->
<div v-if="data.isCenter" style="position: relative">
// 绑定id 做唯一标识
<div class="progress-bar-wrap" :id="data.id">
// 对于初始结点0在中间的进度条,可以分割左右两部分,分别进行渲染
// 左侧底部部分,如果值为负数,那么左侧底部为传进来的bg颜色
// 如果值为正数,那么左侧背景色为透明,渲染border-color为传进来的bg颜色
<div
class="progress-bar-container-left-wrap"
:style="{'background': data.value > 0 ? '#fff0': data.bg,
'border-color': data.value > 0 ? data.bg : '#fff0'
}"
></div>
// 右侧底图部分 背景色和border-color的渲染规则与正好相反
<div
class="progress-bar-container-right-wrap"
:style="{'background': data.value > 0 ? data.bg : '#fff0',
'border-color': data.value > 0 ? '#fff0' : data.bg
}"
></div>
</div>
// 真实值的渲染,渲染父组件传过来的valueBG,以及值对应的宽度(百分比)
<div class="progress-value-wrap"
:style="{'background': data.valueBG, width: widthPer}"
:class="data.value > 0 ? 'isRightCenter' : 'isLeftCenter'"
>
<div class="progress-value-container-wrap"></div>
</div>
// 中间的数字0,判断是在左侧展示还是右侧展示
<div
:class="data.value > 0 ? 'center-num-right' : 'center-num-left'"
class="center-num"
>0</div>
</div>
<!-- 从左侧为0开始计数 -->
<div v-if="!data.isCenter">
// 底层背景色的渲染
<div class="progress-bar-wrap" :style="{'background': data.bg}">
<div class="progress-bar-container-wrap"></div>
</div>
// 值的渲染
<div class="progress-value-wrap" :style="{'background': data.valueBG, width: widthPer}">
<div class="progress-value-container-wrap"></div>
</div>
</div>
</div>
</template>
js部分
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator"
@Component({})
export default class RealInfo extends Vue {
@Prop({
required: true,
default: {
id: 'id',
bg: '#8a2be2', // 底色
valueBG: '#eeeeee', // 值部分的底色
isCenter: true, // 判断初始值0 是在中心还是左侧, true代表在中心, false代表在左侧
value: 0 // 值
}
})data
// 计算值所占的宽度
get widthPer() {
let absVal = Math.abs(this.data.value)
switch(true) {
case val < 100:
return absVal + '%'
break;
case val < 1000:
return absVal / 1000 * 100 + '%'
break;
case val < 10000:
return absVal / 10000 * 100 + '%'
break;
}
}
}
</script>
css部分
<style lang="less" scoped>
.progress-bar-wrap {
width: 100%;
height: 20px;
transform: skewX(-10deg);
.progress-bar-container-left-wrap,
.progress-bar-container-right-wrap {
display: inline-block;
width: 50%;
height: 100%;
border: 1px solid black;
}
.progress-bar-container-wrap {
width: 20%;
height: 100%;
}
}
.progress-value-wrap {
position: absolute;
z-index: 9;
height: 20px;
top: 0;
transform: skewX(-10deg);
.progress-value-container-wrap {
transform: skewX(10deg);
}
}
.isRightCenter {
left: 48%;
}
.isLeftCenter {
right: 50%;
}
.center-num {
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
color: #ffffff;
}
.center-num-right {
right: 50%;
}
.center-num-left {
left: 55%;
}
</style>
父组件
<template>
<ProgressBar :data="videoXProp" />
<ProgressBar :data="videoYProp" />
<ProgressBar :data="videoZProp" />
</template>
<script lang="ts">
import { Component, Prop, Vue, Watch } from "vue-property-decorator"
import ProgressBar from '@/components/chart/progressBar.vue'
@Component({
components: { ProgressBar }
})
export default class RealInfo extends Vue {
videoXProp: any = {
id: 'videoXId',
bg: '#AD9358',
valueBG: '#F8B05F',
isCenter: true,
value: 45
}
videoYProp: any = {
id: 'videoYId',
bg: '#AD9358',
valueBG: '#F8B05F',
isCenter: true,
value: -30
}
videoZProp: any = {
id: 'videoYId',
bg: '#AD9358',
valueBG: '#F8B05F',
isCenter: false,
value: 34
}
}