xc-app/components/ai-progress/ai-progress.vue

177 lines
4.1 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: 0;">
<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>{{ 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: '#15B9D0'
},
// 是否不显示数据
noData: {
type: Boolean,
default: false
},
// 是否自定义显示内容
lineData: {
type: Boolean,
default: false
},
// 自定义底色
inBgColor: {
type: String,
default: '#DCDADA'
}
},
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: 10rpx;
.c-per {
font-size: 26rpx;
}
}
.progress-container {
width: 100%;
border-radius: 100rpx;
.progress-content {
border-radius: 100rpx;
width: 0;
}
.textInside {
color: #fff;
margin-right: 10rpx;
position: relative;
}
}
.text {
margin-left: 10rpx;
}
.percentage {
margin-left: 6rpx;
font-size: 12rpx;
width: 30rpx;
}
.flex {
display: flex;
}
.a-center {
align-items: center;
}
.j-center {
justify-content: center;
}
.j-between {
justify-content: space-between;
}
.content {
margin-bottom: 10rpx;
color: #666;
font-size: 32rpx;
}
</style>