@cqmcui/cqmcui
Version:
轻量级移动端 Vue2、Vue3 组件库(支持小程序开发)
256 lines (255 loc) • 6.87 kB
JavaScript
import { reactive, computed, onBeforeMount, watch, toRefs, openBlock, createElementBlock, normalizeClass, renderSlot } from "vue";
import { p as padZero, c as createComponent } from "./component-81a4c1d0.js";
import { _ as _export_sfc } from "./_plugin-vue_export-helper-cc2b3d55.js";
import "../locale/lang";
const getTimeStamp = (timeStr) => {
if (!timeStr)
return Date.now();
let t = timeStr;
t = t > 0 ? +t : t.toString().replace(/\-/g, "/");
return new Date(t).getTime();
};
const { componentName, create, translate } = createComponent("countdown");
const _sfc_main = create({
props: {
modelValue: {
type: Object,
default: () => {
return {};
}
},
paused: {
default: false,
type: Boolean
},
startTime: {
// 可以是服务器当前时间
type: [Number, String],
validator(v) {
const dateStr = new Date(v).toString().toLowerCase();
return dateStr !== "invalid date";
}
},
endTime: {
type: [Number, String],
validator(v) {
const dateStr = new Date(v).toString().toLowerCase();
return dateStr !== "invalid date";
}
},
// 是否开启毫秒
millisecond: {
default: false,
type: Boolean
},
// 时间格式化
format: {
type: String,
default: "HH:mm:ss"
},
autoStart: {
type: Boolean,
default: true
},
// 倒计时时长,单位毫秒
time: {
type: [Number, String],
default: 0
}
},
emits: ["input", "on-end", "on-restart", "on-paused", "update:modelValue"],
setup(props, { emit, slots }) {
const state = reactive({
restTime: 0,
// 倒计时剩余时间时间
timer: null,
counting: !props.paused && props.autoStart,
// 是否处于倒计时中
handleEndTime: Date.now(),
// 最终截止时间
diffTime: 0
// 设置了 startTime 时,与 date.now() 的差异
});
const classes = computed(() => {
const prefixCls = componentName;
return {
[prefixCls]: true
};
});
const renderTime = computed(() => {
return formatRemainTime(state.restTime);
});
const initTime = () => {
state.handleEndTime = props.endTime;
state.diffTime = Date.now() - getTimeStamp(props.startTime);
if (!state.counting)
state.counting = true;
tick();
};
const tick = () => {
if (window !== void 0) {
state.timer = requestAnimationFrame(() => {
if (state.counting) {
const currentTime = Date.now() - state.diffTime;
const remainTime = Math.max(state.handleEndTime - currentTime, 0);
state.restTime = remainTime;
if (!remainTime) {
state.counting = false;
pause();
emit("on-end");
}
if (remainTime > 0) {
tick();
}
}
});
}
};
const formatRemainTime = (t, type) => {
const ts = t;
let rest = {
d: 0,
h: 0,
m: 0,
s: 0,
ms: 0
};
const SECOND = 1e3;
const MINUTE = 60 * SECOND;
const HOUR = 60 * MINUTE;
const DAY = 24 * HOUR;
if (ts > 0) {
rest.d = ts >= SECOND ? Math.floor(ts / DAY) : 0;
rest.h = Math.floor(ts % DAY / HOUR);
rest.m = Math.floor(ts % HOUR / MINUTE);
rest.s = Math.floor(ts % MINUTE / SECOND);
rest.ms = Math.floor(ts % SECOND);
}
return type == "custom" ? rest : parseFormat({ ...rest });
};
const parseFormat = (time) => {
let { d, h, m, s, ms } = time;
let format = props.format;
if (format.includes("DD")) {
format = format.replace("DD", padZero(d));
} else {
h += Number(d) * 24;
}
if (format.includes("HH")) {
format = format.replace("HH", padZero(h));
} else {
m += Number(h) * 60;
}
if (format.includes("mm")) {
format = format.replace("mm", padZero(m));
} else {
s += Number(m) * 60;
}
if (format.includes("ss")) {
format = format.replace("ss", padZero(s));
} else {
ms += Number(s) * 1e3;
}
if (format.includes("S")) {
const msC = padZero(ms, 3).toString();
if (format.includes("SSS")) {
format = format.replace("SSS", msC);
} else if (format.includes("SS")) {
format = format.replace("SS", msC.slice(0, 2));
} else if (format.includes("S")) {
format = format.replace("SS", msC.slice(0, 1));
}
}
return format;
};
const start = () => {
if (!state.counting && !props.autoStart) {
state.counting = true;
state.handleEndTime = Date.now() + Number(state.restTime);
tick();
emit("on-restart", state.restTime);
}
};
const pause = () => {
cancelAnimationFrame(state.timer);
state.counting = false;
emit("on-paused", state.restTime);
};
const reset = () => {
if (!props.autoStart) {
pause();
state.restTime = props.time;
}
};
onBeforeMount(() => {
if (props.autoStart) {
initTime();
} else {
state.restTime = props.time;
}
});
watch(
() => state.restTime,
(value) => {
let tranTime = formatRemainTime(value, "custom");
emit("update:modelValue", tranTime);
emit("input", tranTime);
}
);
watch(
() => props.paused,
(v, ov) => {
if (!ov) {
if (state.counting) {
pause();
}
} else {
if (!state.counting) {
state.counting = true;
state.handleEndTime = Date.now() + Number(state.restTime);
tick();
}
emit("on-restart", state.restTime);
}
}
);
watch(
() => props.endTime,
(value) => {
initTime();
}
);
watch(
() => props.startTime,
(value) => {
initTime();
}
);
return {
...toRefs(props),
slots,
classes,
start,
pause,
renderTime,
translate,
reset
};
}
});
const _hoisted_1 = ["innerHTML"];
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
return openBlock(), createElementBlock("view", {
class: normalizeClass(_ctx.classes)
}, [
_ctx.slots.default ? renderSlot(_ctx.$slots, "default", { key: 0 }) : (openBlock(), createElementBlock("view", {
key: 1,
class: "cqmc-countdown__content",
innerHTML: _ctx.renderTime
}, null, 8, _hoisted_1))
], 2);
}
const index = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render]]);
export {
index as default
};