<template>
|
<view ref="elePBar" class="zui-progress-bar" :style="style">
|
<view
|
:class="['zui-progress-bar-wrapper', ...barMode]"
|
:style="wrapperStyle"
|
>
|
<view class="zui-progress-bar-bar" :style="barStyle">
|
<view class="zui-progress-bar-inside"></view>
|
</view>
|
<view v-if="!disableValue" class="zui-progress-bar-value">{{
|
valueStr
|
}}</view>
|
</view>
|
</view>
|
</template>
|
|
<script>
|
// #ifndef H5
|
// 获取元素宽
|
const _getWidth = (query, selector) => {
|
return new Promise((resolve, reject) => {
|
query
|
.select(selector)
|
.fields({ size: true })
|
.exec((rst) => {
|
if (!rst) return resolve(0);
|
if (!rst[0]) return resolve(0);
|
const size = rst.pop();
|
resolve(size.width);
|
});
|
});
|
};
|
// #endif
|
|
export default {
|
name: "zui-progress-bar",
|
|
props: {
|
/**
|
* 宽度
|
*
|
* 默认:100%
|
*/
|
width: [String, Number],
|
|
height: {
|
type: Number,
|
default: 12,
|
},
|
|
/**
|
* 进度
|
*
|
* 默认:0
|
*/
|
value: String,
|
|
/**
|
* 不显示值
|
*/
|
disableValue: Boolean,
|
|
unit: {
|
type: String,
|
default: "%",
|
},
|
|
/**
|
* 样式
|
*
|
* left, inside-left
|
* center, inside-center
|
* right, inside-right
|
* outside-left
|
* outside-right
|
* follow-left
|
* follow-right
|
*/
|
type: {
|
type: String,
|
default: "right",
|
validator: () => true,
|
},
|
|
/**
|
* 圆角
|
*/
|
rounded: {
|
type: Boolean,
|
default: true,
|
},
|
|
/**
|
* 文字颜色
|
*/
|
color: {
|
type: [String, Array],
|
default: "#fff",
|
},
|
|
/**
|
* 开启反色
|
*/
|
invertColor: Boolean,
|
|
/**
|
* 颜色纹理
|
*/
|
texture: {
|
type: [String, Array],
|
default: undefined,
|
validator: () => true,
|
},
|
|
/**
|
* 预设模式
|
*/
|
preset: String,
|
},
|
|
data() {
|
return {
|
valuePosFix: 0,
|
};
|
},
|
|
computed: {
|
valueFixed() {
|
if (this.value < -1) return -1
|
if (this.value > 1) return 1
|
return this.value
|
},
|
|
textureLib() {
|
let texture;
|
if (typeof this.texture === "string") {
|
texture = [this.texture, "transparent"];
|
} else if (this.texture) {
|
texture = [...this.texture];
|
} else {
|
texture = ["#5fb878", "#eeeeee"];
|
}
|
return texture;
|
},
|
|
style() {
|
const style = {};
|
if (this.width) {
|
style.width =
|
typeof this.width === "string" ? this.width : `${this.width}px`;
|
}
|
return Object.keys(style)
|
.map((key) => `${key}:${style[key]}`)
|
.join(";");
|
},
|
|
wrapperStyle() {
|
const style = {
|
height: `${this.height}px`,
|
};
|
|
const fontSize = this.height > 14 ? this.height - 4 : 10;
|
style["font-size"] = `${fontSize}px`;
|
style["--zui-progress-bar-color"] = this.color;
|
|
style["--zui-progress-bar-value"] = `${this.valueFixed * 100}%`;
|
let fixedPos = this.valueFixed * 100;
|
if (this.type === "follow-left" && this.valuePosFix > fixedPos) {
|
fixedPos = this.valuePosFix;
|
} else if (this.type === "follow-right") {
|
const pos = 100 - this.valuePosFix;
|
if (fixedPos > pos) {
|
fixedPos = pos;
|
}
|
}
|
style["--zui-progress-bar-value-fixed"] = `${fixedPos}%`;
|
style["--zui-progress-bar-fg"] = this.textureLib[0];
|
style["--zui-progress-bar-bg"] = this.textureLib[1];
|
style["--zui-progress-bar-radius"] = this.rounded
|
? `${this.height / 2}px`
|
: "0";
|
|
style["--zui-progress-bar-invert"] = this.invertColor
|
? "difference"
|
: "none";
|
|
return Object.keys(style)
|
.map((key) => `${key}:${style[key]}`)
|
.join(";");
|
},
|
|
barStyle() {
|
const style = {
|
height:
|
typeof this.height === "string" ? this.height : `${this.height}px`,
|
};
|
|
return Object.keys(style)
|
.map((key) => `${key}:${style[key]}`)
|
.join(";");
|
},
|
|
barMode() {
|
const type = this.type.replace(/inside-/, "");
|
return [type, this.rounded && "rounded"];
|
},
|
|
valueStr() {
|
const val = Math.floor((this.valueFixed || 0) * 1000) / 10;
|
return `${val}${this.unit}`;
|
},
|
},
|
|
watch: {
|
value() {
|
this.$nextTick(() => {
|
this.fixValuePosition();
|
});
|
},
|
},
|
|
mounted() {
|
this.fixValuePosition();
|
},
|
|
methods: {
|
/**
|
* 修复 follow- 模式下文字的位置
|
*/
|
fixValuePosition() {
|
if (this.disableValue) return;
|
|
// #ifndef H5
|
const query = uni.createSelectorQuery().in(this);
|
Promise.all([
|
_getWidth(query, ".zui-progress-bar-bar"),
|
_getWidth(query, ".zui-progress-bar-value"),
|
]).then((resp) => {
|
if (!resp[0] || !resp[1]) return;
|
this.valuePosFix = ((resp[1] + 8) / resp[0]) * 100;
|
});
|
// #endif
|
|
// #ifdef H5
|
const dom = this.$refs.elePBar.$el;
|
if (!dom) return;
|
const bar = dom.querySelector(".zui-progress-bar-bar");
|
const val = dom.querySelector(".zui-progress-bar-value");
|
const barWidthPx = bar.getBoundingClientRect().width;
|
const valueWidthPx = val.getBoundingClientRect().width;
|
this.valuePosFix = (valueWidthPx / barWidthPx) * 100;
|
// #endif
|
},
|
},
|
};
|
</script>
|
|
<style scoped lang="scss">
|
.zui-progress-bar {
|
position: relative;
|
width: 100%;
|
margin: 4px 0;
|
}
|
.zui-progress-bar-wrapper {
|
display: flex;
|
justify-content: space-between;
|
align-items: center;
|
width: 100%;
|
}
|
|
.zui-progress-bar-bar {
|
width: 100%;
|
background: var(--zui-progress-bar-bg, "transparent");
|
}
|
.zui-progress-bar-inside {
|
height: 100%;
|
width: var(--zui-progress-bar-value, 0);
|
background: var(--zui-progress-bar-fg, --zui-progress-bar-fg-def);
|
}
|
|
.zui-progress-bar-bar,
|
.zui-progress-bar-inside,
|
.zui-progress-bar-value {
|
transition: all 0.1s ease-in-out;
|
background-size: auto 100%;
|
}
|
.zui-progress-bar-value {
|
color: var(--zui-progress-bar-color);
|
mix-blend-mode: var(--zui-progress-bar-invert, none);
|
}
|
|
.rounded {
|
.zui-progress-bar-bar,
|
.zui-progress-bar-inside {
|
border-radius: var(--zui-progress-bar-radius, 0);
|
overflow: hidden;
|
}
|
}
|
|
.left,
|
.inside-left {
|
.zui-progress-bar-value {
|
position: absolute;
|
padding: 0 4px;
|
left: 0;
|
top: 50%;
|
transform: translateY(-50%);
|
}
|
}
|
.center,
|
.inside-center {
|
.zui-progress-bar-value {
|
position: absolute;
|
left: 50%;
|
top: 50%;
|
transform: translate(-50%, -50%);
|
}
|
}
|
.right,
|
.inside-right {
|
.zui-progress-bar-value {
|
position: absolute;
|
padding: 0 4px;
|
right: 0;
|
top: 50%;
|
transform: translateY(-50%);
|
}
|
}
|
.outside-left {
|
flex-direction: row-reverse;
|
.zui-progress-bar-value {
|
margin-right: 4px;
|
}
|
}
|
.outside-right {
|
.zui-progress-bar-value {
|
margin-left: 4px;
|
}
|
}
|
|
.follow-left {
|
.zui-progress-bar-value {
|
position: absolute;
|
top: 50%;
|
left: var(--zui-progress-bar-value-fixed);
|
transform: translate(-100%, -50%);
|
padding: 0 4px;
|
}
|
}
|
.follow-right {
|
.zui-progress-bar-value {
|
position: absolute;
|
top: 50%;
|
left: var(--zui-progress-bar-value-fixed);
|
transform: translate(0, -50%);
|
padding: 0 4px;
|
}
|
}
|
</style>
|