vxe-pc-ui
Version:
A vue based PC component library
225 lines (224 loc) • 8.1 kB
JavaScript
import { defineComponent, ref, h, reactive, watch, computed, onUnmounted, onMounted, createCommentVNode } from 'vue';
import { getConfig, getI18n, createEvent, useSize } from '../../ui';
import { getSlotVNs } from '../../ui/src/vn';
import VxeTextComponent from '../../text/src/text';
import XEUtils from 'xe-utils';
export default defineComponent({
name: 'VxeCountdown',
props: {
modelValue: [Number, String],
format: String,
prefixConfig: Object,
suffixConfig: Object,
size: {
type: String,
default: () => getConfig().countdown.size || getConfig().size
}
},
emits: [
'update:modelValue',
'start',
'end'
],
setup(props, context) {
const { slots, emit } = context;
const xID = XEUtils.uniqueId();
const refElem = ref();
const { computeSize } = useSize(props);
const reactData = reactive({
currNum: 0,
secondNum: 0
});
const internalData = {
dnTimeout: undefined
};
const refMaps = {
refElem
};
const computeTimeFormats = computed(() => {
const { secondNum } = reactData;
if (secondNum >= 31622400000) {
return ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss'];
}
if (secondNum >= 2678400000) {
return ['MM', 'dd', 'HH', 'mm', 'ss'];
}
if (secondNum >= 86400000) {
return ['dd', 'HH', 'mm', 'ss'];
}
if (secondNum >= 3600000) {
return ['HH', 'mm', 'ss'];
}
if (secondNum >= 60000) {
return ['mm', 'ss'];
}
return ['ss'];
});
const computeDiffConf = computed(() => {
const { currNum } = reactData;
return XEUtils.getDateDiff(Date.now(), Date.now() + currNum);
});
const computeFormatLabel = computed(() => {
const { format } = props;
const diffConf = computeDiffConf.value;
let rest = '';
if (format) {
rest = `${format}`;
XEUtils.each(diffConf, (val, key) => {
rest = rest.replace(new RegExp(key, 'g'), XEUtils.padStart(val, key.length, '0'));
});
return rest;
}
return rest;
});
const computePrefixOpts = computed(() => {
return Object.assign({}, props.prefixConfig, getConfig().countdown.prefixConfig);
});
const computeSuffixOpts = computed(() => {
return Object.assign({}, props.suffixConfig, getConfig().countdown.suffixConfig);
});
const computeMaps = {
computeSize
};
const $xeCountdown = {
xID,
props,
context,
reactData,
internalData,
getRefMaps: () => refMaps,
getComputeMaps: () => computeMaps
};
const dispatchEvent = (type, params, evnt) => {
emit(type, createEvent(evnt, { $carousel: $xeCountdown }, params));
};
const updateCount = () => {
const secondNum = XEUtils.toNumber(props.modelValue || 0);
reactData.secondNum = secondNum;
reactData.currNum = secondNum;
};
const handleTime = () => {
const { currNum } = reactData;
if (currNum > 1000) {
reactData.currNum -= 1000;
internalData.dnTimeout = setTimeout(() => {
handleTime();
}, 1000);
}
else {
reactData.currNum = 0;
handleStop();
}
};
const countdownMethods = {
dispatchEvent
};
const handleStart = () => {
dispatchEvent('start', {}, null);
handleTime();
};
const handleStop = () => {
const { dnTimeout } = internalData;
if (dnTimeout) {
clearTimeout(dnTimeout);
internalData.dnTimeout = undefined;
dispatchEvent('end', {}, null);
}
};
const countdownPrivateMethods = {};
Object.assign($xeCountdown, countdownMethods, countdownPrivateMethods);
const renderDefaultContentVNs = () => {
const { format } = props;
const timeFormats = computeTimeFormats.value;
const diffConf = computeDiffConf.value;
const formatLabel = computeFormatLabel.value;
if (format) {
return [
h('div', {
key: 'format',
class: 'vxe-countdown--content-format'
}, formatLabel)
];
}
return timeFormats.map((key, index) => {
return h('div', {
key: index,
class: 'vxe-countdown--content-item'
}, [
h('div', {
class: 'vxe-countdown--content-num'
}, `${diffConf[key] || 0}`),
h('div', {
class: 'vxe-countdown--content-unit'
}, getI18n(`vxe.countdown.formats.${key}`))
]);
});
};
const renderVN = () => {
const { prefixConfig, suffixConfig } = props;
const { currNum } = reactData;
const vSize = computeSize.value;
const diffConf = computeDiffConf.value;
const prefixOpts = computePrefixOpts.value;
const suffixOpts = computeSuffixOpts.value;
const prefixSlot = slots.prefix;
const suffixSlot = slots.suffix;
const defaultSlot = slots.default;
return h('div', {
ref: refElem,
class: ['vxe-countdown', diffConf.done ? 'is--progress' : 'is-end', {
[`size--${vSize}`]: vSize
}]
}, [
prefixSlot || prefixConfig
? h('div', {
class: 'vxe-countdown--prefix'
}, prefixSlot
? getSlotVNs(prefixSlot({ currentValue: currNum, diffConf }))
: [
h(VxeTextComponent, {
content: prefixOpts.content,
icon: prefixOpts.icon,
status: prefixOpts.status
})
])
: createCommentVNode(),
h('div', {
class: 'vxe-countdown--content'
}, defaultSlot
? getSlotVNs(defaultSlot({ currentValue: currNum, diffConf }))
: renderDefaultContentVNs()),
suffixSlot || suffixConfig
? h('div', {
class: 'vxe-countdown--suffix'
}, suffixSlot
? getSlotVNs(suffixSlot({ currentValue: currNum, diffConf }))
: [
h(VxeTextComponent, {
content: suffixOpts.content,
icon: suffixOpts.icon,
status: suffixOpts.status
})
])
: createCommentVNode()
]);
};
watch(() => props.modelValue, () => {
updateCount();
handleStop();
handleStart();
});
onUnmounted(() => {
handleStop();
});
onMounted(() => {
handleStart();
});
updateCount();
$xeCountdown.renderVN = renderVN;
return $xeCountdown;
},
render() {
return this.renderVN();
}
});