73 lines
1.8 KiB
TypeScript
73 lines
1.8 KiB
TypeScript
import moment from 'moment';
|
|
|
|
type RTimeElement = HTMLElement & { _next_timer?: number };
|
|
|
|
const parseInterval = (arg: string | undefined): number => {
|
|
if (!arg) {
|
|
return 60 * 1000;
|
|
}
|
|
|
|
const match = arg.match(/^(\d+)([smhd])$/);
|
|
|
|
if (!match) {
|
|
return 60 * 1000;
|
|
}
|
|
|
|
const [, numStr, unit] = match;
|
|
const num = parseInt(String(numStr), 10);
|
|
|
|
switch (unit) {
|
|
case 'd':
|
|
return num * 24 * 3600 * 1000;
|
|
case 'h':
|
|
return num * 3600 * 1000;
|
|
case 'm':
|
|
return num * 60 * 1000;
|
|
case 's':
|
|
return num * 1000;
|
|
default:
|
|
return 60 * 1000;
|
|
}
|
|
};
|
|
|
|
export default defineNuxtPlugin((nuxtApp) => {
|
|
nuxtApp.vueApp.directive('rtime', {
|
|
mounted(el: RTimeElement, binding) {
|
|
const intervalMs = parseInterval(binding.arg);
|
|
const update = () => {
|
|
const val = binding.value;
|
|
if (Number.isFinite(val)) {
|
|
el.textContent = moment.unix(val as number).fromNow();
|
|
return;
|
|
}
|
|
el.textContent = moment(val).fromNow();
|
|
};
|
|
|
|
update();
|
|
el._next_timer = window.setInterval(update, intervalMs);
|
|
},
|
|
updated(el: RTimeElement, binding) {
|
|
if (binding.oldValue !== binding.value) {
|
|
if (null != el._next_timer) clearInterval(el._next_timer);
|
|
|
|
const intervalMs = parseInterval(binding.arg);
|
|
const update = () => {
|
|
const val = binding.value;
|
|
if (Number.isFinite(val)) {
|
|
el.textContent = moment.unix(val as number).fromNow();
|
|
return;
|
|
}
|
|
el.textContent = moment(val).fromNow();
|
|
};
|
|
|
|
update();
|
|
el._next_timer = window.setInterval(update, intervalMs);
|
|
}
|
|
},
|
|
beforeUnmount(el: RTimeElement) {
|
|
if (null != el._next_timer) clearInterval(el._next_timer);
|
|
},
|
|
});
|
|
|
|
return {};
|
|
});
|