You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

204 lines
4.6 KiB

<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>