204 lines
4.6 KiB
Vue
204 lines
4.6 KiB
Vue
|
<template>
|
||
|
<view>
|
||
|
<view class="flex a-center content" v-if="lineData">
|
||
|
<view>
|
||
|
<slot name="content"></slot>
|
||
|
</view>
|
||
|
</view>
|
||
|
<view class="flex a-center" style="padding-right: 10rpx">
|
||
|
<view
|
||
|
class="progress-container"
|
||
|
id="container"
|
||
|
ref="progressContainer"
|
||
|
:style="{ background: inBgColor }"
|
||
|
>
|
||
|
<view
|
||
|
class="progress-content flex j-end"
|
||
|
id="content"
|
||
|
ref="progressContent"
|
||
|
:style="{
|
||
|
height: strokeWidth + 'px',
|
||
|
background: bgColor,
|
||
|
width: contentWidth,
|
||
|
transition: `width ${duration / 1000}s ease`,
|
||
|
}"
|
||
|
v-if="isAnimate"
|
||
|
>
|
||
|
<view class="textInside flex a-center j-center" v-if="textInside && !noData">
|
||
|
<view class="text">{{ percentage }}%</view>
|
||
|
</view>
|
||
|
</view>
|
||
|
<view
|
||
|
v-if="!isAnimate"
|
||
|
class="progress-content flex j-end"
|
||
|
:style="{ width: percentage + '%', height: strokeWidth + 'px', background: bgColor }"
|
||
|
>
|
||
|
<view class="textInside flex a-center j-center" v-if="textInside && !noData">
|
||
|
<view class="text">{{ percentage }}%</view>
|
||
|
</view>
|
||
|
</view>
|
||
|
</view>
|
||
|
<view>
|
||
|
<view class="percentage" v-if="!textInside && !lineData && !noData && !isAnimate"
|
||
|
>{{ percentage }}%
|
||
|
</view>
|
||
|
</view>
|
||
|
</view>
|
||
|
</view>
|
||
|
</template>
|
||
|
|
||
|
<script>
|
||
|
export default {
|
||
|
name: 'AiProgress',
|
||
|
components: {},
|
||
|
props: {
|
||
|
// 进度条的值
|
||
|
percentage: {
|
||
|
type: [Number, String],
|
||
|
required: true,
|
||
|
},
|
||
|
// 是否内联显示数据
|
||
|
textInside: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
// 进度条高度
|
||
|
strokeWidth: {
|
||
|
type: [Number, String],
|
||
|
default: 6,
|
||
|
},
|
||
|
// 默认动画时长
|
||
|
duration: {
|
||
|
type: [Number, String],
|
||
|
default: 2000,
|
||
|
},
|
||
|
// 是否有动画
|
||
|
isAnimate: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
// 背景颜色
|
||
|
bgColor: {
|
||
|
type: String,
|
||
|
default: 'linear-gradient(90deg, var(--ui-BG-Main) 0%, var(--ui-BG-Main-gradient) 100%)',
|
||
|
},
|
||
|
// 是否不显示数据
|
||
|
noData: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
// 是否自定义显示内容
|
||
|
lineData: {
|
||
|
type: Boolean,
|
||
|
default: false,
|
||
|
},
|
||
|
// 自定义底色
|
||
|
inBgColor: {
|
||
|
type: String,
|
||
|
default: '#ebeef5',
|
||
|
},
|
||
|
},
|
||
|
data() {
|
||
|
return {
|
||
|
width: 0,
|
||
|
timer: null,
|
||
|
containerWidth: 0,
|
||
|
contentWidth: 0,
|
||
|
};
|
||
|
},
|
||
|
methods: {
|
||
|
start() {
|
||
|
if (this.isAnimate) {
|
||
|
// #ifdef H5
|
||
|
this.$nextTick(() => {
|
||
|
let progressContainer = this.$refs.progressContainer.$el;
|
||
|
let progressContent = this.$refs.progressContent.$el;
|
||
|
let style = window.getComputedStyle(progressContainer, null);
|
||
|
let width = style.width.replace('px', '') * ((this.percentage * 1) / 100);
|
||
|
progressContent.style.width = width.toFixed(2) + 'px';
|
||
|
progressContent.style.transition = `width ${this.duration / 1000}s ease`;
|
||
|
});
|
||
|
// #endif
|
||
|
const container = uni.createSelectorQuery().in(this).selectAll('#container');
|
||
|
const content = uni.createSelectorQuery().in(this).selectAll('#content');
|
||
|
container.boundingClientRect().exec((res1) => {
|
||
|
this.contentWidth =
|
||
|
res1[0][0].width * 1 * ((this.percentage * 1) / 100).toFixed(2) + 'px';
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
},
|
||
|
mounted() {
|
||
|
this.$nextTick(() => {
|
||
|
this.start();
|
||
|
});
|
||
|
},
|
||
|
created() {},
|
||
|
filters: {},
|
||
|
computed: {},
|
||
|
watch: {},
|
||
|
directives: {},
|
||
|
};
|
||
|
</script>
|
||
|
|
||
|
<style scoped lang="scss">
|
||
|
.content {
|
||
|
margin-bottom: 10px;
|
||
|
|
||
|
.c-per {
|
||
|
font-size: 26px;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.progress-container {
|
||
|
width: 100%;
|
||
|
border-radius: 100px;
|
||
|
|
||
|
.progress-content {
|
||
|
border-radius: 100px;
|
||
|
width: 0;
|
||
|
}
|
||
|
|
||
|
.textInside {
|
||
|
color: #fff;
|
||
|
margin-right: 10rpx;
|
||
|
position: relative;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
.text {
|
||
|
margin-left: 10rpx;
|
||
|
font-size: 16rpx;
|
||
|
width: 100rpx;
|
||
|
color: #FFB9B9;
|
||
|
}
|
||
|
|
||
|
.percentage {
|
||
|
margin-left: 6px;
|
||
|
font-size: 12px;
|
||
|
width: 30px;
|
||
|
}
|
||
|
|
||
|
.flex {
|
||
|
display: flex;
|
||
|
}
|
||
|
|
||
|
.a-center {
|
||
|
align-items: center;
|
||
|
}
|
||
|
|
||
|
.j-center {
|
||
|
justify-content: center;
|
||
|
}
|
||
|
|
||
|
.j-between {
|
||
|
justify-content: space-between;
|
||
|
}
|
||
|
|
||
|
.content {
|
||
|
margin-bottom: 10px;
|
||
|
color: #666;
|
||
|
font-size: 32rpx;
|
||
|
}
|
||
|
</style>
|