UNPKG

vxe-pc-ui

Version:
225 lines (224 loc) • 8.1 kB
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(); } });