@zhsz/cool-design-dv
Version:
265 lines (264 loc) • 7.84 kB
JavaScript
import { defineComponent, useAttrs, ref, computed, watch, onMounted, onBeforeUnmount, openBlock, createElementBlock, mergeProps, unref, renderSlot, createTextVNode, toDisplayString, createCommentVNode, createElementVNode, normalizeClass, createBlock } from "vue";
import "./baseNumber.css";
import { Icon } from "@iconify/vue";
import { CountUp } from "countup.js";
import { isObject } from "lodash-es";
const _hoisted_1 = {
key: 0,
class: "my-number__prefix"
};
const _hoisted_2 = {
key: 1,
class: "my-number__suffix"
};
const __default__ = defineComponent({
name: "baseNumber"
});
const _sfc_main = /* @__PURE__ */ defineComponent({
...__default__,
props: {
// 数字
value: [Number, String],
// 默认值
defaultValue: {
type: [Number, String],
default: 0
},
// CountUp配置参数对象
countUp: {
type: [Boolean, Object]
},
// 趋势
trend: {
type: String,
validator(val) {
return ["up", "down", "-"].includes(val);
}
},
// 精度,保留几位小数
precision: {
type: Number,
default: 0
},
// 分隔符
separator: {
type: String,
default: ","
},
// 前缀
prefix: {
type: String
},
// 后缀
suffix: String,
// 按百分比计算显示
percentage: Boolean,
// 颜色类型
type: {
type: String,
default: "",
validator(val) {
return ["", "primary", "success", "warning", "danger", "info"].includes(
val
);
}
},
// 前缀 和 后缀采用下标显示
sup: Boolean
},
emits: ["complete"],
setup(__props, { emit: __emit }) {
const props = __props;
const defaultCountUp = {
auto: true,
// 是否自动开始计数,默认为自动开始
startVal: 0,
// 计数初始值,不限正负数,默认值为0
decimalPlaces: 0,
// 计数器数值精度。默认值为0
duration: 2,
// 计数器动画持续时间,即计数器从开始到结束的时间,单位为秒,默认值为2秒
useEasing: true,
// 是否显示渐入渐出效果。默认值为显示
useGrouping: true,
// 计数器是否采用带格式的值,如10,000和10000两种格式(分隔符用separator来定义),默认值为使用
separator: ","
// 分隔值的符号,默认值为‘,’(英文逗号)
};
const $attrs = useAttrs();
const $emit = __emit;
const counter = ref();
const container = ref();
const displayValue = computed(() => {
if (!isNumber(props.value)) {
return props.defaultValue ? getPercent(props.defaultValue) : "";
}
if (props.percentage) {
return getPercent(props.value);
}
return format(props.value || "", props.precision, props.separator);
});
const trendClasses = computed(() => {
if (!props.trend)
return;
if (props.trend === "-") {
return "is-default";
}
return `is-${props.trend}`;
});
const classes = computed(() => {
return {
"my-number": true,
"is-pointer": $attrs.onClick,
[`is-${props.type}`]: !!props.type
};
});
computed(() => {
return {
"my-number__sup": !!props.sup
};
});
const countUpOptions = computed(() => {
if (props.countUp === true) {
return {
...defaultCountUp,
separator: props.separator,
decimalPlaces: props.precision
};
}
if (isObject(props.countUp)) {
return {
...defaultCountUp,
...props.countUp,
separator: props.separator,
decimalPlaces: props.precision
};
}
return null;
});
function init() {
var _a;
setCountUp();
if ((_a = countUpOptions.value) == null ? void 0 : _a.auto) {
start();
}
}
function setCountUp() {
if (counter.value) {
counter.value = null;
}
if (countUpOptions.value === null)
return;
counter.value = new CountUp(
container.value,
Number(props.value),
countUpOptions.value
);
}
function start() {
reset();
counter.value && counter.value.start(onComplete);
}
function reset() {
counter.value && counter.value.reset();
}
function update(num) {
if (num) {
counter.value && counter.value.update(num);
} else {
counter.value && counter.value.update(props.value);
}
}
function onComplete() {
$emit("complete");
}
function isNumber(n) {
const val = Number.parseFloat(String(n));
return !Number.isNaN(val) && Number.isFinite(val);
}
function getPercent(val) {
return props.percentage ? `${(Number.parseFloat(String(val)) * 100).toFixed(props.precision)}%` : val;
}
function format(val, n, separator) {
const s = Number.parseFloat(String(val).replace(/[^\d.-]/g, "")).toFixed(n) + "";
const l = s.split(".")[0].split("").reverse();
const r = s.split(".")[1];
let t = "";
for (let i = 0; i < l.length; i++) {
t += l[i] + ((i + 1) % 3 === 0 && i + 1 !== l.length ? `${separator}` : "");
}
return t.split("").reverse().join("") + (r ? `.${r}` : "");
}
watch(
() => props.value,
(val) => {
update(val);
}
);
watch(
() => countUpOptions.value,
() => {
if (!countUpOptions.value) {
return;
}
init();
}
);
onMounted(() => {
if (countUpOptions.value) {
init();
}
});
onBeforeUnmount(() => {
counter.value = null;
});
return (_ctx, _cache) => {
return openBlock(), createElementBlock("div", mergeProps({ class: classes.value }, unref($attrs)), [
__props.prefix || _ctx.$slots.prefix ? (openBlock(), createElementBlock("span", _hoisted_1, [
renderSlot(_ctx.$slots, "prefix", {}, () => [
createTextVNode(toDisplayString(__props.prefix), 1)
])
])) : createCommentVNode("", true),
createElementVNode("span", {
class: "my-number__value",
ref_key: "container",
ref: container
}, [
renderSlot(_ctx.$slots, "default", {
value: __props.value,
displayValue: displayValue.value
}, () => [
createTextVNode(toDisplayString(displayValue.value), 1)
])
], 512),
__props.suffix || _ctx.$slots.suffix ? (openBlock(), createElementBlock("span", _hoisted_2, [
renderSlot(_ctx.$slots, "suffix", {}, () => [
createTextVNode(toDisplayString(__props.suffix), 1)
])
])) : createCommentVNode("", true),
__props.trend || _ctx.$slots.trend ? (openBlock(), createElementBlock("span", {
key: 2,
class: normalizeClass(["my-number__trend", trendClasses.value])
}, [
renderSlot(_ctx.$slots, "trend", { trend: __props.trend }, () => [
__props.trend === "up" ? (openBlock(), createBlock(unref(Icon), {
key: 0,
icon: "icon-park-outline:arrow-up"
})) : createCommentVNode("", true),
__props.trend === "down" ? (openBlock(), createBlock(unref(Icon), {
key: 1,
icon: "icon-park-outline:arrow-down"
})) : createCommentVNode("", true),
__props.trend === "-" ? (openBlock(), createBlock(unref(Icon), {
key: 2,
icon: "icon-park-outline:minus"
})) : createCommentVNode("", true)
])
], 2)) : createCommentVNode("", true)
], 16);
};
}
});
export {
_sfc_main as default
};