refactor(client): extract interval logic to a composable function

あと`onUnmounted`を`onMounted`内で呼んでいたりしたのを修正したりとか
This commit is contained in:
syuilo 2022-06-26 03:12:58 +09:00
parent 6a4574b612
commit 5e95a1f7af
18 changed files with 207 additions and 183 deletions

View File

@ -3,7 +3,8 @@
<div class="label" @click="focus"><slot name="label"></slot></div> <div class="label" @click="focus"><slot name="label"></slot></div>
<div class="input" :class="{ inline, disabled, focused }"> <div class="input" :class="{ inline, disabled, focused }">
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div> <div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
<input ref="inputEl" <input
ref="inputEl"
v-model="v" v-model="v"
v-adaptive-border v-adaptive-border
:type="type" :type="type"
@ -34,8 +35,9 @@
<script lang="ts"> <script lang="ts">
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue'; import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
import MkButton from '@/components/ui/button.vue';
import { debounce } from 'throttle-debounce'; import { debounce } from 'throttle-debounce';
import MkButton from '@/components/ui/button.vue';
import { useInterval } from '@/scripts/use-interval';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -44,45 +46,45 @@ export default defineComponent({
props: { props: {
modelValue: { modelValue: {
required: true required: true,
}, },
type: { type: {
type: String, type: String,
required: false required: false,
}, },
required: { required: {
type: Boolean, type: Boolean,
required: false required: false,
}, },
readonly: { readonly: {
type: Boolean, type: Boolean,
required: false required: false,
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,
required: false required: false,
}, },
pattern: { pattern: {
type: String, type: String,
required: false required: false,
}, },
placeholder: { placeholder: {
type: String, type: String,
required: false required: false,
}, },
autofocus: { autofocus: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
autocomplete: { autocomplete: {
required: false required: false,
}, },
spellcheck: { spellcheck: {
required: false required: false,
}, },
step: { step: {
required: false required: false,
}, },
datalist: { datalist: {
type: Array, type: Array,
@ -91,17 +93,17 @@ export default defineComponent({
inline: { inline: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
debounce: { debounce: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
manualSave: { manualSave: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
}, },
@ -134,7 +136,7 @@ export default defineComponent({
const updated = () => { const updated = () => {
changed.value = false; changed.value = false;
if (type?.value === 'number') { if (type.value === 'number') {
context.emit('update:modelValue', parseFloat(v.value)); context.emit('update:modelValue', parseFloat(v.value));
} else { } else {
context.emit('update:modelValue', v.value); context.emit('update:modelValue', v.value);
@ -159,30 +161,29 @@ export default defineComponent({
invalid.value = inputEl.value.validity.badInput; invalid.value = inputEl.value.validity.badInput;
}); });
//
// 0
useInterval(() => {
if (prefixEl.value) {
if (prefixEl.value.offsetWidth) {
inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
}
}
if (suffixEl.value) {
if (suffixEl.value.offsetWidth) {
inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
}
}
}, 100, {
immediate: true,
afterMounted: true,
});
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
if (autofocus.value) { if (autofocus.value) {
focus(); focus();
} }
//
// 0
const clock = window.setInterval(() => {
if (prefixEl.value) {
if (prefixEl.value.offsetWidth) {
inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
}
}
if (suffixEl.value) {
if (suffixEl.value.offsetWidth) {
inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
}
}
}, 100);
onUnmounted(() => {
window.clearInterval(clock);
});
}); });
}); });

View File

@ -24,31 +24,31 @@ export default defineComponent({
modelValue: { modelValue: {
type: Number, type: Number,
required: false, required: false,
default: 0 default: 0,
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
min: { min: {
type: Number, type: Number,
required: false, required: false,
default: 0 default: 0,
}, },
max: { max: {
type: Number, type: Number,
required: false, required: false,
default: 100 default: 100,
}, },
step: { step: {
type: Number, type: Number,
required: false, required: false,
default: 1 default: 1,
}, },
autofocus: { autofocus: {
type: Boolean, type: Boolean,
required: false required: false,
}, },
textConverter: { textConverter: {
type: Function, type: Function,
@ -90,14 +90,18 @@ export default defineComponent({
} }
}; };
watch([steppedValue, containerEl], calcThumbPosition); watch([steppedValue, containerEl], calcThumbPosition);
let ro: ResizeObserver | undefined;
onMounted(() => { onMounted(() => {
const ro = new ResizeObserver((entries, observer) => { ro = new ResizeObserver((entries, observer) => {
calcThumbPosition(); calcThumbPosition();
}); });
ro.observe(containerEl.value); ro.observe(containerEl.value);
onUnmounted(() => { });
ro.disconnect();
}); onUnmounted(() => {
if (ro) ro.disconnect();
}); });
const steps = computed(() => { const steps = computed(() => {

View File

@ -3,7 +3,8 @@
<div class="label" @click="focus"><slot name="label"></slot></div> <div class="label" @click="focus"><slot name="label"></slot></div>
<div ref="container" class="input" :class="{ inline, disabled, focused }" @click.prevent="onClick"> <div ref="container" class="input" :class="{ inline, disabled, focused }" @click.prevent="onClick">
<div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div> <div ref="prefixEl" class="prefix"><slot name="prefix"></slot></div>
<select ref="inputEl" <select
ref="inputEl"
v-model="v" v-model="v"
v-adaptive-border v-adaptive-border
class="select" class="select"
@ -29,6 +30,7 @@
import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, VNode } from 'vue'; import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs, VNode } from 'vue';
import MkButton from '@/components/ui/button.vue'; import MkButton from '@/components/ui/button.vue';
import * as os from '@/os'; import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
export default defineComponent({ export default defineComponent({
components: { components: {
@ -37,38 +39,38 @@ export default defineComponent({
props: { props: {
modelValue: { modelValue: {
required: true required: true,
}, },
required: { required: {
type: Boolean, type: Boolean,
required: false required: false,
}, },
readonly: { readonly: {
type: Boolean, type: Boolean,
required: false required: false,
}, },
disabled: { disabled: {
type: Boolean, type: Boolean,
required: false required: false,
}, },
placeholder: { placeholder: {
type: String, type: String,
required: false required: false,
}, },
autofocus: { autofocus: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
inline: { inline: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
manualSave: { manualSave: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false default: false,
}, },
}, },
@ -109,30 +111,29 @@ export default defineComponent({
invalid.value = inputEl.value.validity.badInput; invalid.value = inputEl.value.validity.badInput;
}); });
//
// 0
useInterval(() => {
if (prefixEl.value) {
if (prefixEl.value.offsetWidth) {
inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
}
}
if (suffixEl.value) {
if (suffixEl.value.offsetWidth) {
inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
}
}
}, 100, {
immediate: true,
afterMounted: true,
});
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
if (autofocus.value) { if (autofocus.value) {
focus(); focus();
} }
//
// 0
const clock = window.setInterval(() => {
if (prefixEl.value) {
if (prefixEl.value.offsetWidth) {
inputEl.value.style.paddingLeft = prefixEl.value.offsetWidth + 'px';
}
}
if (suffixEl.value) {
if (suffixEl.value.offsetWidth) {
inputEl.value.style.paddingRight = suffixEl.value.offsetWidth + 'px';
}
}
}, 100);
onUnmounted(() => {
window.clearInterval(clock);
});
}); });
}); });

View File

@ -24,14 +24,14 @@ let now = $ref(new Date());
const relative = $computed(() => { const relative = $computed(() => {
const ago = (now.getTime() - _time.getTime()) / 1000/*ms*/; const ago = (now.getTime() - _time.getTime()) / 1000/*ms*/;
return ( return (
ago >= 31536000 ? i18n.t('_ago.yearsAgo', { n: Math.round(ago / 31536000).toString() }) : ago >= 31536000 ? i18n.t('_ago.yearsAgo', { n: Math.round(ago / 31536000).toString() }) :
ago >= 2592000 ? i18n.t('_ago.monthsAgo', { n: Math.round(ago / 2592000).toString() }) : ago >= 2592000 ? i18n.t('_ago.monthsAgo', { n: Math.round(ago / 2592000).toString() }) :
ago >= 604800 ? i18n.t('_ago.weeksAgo', { n: Math.round(ago / 604800).toString() }) : ago >= 604800 ? i18n.t('_ago.weeksAgo', { n: Math.round(ago / 604800).toString() }) :
ago >= 86400 ? i18n.t('_ago.daysAgo', { n: Math.round(ago / 86400).toString() }) : ago >= 86400 ? i18n.t('_ago.daysAgo', { n: Math.round(ago / 86400).toString() }) :
ago >= 3600 ? i18n.t('_ago.hoursAgo', { n: Math.round(ago / 3600).toString() }) : ago >= 3600 ? i18n.t('_ago.hoursAgo', { n: Math.round(ago / 3600).toString() }) :
ago >= 60 ? i18n.t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) : ago >= 60 ? i18n.t('_ago.minutesAgo', { n: (~~(ago / 60)).toString() }) :
ago >= 10 ? i18n.t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) : ago >= 10 ? i18n.t('_ago.secondsAgo', { n: (~~(ago % 60)).toString() }) :
ago >= -1 ? i18n.ts._ago.justNow : ago >= -1 ? i18n.ts._ago.justNow :
i18n.ts._ago.future); i18n.ts._ago.future);
}); });
@ -50,7 +50,7 @@ if (props.mode === 'relative' || props.mode === 'detail') {
tickId = window.requestAnimationFrame(tick); tickId = window.requestAnimationFrame(tick);
onUnmounted(() => { onUnmounted(() => {
window.clearTimeout(tickId); window.cancelAnimationFrame(tickId);
}); });
} }
</script> </script>

View File

@ -29,6 +29,7 @@
import { onUnmounted, watch } from 'vue'; import { onUnmounted, watch } from 'vue';
import { v4 as uuid } from 'uuid'; import { v4 as uuid } from 'uuid';
import tinycolor from 'tinycolor2'; import tinycolor from 'tinycolor2';
import { useInterval } from '@/scripts/use-interval';
const props = defineProps<{ const props = defineProps<{
src: number[]; src: number[];
@ -65,9 +66,8 @@ function draw(): void {
watch(() => props.src, draw, { immediate: true }); watch(() => props.src, draw, { immediate: true });
// VueWatch // VueWatch
clock = window.setInterval(draw, 1000); useInterval(draw, 1000, {
immediate: false,
onUnmounted(() => { afterMounted: true,
window.clearInterval(clock);
}); });
</script> </script>

View File

@ -112,9 +112,12 @@ export default defineComponent({
const elRef = ref<HTMLElement>(null); const elRef = ref<HTMLElement>(null);
const reactionRef = ref(null); const reactionRef = ref(null);
let readObserver: IntersectionObserver | undefined;
let connection;
onMounted(() => { onMounted(() => {
if (!props.notification.isRead) { if (!props.notification.isRead) {
const readObserver = new IntersectionObserver((entries, observer) => { readObserver = new IntersectionObserver((entries, observer) => {
if (!entries.some(entry => entry.isIntersecting)) return; if (!entries.some(entry => entry.isIntersecting)) return;
stream.send('readNotification', { stream.send('readNotification', {
id: props.notification.id, id: props.notification.id,
@ -124,20 +127,20 @@ export default defineComponent({
readObserver.observe(elRef.value); readObserver.observe(elRef.value);
const connection = stream.useChannel('main'); connection = stream.useChannel('main');
connection.on('readAllNotifications', () => readObserver.disconnect()); connection.on('readAllNotifications', () => readObserver.disconnect());
watch(props.notification.isRead, () => { watch(props.notification.isRead, () => {
readObserver.disconnect(); readObserver.disconnect();
}); });
onUnmounted(() => {
readObserver.disconnect();
connection.dispose();
});
} }
}); });
onUnmounted(() => {
if (readObserver) readObserver.disconnect();
if (connection) connection.dispose();
});
const followRequestDone = ref(false); const followRequestDone = ref(false);
const groupInviteDone = ref(false); const groupInviteDone = ref(false);

View File

@ -60,8 +60,10 @@ const onNotification = (notification) => {
} }
}; };
let connection;
onMounted(() => { onMounted(() => {
const connection = stream.useChannel('main'); connection = stream.useChannel('main');
connection.on('notification', onNotification); connection.on('notification', onNotification);
connection.on('readAllNotifications', () => { connection.on('readAllNotifications', () => {
if (pagingComponent.value) { if (pagingComponent.value) {
@ -87,10 +89,10 @@ onMounted(() => {
} }
} }
}); });
});
onUnmounted(() => { onUnmounted(() => {
connection.dispose(); if (connection) connection.dispose();
});
}); });
</script> </script>

View File

@ -27,18 +27,19 @@ import { sum } from '@/scripts/array';
import { pleaseLogin } from '@/scripts/please-login'; import { pleaseLogin } from '@/scripts/please-login';
import * as os from '@/os'; import * as os from '@/os';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { useInterval } from '@/scripts/use-interval';
export default defineComponent({ export default defineComponent({
props: { props: {
note: { note: {
type: Object, type: Object,
required: true required: true,
}, },
readOnly: { readOnly: {
type: Boolean, type: Boolean,
required: false, required: false,
default: false, default: false,
} },
}, },
setup(props) { setup(props) {
@ -54,7 +55,7 @@ export default defineComponent({
s: Math.floor(remaining.value % 60), s: Math.floor(remaining.value % 60),
m: Math.floor(remaining.value / 60) % 60, m: Math.floor(remaining.value / 60) % 60,
h: Math.floor(remaining.value / 3600) % 24, h: Math.floor(remaining.value / 3600) % 24,
d: Math.floor(remaining.value / 86400) d: Math.floor(remaining.value / 86400),
})); }));
const showResult = ref(props.readOnly || isVoted.value); const showResult = ref(props.readOnly || isVoted.value);
@ -68,10 +69,9 @@ export default defineComponent({
} }
}; };
tick(); useInterval(tick, 3000, {
const intevalId = window.setInterval(tick, 3000); immediate: true,
onUnmounted(() => { afterMounted: false,
window.clearInterval(intevalId);
}); });
} }

View File

@ -33,7 +33,8 @@
</svg> </svg>
--> -->
<svg v-for="particle in particles" :key="particle.id" :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`" xmlns="http://www.w3.org/2000/svg"> <svg v-for="particle in particles" :key="particle.id" :width="width" :height="height" :viewBox="`0 0 ${width} ${height}`" xmlns="http://www.w3.org/2000/svg">
<path style="transform-origin: center; transform-box: fill-box;" <path
style="transform-origin: center; transform-box: fill-box;"
:transform="`translate(${particle.x} ${particle.y})`" :transform="`translate(${particle.x} ${particle.y})`"
:fill="particle.color" :fill="particle.color"
d="M29.427,2.011C29.721,0.83 30.782,0 32,0C33.218,0 34.279,0.83 34.573,2.011L39.455,21.646C39.629,22.347 39.991,22.987 40.502,23.498C41.013,24.009 41.653,24.371 42.354,24.545L61.989,29.427C63.17,29.721 64,30.782 64,32C64,33.218 63.17,34.279 61.989,34.573L42.354,39.455C41.653,39.629 41.013,39.991 40.502,40.502C39.991,41.013 39.629,41.653 39.455,42.354L34.573,61.989C34.279,63.17 33.218,64 32,64C30.782,64 29.721,63.17 29.427,61.989L24.545,42.354C24.371,41.653 24.009,41.013 23.498,40.502C22.987,39.991 22.347,39.629 21.646,39.455L2.011,34.573C0.83,34.279 0,33.218 0,32C0,30.782 0.83,29.721 2.011,29.427L21.646,24.545C22.347,24.371 22.987,24.009 23.498,23.498C24.009,22.987 24.371,22.347 24.545,21.646L29.427,2.011Z" d="M29.427,2.011C29.721,0.83 30.782,0 32,0C33.218,0 34.279,0.83 34.573,2.011L39.455,21.646C39.629,22.347 39.991,22.987 40.502,23.498C41.013,24.009 41.653,24.371 42.354,24.545L61.989,29.427C63.17,29.721 64,30.782 64,32C64,33.218 63.17,34.279 61.989,34.573L42.354,39.455C41.653,39.629 41.013,39.991 40.502,40.502C39.991,41.013 39.629,41.653 39.455,42.354L34.573,61.989C34.279,63.17 33.218,64 32,64C30.782,64 29.721,63.17 29.427,61.989L24.545,42.354C24.371,41.653 24.009,41.013 23.498,40.502C22.987,39.991 22.347,39.629 21.646,39.455L2.011,34.573C0.83,34.279 0,33.218 0,32C0,30.782 0.83,29.721 2.011,29.427L21.646,24.545C22.347,24.371 22.987,24.009 23.498,23.498C24.009,22.987 24.371,22.347 24.545,21.646L29.427,2.011Z"
@ -73,14 +74,15 @@ export default defineComponent({
const width = ref(0); const width = ref(0);
const height = ref(0); const height = ref(0);
const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202']; const colors = ['#FF1493', '#00FFFF', '#FFE202', '#FFE202', '#FFE202'];
let stop = false;
let ro: ResizeObserver | undefined;
onMounted(() => { onMounted(() => {
const ro = new ResizeObserver((entries, observer) => { ro = new ResizeObserver((entries, observer) => {
width.value = el.value?.offsetWidth + 64; width.value = el.value?.offsetWidth + 64;
height.value = el.value?.offsetHeight + 64; height.value = el.value?.offsetHeight + 64;
}); });
ro.observe(el.value); ro.observe(el.value);
let stop = false;
const add = () => { const add = () => {
if (stop) return; if (stop) return;
const x = (Math.random() * (width.value - 64)); const x = (Math.random() * (width.value - 64));
@ -104,10 +106,11 @@ export default defineComponent({
}, 500 + (Math.random() * 500)); }, 500 + (Math.random() * 500));
}; };
add(); add();
onUnmounted(() => { });
ro.disconnect();
stop = true; onUnmounted(() => {
}); if (ro) ro.disconnect();
stop = true;
}); });
return { return {

View File

@ -18,6 +18,7 @@
import { onMounted, onUnmounted, ref } from 'vue'; import { onMounted, onUnmounted, ref } from 'vue';
import MkMiniChart from '@/components/mini-chart.vue'; import MkMiniChart from '@/components/mini-chart.vue';
import * as os from '@/os'; import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
const instances = ref([]); const instances = ref([]);
const charts = ref([]); const charts = ref([]);
@ -34,15 +35,9 @@ const fetch = async () => {
fetching.value = false; fetching.value = false;
}; };
let intervalId; useInterval(fetch, 1000 * 60, {
immediate: true,
onMounted(() => { afterMounted: true,
fetch();
intervalId = window.setInterval(fetch, 1000 * 60);
});
onUnmounted(() => {
window.clearInterval(intervalId);
}); });
</script> </script>

View File

@ -0,0 +1,22 @@
import { onMounted, onUnmounted } from 'vue';
export function useInterval(fn: () => void, interval: number, options: {
immediate: boolean;
afterMounted: boolean;
}): void {
let intervalId: number | null = null;
if (options.afterMounted) {
onMounted(() => {
if (options.immediate) fn();
intervalId = window.setInterval(fn, interval);
});
} else {
if (options.immediate) fn();
intervalId = window.setInterval(fn, interval);
}
onUnmounted(() => {
if (intervalId) window.clearInterval(intervalId);
});
}

View File

@ -6,8 +6,8 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, reactive, ref } from 'vue'; import { onMounted, onUnmounted, reactive, ref } from 'vue';
import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
import { GetFormResultType } from '@/scripts/form';
const name = 'ai'; const name = 'ai';
@ -38,22 +38,23 @@ const touched = () => {
//if (this.live2d) this.live2d.changeExpression('gurugurume'); //if (this.live2d) this.live2d.changeExpression('gurugurume');
}; };
onMounted(() => { const onMousemove = (ev: MouseEvent) => {
const onMousemove = (ev: MouseEvent) => { const iframeRect = live2d.value.getBoundingClientRect();
const iframeRect = live2d.value.getBoundingClientRect(); live2d.value.contentWindow.postMessage({
live2d.value.contentWindow.postMessage({ type: 'moveCursor',
type: 'moveCursor', body: {
body: { x: ev.clientX - iframeRect.left,
x: ev.clientX - iframeRect.left, y: ev.clientY - iframeRect.top,
y: ev.clientY - iframeRect.top, },
} }, '*');
}, '*'); };
};
onMounted(() => {
window.addEventListener('mousemove', onMousemove, { passive: true }); window.addEventListener('mousemove', onMousemove, { passive: true });
onUnmounted(() => { });
window.removeEventListener('mousemove', onMousemove);
}); onUnmounted(() => {
window.removeEventListener('mousemove', onMousemove);
}); });
defineExpose<WidgetComponentExpose>({ defineExpose<WidgetComponentExpose>({

View File

@ -34,9 +34,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onUnmounted, ref } from 'vue'; import { onUnmounted, ref } from 'vue';
import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
import { GetFormResultType } from '@/scripts/form';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { useInterval } from '@/scripts/use-interval';
const name = 'calendar'; const name = 'calendar';
@ -85,28 +86,26 @@ const tick = () => {
i18n.ts._weekday.wednesday, i18n.ts._weekday.wednesday,
i18n.ts._weekday.thursday, i18n.ts._weekday.thursday,
i18n.ts._weekday.friday, i18n.ts._weekday.friday,
i18n.ts._weekday.saturday i18n.ts._weekday.saturday,
][now.getDay()]; ][now.getDay()];
const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime(); const dayNumer = now.getTime() - new Date(ny, nm, nd).getTime();
const dayDenom = 1000/*ms*/ * 60/*s*/ * 60/*m*/ * 24/*h*/; const dayDenom = 1000/*ms*/ * 60/*s*/ * 60/*m*/ * 24/*h*/;
const monthNumer = now.getTime() - new Date(ny, nm, 1).getTime(); const monthNumer = now.getTime() - new Date(ny, nm, 1).getTime();
const monthDenom = new Date(ny, nm + 1, 1).getTime() - new Date(ny, nm, 1).getTime(); const monthDenom = new Date(ny, nm + 1, 1).getTime() - new Date(ny, nm, 1).getTime();
const yearNumer = now.getTime() - new Date(ny, 0, 1).getTime(); const yearNumer = now.getTime() - new Date(ny, 0, 1).getTime();
const yearDenom = new Date(ny + 1, 0, 1).getTime() - new Date(ny, 0, 1).getTime(); const yearDenom = new Date(ny + 1, 0, 1).getTime() - new Date(ny, 0, 1).getTime();
dayP.value = dayNumer / dayDenom * 100; dayP.value = dayNumer / dayDenom * 100;
monthP.value = monthNumer / monthDenom * 100; monthP.value = monthNumer / monthDenom * 100;
yearP.value = yearNumer / yearDenom * 100; yearP.value = yearNumer / yearDenom * 100;
isHoliday.value = now.getDay() === 0 || now.getDay() === 6; isHoliday.value = now.getDay() === 0 || now.getDay() === 6;
}; };
tick(); useInterval(tick, 1000, {
immediate: true,
const intervalId = window.setInterval(tick, 1000); afterMounted: false,
onUnmounted(() => {
window.clearInterval(intervalId);
}); });
defineExpose<WidgetComponentExpose>({ defineExpose<WidgetComponentExpose>({

View File

@ -25,6 +25,7 @@ import { GetFormResultType } from '@/scripts/form';
import MkContainer from '@/components/ui/container.vue'; import MkContainer from '@/components/ui/container.vue';
import MkMiniChart from '@/components/mini-chart.vue'; import MkMiniChart from '@/components/mini-chart.vue';
import * as os from '@/os'; import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
const name = 'federation'; const name = 'federation';
@ -64,12 +65,9 @@ const fetch = async () => {
fetching.value = false; fetching.value = false;
}; };
onMounted(() => { useInterval(fetch, 1000 * 60, {
fetch(); immediate: true,
const intervalId = window.setInterval(fetch, 1000 * 60); afterMounted: true,
onUnmounted(() => {
window.clearInterval(intervalId);
});
}); });
defineExpose<WidgetComponentExpose>({ defineExpose<WidgetComponentExpose>({

View File

@ -8,9 +8,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue'; import { onMounted, onUnmounted, ref } from 'vue';
import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
import { GetFormResultType } from '@/scripts/form';
import * as os from '@/os'; import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
const name = 'onlineUsers'; const name = 'onlineUsers';
@ -43,12 +44,9 @@ const tick = () => {
}); });
}; };
onMounted(() => { useInterval(tick, 1000 * 15, {
tick(); immediate: true,
const intervalId = window.setInterval(tick, 1000 * 15); afterMounted: true,
onUnmounted(() => {
window.clearInterval(intervalId);
});
}); });
defineExpose<WidgetComponentExpose>({ defineExpose<WidgetComponentExpose>({

View File

@ -14,10 +14,11 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref, watch } from 'vue'; import { onMounted, onUnmounted, ref, watch } from 'vue';
import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
import { GetFormResultType } from '@/scripts/form';
import * as os from '@/os'; import * as os from '@/os';
import MkContainer from '@/components/ui/container.vue'; import MkContainer from '@/components/ui/container.vue';
import { useInterval } from '@/scripts/use-interval';
const name = 'rss'; const name = 'rss';
@ -60,12 +61,9 @@ const tick = () => {
watch(() => widgetProps.url, tick); watch(() => widgetProps.url, tick);
onMounted(() => { useInterval(tick, 60000, {
tick(); immediate: true,
const intervalId = window.setInterval(tick, 60000); afterMounted: true,
onUnmounted(() => {
window.clearInterval(intervalId);
});
}); });
defineExpose<WidgetComponentExpose>({ defineExpose<WidgetComponentExpose>({

View File

@ -13,9 +13,10 @@
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'; import { nextTick, onMounted, onUnmounted, reactive, ref } from 'vue';
import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
import { GetFormResultType } from '@/scripts/form';
import * as os from '@/os'; import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
const name = 'slideshow'; const name = 'slideshow';
@ -75,7 +76,7 @@ const fetch = () => {
os.api('drive/files', { os.api('drive/files', {
folderId: widgetProps.folderId, folderId: widgetProps.folderId,
type: 'image/*', type: 'image/*',
limit: 100 limit: 100,
}).then(res => { }).then(res => {
images.value = res; images.value = res;
fetching.value = false; fetching.value = false;
@ -96,15 +97,15 @@ const choose = () => {
}); });
}; };
useInterval(change, 10000, {
immediate: false,
afterMounted: true,
});
onMounted(() => { onMounted(() => {
if (widgetProps.folderId != null) { if (widgetProps.folderId != null) {
fetch(); fetch();
} }
const intervalId = window.setInterval(change, 10000);
onUnmounted(() => {
window.clearInterval(intervalId);
});
}); });
defineExpose<WidgetComponentExpose>({ defineExpose<WidgetComponentExpose>({

View File

@ -19,11 +19,12 @@
<script lang="ts" setup> <script lang="ts" setup>
import { onMounted, onUnmounted, ref } from 'vue'; import { onMounted, onUnmounted, ref } from 'vue';
import { GetFormResultType } from '@/scripts/form';
import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget'; import { useWidgetPropsManager, Widget, WidgetComponentEmits, WidgetComponentExpose, WidgetComponentProps } from './widget';
import { GetFormResultType } from '@/scripts/form';
import MkContainer from '@/components/ui/container.vue'; import MkContainer from '@/components/ui/container.vue';
import MkMiniChart from '@/components/mini-chart.vue'; import MkMiniChart from '@/components/mini-chart.vue';
import * as os from '@/os'; import * as os from '@/os';
import { useInterval } from '@/scripts/use-interval';
const name = 'hashtags'; const name = 'hashtags';
@ -58,12 +59,9 @@ const fetch = () => {
}); });
}; };
onMounted(() => { useInterval(fetch, 1000 * 60, {
fetch(); immediate: true,
const intervalId = window.setInterval(fetch, 1000 * 60); afterMounted: true,
onUnmounted(() => {
window.clearInterval(intervalId);
});
}); });
defineExpose<WidgetComponentExpose>({ defineExpose<WidgetComponentExpose>({