perf(game-ui): 대규모 장수일람 초기 렌더링을 줄인다

현재 화면 폭에 필요한 표 또는 카드만 마운트하고 화면 밖 장수 얼굴은 지연 로딩한다. PYA 규모 845명 Chromium 회귀로 레이아웃 전환과 요청 수 경계를 고정한다.
This commit is contained in:
2026-08-25 02:11:47 +00:00
parent 36b4087382
commit f20fb9408d
2 changed files with 87 additions and 4 deletions
@@ -1,4 +1,6 @@
<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, ref } from 'vue';
import { resolveGeneralIconUrl, useDefaultGeneralIcon } from '../../utils/generalIcon';
import { formatOfficerLevelText } from '../../utils/nationFormat';
import { getNpcColor } from '../../utils/npcColor';
@@ -29,6 +31,26 @@ const props = withDefaults(
const emit = defineEmits<{ sort: [value: number] }>();
const narrowViewportQuery =
typeof window !== 'undefined' && typeof window.matchMedia === 'function'
? window.matchMedia('(max-width: 600px)')
: null;
const narrowViewport = ref(narrowViewportQuery?.matches ?? false);
const renderCardLayout = computed(() => props.layout === 'card' || narrowViewport.value);
const updateNarrowViewport = (event: MediaQueryListEvent): void => {
narrowViewport.value = event.matches;
};
onMounted(() => {
if (!narrowViewportQuery) return;
narrowViewport.value = narrowViewportQuery.matches;
narrowViewportQuery.addEventListener('change', updateNarrowViewport);
});
onBeforeUnmount(() => {
narrowViewportQuery?.removeEventListener('change', updateNarrowViewport);
});
const headers: ReadonlyArray<Header> = [
{ label: '얼 굴' },
{ label: '이 름', sort: 0 },
@@ -71,7 +93,7 @@ const sortHelp = (header: Header): string =>
</script>
<template>
<table class="directory-table general-table legacy-bg0" :class="{ 'layout-card': layout === 'card' }">
<table v-if="!renderCardLayout" class="directory-table general-table legacy-bg0">
<colgroup>
<col style="width: 64px" />
<col style="width: 140px" />
@@ -134,6 +156,8 @@ const sortHelp = (header: Header): string =>
class="general-icon"
width="64"
height="64"
loading="lazy"
decoding="async"
:src="resolveGeneralIconUrl(general)"
alt=""
@error="useDefaultGeneralIcon"
@@ -208,7 +232,7 @@ const sortHelp = (header: Header): string =>
</tbody>
</table>
<div class="general-card-list" :class="{ 'layout-card': layout === 'card' }">
<div v-if="renderCardLayout" class="general-card-list" :class="{ 'layout-card': layout === 'card' }">
<div v-if="loading" class="general-card-loading legacy-bg0">불러오는 중...</div>
<article
v-for="general in generals"
@@ -229,6 +253,8 @@ const sortHelp = (header: Header): string =>
class="general-icon"
width="64"
height="64"
loading="lazy"
decoding="async"
:src="resolveGeneralIconUrl(general)"
alt=""
@error="useDefaultGeneralIcon"