Merge pull request 'frontend performance improvements' (#59) from sugar/forkey:frontend-performance-improvements into main

Reviewed-on: woem.men/forkey#59
Reviewed-by: leah <leah@noreply.woem.men>
This commit is contained in:
sugar 2025-02-07 18:36:39 +00:00
commit cfba325ae7
2 changed files with 45 additions and 13 deletions

View file

@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { nextTick, onMounted, onUnmounted, shallowRef } from 'vue'; import { nextTick, onMounted, onUnmounted, shallowRef, watch } from 'vue';
import * as os from '@/os.js'; import * as os from '@/os.js';
import { calcPopupPosition } from '@/scripts/popup-position.js'; import { calcPopupPosition } from '@/scripts/popup-position.js';
import { defaultStore } from '@/store.js'; import { defaultStore } from '@/store.js';
@ -70,7 +70,7 @@ function setPosition() {
el.value.style.top = data.top + 'px'; el.value.style.top = data.top + 'px';
} }
let loopHandler; let loopHandler: number | undefined;
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
@ -81,12 +81,23 @@ onMounted(() => {
loopHandler = window.requestAnimationFrame(loop); loopHandler = window.requestAnimationFrame(loop);
}; };
watch(() => props.showing, show => {
if (show) {
if (!loopHandler) {
loop(); loop();
}
} else if (loopHandler) {
window.cancelAnimationFrame(loopHandler);
loopHandler = undefined;
}
});
}); });
}); });
onUnmounted(() => { onUnmounted(() => {
if (loopHandler) {
window.cancelAnimationFrame(loopHandler); window.cancelAnimationFrame(loopHandler);
}
}); });
</script> </script>

View file

@ -225,7 +225,7 @@ import MkTextarea from '@/components/MkTextarea.vue';
import MkOmit from '@/components/MkOmit.vue'; import MkOmit from '@/components/MkOmit.vue';
import MkInfo from '@/components/MkInfo.vue'; import MkInfo from '@/components/MkInfo.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { getScrollPosition } from '@/scripts/scroll.js'; import { getScrollContainer } from '@/scripts/scroll.js';
import { getUserMenu } from '@/scripts/get-user-menu.js'; import { getUserMenu } from '@/scripts/get-user-menu.js';
import number from '@/filters/number.js'; import number from '@/filters/number.js';
import { userPage } from '@/filters/user.js'; import { userPage } from '@/filters/user.js';
@ -282,6 +282,7 @@ const isEditingMemo = ref(false);
const moderationNote = ref(props.user.moderationNote); const moderationNote = ref(props.user.moderationNote);
const editModerationNote = ref(false); const editModerationNote = ref(false);
const movedFromLog = ref<null | {movedFromId:string;}[]>(null); const movedFromLog = ref<null | {movedFromId:string;}[]>(null);
let scrollEl: null | HTMLElement = null;
watch(moderationNote, async () => { watch(moderationNote, async () => {
await misskeyApi('admin/update-user-note', { userId: props.user.id, text: moderationNote.value }); await misskeyApi('admin/update-user-note', { userId: props.user.id, text: moderationNote.value });
@ -313,15 +314,19 @@ async function fetchMovedFromLog() {
} }
function parallaxLoop() { function parallaxLoop() {
parallaxAnimationId.value = window.requestAnimationFrame(parallaxLoop); requestNextParallaxFrame();
parallax(); parallax();
} }
function requestNextParallaxFrame() {
parallaxAnimationId.value = window.requestAnimationFrame(parallaxLoop);
}
function parallax() { function parallax() {
const banner = bannerEl.value as any; const banner = bannerEl.value as any;
if (banner == null) return; if (banner == null) return;
const top = getScrollPosition(rootEl.value); const top = scrollEl?.scrollTop ?? scrollY;
if (top < 0) return; if (top < 0) return;
@ -330,6 +335,23 @@ function parallax() {
banner.style.backgroundPosition = `center calc(50% - ${pos}px)`; banner.style.backgroundPosition = `center calc(50% - ${pos}px)`;
} }
function startParallax() {
(scrollEl ?? window).removeEventListener('scroll', startParallax);
requestNextParallaxFrame();
}
function addScrollEvent() {
(scrollEl ?? window).addEventListener('scroll', startParallax);
}
function cancelParallax() {
if (parallaxAnimationId.value) {
window.cancelAnimationFrame(parallaxAnimationId.value);
parallaxAnimationId.value = null;
addScrollEvent();
}
}
function showMemoTextarea() { function showMemoTextarea() {
isEditingMemo.value = true; isEditingMemo.value = true;
nextTick(() => { nextTick(() => {
@ -394,7 +416,10 @@ watch([props.user], () => {
}); });
onMounted(() => { onMounted(() => {
window.requestAnimationFrame(parallaxLoop); scrollEl = getScrollContainer(rootEl.value);
addScrollEvent();
(scrollEl ?? window).addEventListener('scrollend', cancelParallax);
parallax();
narrow.value = rootEl.value!.clientWidth < 1000; narrow.value = rootEl.value!.clientWidth < 1000;
if (props.user.birthday) { if (props.user.birthday) {
@ -417,11 +442,7 @@ onMounted(() => {
}); });
}); });
onUnmounted(() => { onUnmounted(cancelParallax);
if (parallaxAnimationId.value) {
window.cancelAnimationFrame(parallaxAnimationId.value);
}
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>