优化可用高度计算

This commit is contained in:
jxxghp
2025-07-11 15:14:16 +08:00
parent 79d203470a
commit e409dbd5b8
6 changed files with 109 additions and 50 deletions
+4 -2
View File
@@ -2,6 +2,8 @@
<html lang="zh-CN" style=" <html lang="zh-CN" style="
overflow: hidden auto; overflow: hidden auto;
min-block-size: calc(100% + env(safe-area-inset-top) + env(safe-area-inset-bottom)); min-block-size: calc(100% + env(safe-area-inset-top) + env(safe-area-inset-bottom));
--safe-area-inset-bottom: env(safe-area-inset-bottom);
--safe-area-inset-top: env(safe-area-inset-top);
background: var(--initial-loader-bg, #fff); background: var(--initial-loader-bg, #fff);
"> ">
@@ -87,11 +89,11 @@
<link rel="dns-prefetch" href="//image.tmdb.org" /> <link rel="dns-prefetch" href="//image.tmdb.org" />
<link rel="preconnect" href="https://fonts.googleapis.com" crossorigin /> <link rel="preconnect" href="https://fonts.googleapis.com" crossorigin />
<link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin /> <link rel="preconnect" href="https://cdn.jsdelivr.net" crossorigin />
<!-- 预加载关键资源 --> <!-- 预加载关键资源 -->
<link rel="preload" href="/logo.png" as="image" /> <link rel="preload" href="/logo.png" as="image" />
<link rel="modulepreload" href="/src/main.ts" /> <link rel="modulepreload" href="/src/main.ts" />
<!-- 内联关键CSS --> <!-- 内联关键CSS -->
<style> <style>
/* 关键路径CSS - 从loader.css内联 */ /* 关键路径CSS - 从loader.css内联 */
+1 -25
View File
@@ -3,9 +3,7 @@ import FileList from './filebrowser/FileList.vue'
import FileToolbar from './filebrowser/FileToolbar.vue' import FileToolbar from './filebrowser/FileToolbar.vue'
import FileNavigator from './filebrowser/FileNavigator.vue' import FileNavigator from './filebrowser/FileNavigator.vue'
import type { EndPoints, FileItem, StorageConf } from '@/api/types' import type { EndPoints, FileItem, StorageConf } from '@/api/types'
import { useDisplay } from 'vuetify'
import { storageIconDict } from '@/api/constants' import { storageIconDict } from '@/api/constants'
import { usePWA } from '@/composables/usePWA'
// 输入参数 // 输入参数
const props = defineProps({ const props = defineProps({
@@ -30,13 +28,6 @@ const props = defineProps({
// 对外事件 // 对外事件
const emit = defineEmits(['pathchanged']) const emit = defineEmits(['pathchanged'])
// 显示器宽度
const display = useDisplay()
// APP
// PWA模式检测
const { appMode } = usePWA()
const fileIcons = { const fileIcons = {
// 压缩包 // 压缩包
zip: 'mdi-folder-zip-outline', zip: 'mdi-folder-zip-outline',
@@ -240,20 +231,6 @@ function stopDrag() {
;(document.body.style as any).webkitUserSelect = '' ;(document.body.style as any).webkitUserSelect = ''
;(document.body.style as any).mozUserSelect = '' ;(document.body.style as any).mozUserSelect = ''
} }
// 外层DIV大小控制
const scrollStyle = computed(() => {
return appMode.value
? 'height: calc(100vh - 10.5rem - env(safe-area-inset-bottom) - 7rem)'
: 'height: calc(100vh - 10.5rem - env(safe-area-inset-bottom)'
})
// 文件列表大小限制
const fileListStyle = computed(() => {
return appMode.value
? 'height: calc(100vh - 14rem - env(safe-area-inset-bottom) - 7rem)'
: 'height: calc(100vh - 14rem - env(safe-area-inset-bottom)'
})
</script> </script>
<template> <template>
@@ -271,7 +248,7 @@ const fileListStyle = computed(() => {
@foldercreated="refreshPending = true" @foldercreated="refreshPending = true"
@sortchanged="sortChanged" @sortchanged="sortChanged"
/> />
<div class="flex" :style="scrollStyle"> <div class="flex">
<FileNavigator <FileNavigator
v-if="showDirTree" v-if="showDirTree"
:storage="activeStorage" :storage="activeStorage"
@@ -295,7 +272,6 @@ const fileListStyle = computed(() => {
:axios="axios" :axios="axios"
:refreshpending="refreshPending" :refreshpending="refreshPending"
:sort="sort" :sort="sort"
:listStyle="fileListStyle"
:showTree="showDirTree" :showTree="showDirTree"
:style="{ flex: 1 }" :style="{ flex: 1 }"
@pathchanged="pathChanged" @pathchanged="pathChanged"
+42 -5
View File
@@ -12,6 +12,7 @@ import { useDisplay } from 'vuetify'
import MediaInfoDialog from '../dialog/MediaInfoDialog.vue' import MediaInfoDialog from '../dialog/MediaInfoDialog.vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useBackgroundOptimization } from '@/composables/useBackgroundOptimization' import { useBackgroundOptimization } from '@/composables/useBackgroundOptimization'
import { usePWA } from '@/composables/usePWA'
// 国际化 // 国际化
const { t } = useI18n() const { t } = useI18n()
@@ -20,6 +21,8 @@ const { useProgressSSE } = useBackgroundOptimization()
// 显示器宽度 // 显示器宽度
const display = useDisplay() const display = useDisplay()
const { appMode } = usePWA()
// 输入参数 // 输入参数
const inProps = defineProps({ const inProps = defineProps({
icons: Object, icons: Object,
@@ -35,7 +38,6 @@ const inProps = defineProps({
required: true, required: true,
}, },
sort: String, sort: String,
listStyle: String,
showTree: Boolean, showTree: Boolean,
}) })
@@ -125,6 +127,30 @@ const transferItems = ref<FileItem[]>([])
// 当前图片地址 // 当前图片地址
const currentImgLink = ref('') const currentImgLink = ref('')
// 计算列表可用高度
const listAvailableHeight = computed(() => {
// 获取视口高度
const viewportHeight = window.innerHeight || document.documentElement.clientHeight
// navbar高度
const navbarHeight = 72
// 工具栏高度(包含搜索框和按钮)
const toolbarHeight = 64
// 底部导航栏高度
const footerHeight = appMode.value ? 80 : 16
// 安全区域高度
const safeAreaHeight =
parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-inset-bottom')) ||
parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-inset-top')) ||
0
// 计算可用高度,预留一些边距
const availableHeight = viewportHeight - navbarHeight - toolbarHeight - footerHeight - safeAreaHeight - 40
// 确保最小高度
return Math.max(availableHeight, 300)
})
// 是否为图片文件 // 是否为图片文件
const isImage = computed(() => { const isImage = computed(() => {
const ext = inProps.item.path?.split('.').pop()?.toLowerCase() const ext = inProps.item.path?.split('.').pop()?.toLowerCase()
@@ -546,7 +572,7 @@ const progressSSE = useProgressSSE(
`${import.meta.env.VITE_API_BASE_URL}system/progress/batchrename`, `${import.meta.env.VITE_API_BASE_URL}system/progress/batchrename`,
handleProgressMessage, handleProgressMessage,
'file-batch-rename-progress', 'file-batch-rename-progress',
progressActive progressActive,
) )
// 使用SSE监听加载进度 // 使用SSE监听加载进度
@@ -567,6 +593,14 @@ onMounted(() => {
}) })
</script> </script>
<style scoped>
.file-list-container {
overflow: hidden auto;
block-size: 100%;
max-block-size: 100%;
}
</style>
<template> <template>
<div> <div>
<VCard class="d-flex flex-column w-full h-full rounded-t-0" :class="{ 'rounded-s-0': showTree }"> <VCard class="d-flex flex-column w-full h-full rounded-t-0" :class="{ 'rounded-s-0': showTree }">
@@ -635,9 +669,12 @@ onMounted(() => {
<VImg :src="currentImgLink" max-width="100%" max-height="100%" /> <VImg :src="currentImgLink" max-width="100%" max-height="100%" />
</VCardText> </VCardText>
<!-- 目录和文件列表 --> <!-- 目录和文件列表 -->
<VCardText v-else-if="dirs.length || files.length" class="p-0"> <VCardText v-else-if="dirs.length || files.length" class="p-0 flex-grow-1 overflow-hidden">
<VList class="text-high-emphasis"> <VList
<VVirtualScroll :items="[...dirs, ...files]" :style="listStyle"> class="text-high-emphasis file-list-container"
:style="{ height: `${listAvailableHeight}px`, maxHeight: `${listAvailableHeight}px` }"
>
<VVirtualScroll :items="[...dirs, ...files]" style="block-size: 100%">
<template #default="{ item }"> <template #default="{ item }">
<VHover> <VHover>
<template #default="hover"> <template #default="hover">
+37 -11
View File
@@ -4,6 +4,7 @@ import type { FileItem } from '@/api/types'
import { useDisplay } from 'vuetify' import { useDisplay } from 'vuetify'
import type { AxiosRequestConfig } from 'axios' import type { AxiosRequestConfig } from 'axios'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { usePWA } from '@/composables/usePWA'
// 国际化 // 国际化
const { t } = useI18n() const { t } = useI18n()
@@ -11,6 +12,32 @@ const { t } = useI18n()
// 显示器宽度 // 显示器宽度
const display = useDisplay() const display = useDisplay()
const { appMode } = usePWA()
// 计算列表可用高度
const availableHeight = computed(() => {
// 获取视口高度
const viewportHeight = window.innerHeight || document.documentElement.clientHeight
// navbar高度
const navbarHeight = 72
// 工具栏高度
const toolbarHeight = 25
// 底部导航栏高度
const footerHeight = appMode.value ? 80 : 16
// 安全区域高度
const safeAreaHeight =
parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-inset-bottom')) ||
parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-inset-top')) ||
0
// 计算可用高度,预留一些边距
const availableHeight = viewportHeight - navbarHeight - toolbarHeight - footerHeight - safeAreaHeight - 40
// 确保最小高度
return Math.max(availableHeight, 300)
})
// 输入参数 // 输入参数
const props = defineProps({ const props = defineProps({
storage: { storage: {
@@ -125,11 +152,6 @@ async function loadRootDirectories() {
await loadSubdirectories('/') await loadSubdirectories('/')
} }
// 获取目录层级深度
function getDirectoryDepth(path: string) {
return path.split('/').filter(p => p).length
}
// 检索所有目录节点 // 检索所有目录节点
function getAllDirectories() { function getAllDirectories() {
const allDirs: { dir: FileItem; level: number; parentPath: string }[] = [] const allDirs: { dir: FileItem; level: number; parentPath: string }[] = []
@@ -227,11 +249,6 @@ const flattenedDirectories = computed(() => {
return getAllDirectories() return getAllDirectories()
}) })
// 组件挂载时初始加载
onMounted(async () => {
await loadRootDirectories()
})
// 检查路径是否为指定目录的子目录或后代 // 检查路径是否为指定目录的子目录或后代
function isChildOrDescendant(path: string, ancestorPath: string) { function isChildOrDescendant(path: string, ancestorPath: string) {
if (!path || !ancestorPath) return false if (!path || !ancestorPath) return false
@@ -260,10 +277,19 @@ function getIndentLevel(path: string, ancestorPath: string) {
return pathParts - ancestorParts return pathParts - ancestorParts
} }
// 组件挂载时初始加载
onMounted(async () => {
await loadRootDirectories()
})
onActivated(() => {
updateHeight()
})
</script> </script>
<template> <template>
<VCard class="file-navigator rounded-e-0 rounded-t-0" v-if="!isMobile"> <VCard class="file-navigator rounded-e-0 rounded-t-0" v-if="!isMobile" :height="`${availableHeight}px`">
<div class="tree-container"> <div class="tree-container">
<!-- 根目录项 --> <!-- 根目录项 -->
<div <div
+1 -1
View File
@@ -6,7 +6,7 @@ declare let self: ServiceWorkerGlobalScope & {
} }
// 缓存版本控制 // 缓存版本控制
const CACHE_VERSION = 'v1.0.1' const CACHE_VERSION = 'v1.0.2'
const CACHE_NAMES = { const CACHE_NAMES = {
appShell: `app-shell-${CACHE_VERSION}`, appShell: `app-shell-${CACHE_VERSION}`,
static: `static-resources-${CACHE_VERSION}`, static: `static-resources-${CACHE_VERSION}`,
+24 -6
View File
@@ -214,10 +214,28 @@ const TransferDict: { [key: string]: string } = {
rclone_move: t('transferHistory.transferMode.rclone_move'), rclone_move: t('transferHistory.transferMode.rclone_move'),
} }
const tableStyle = computed(() => { // 计算列表可用高度
return appMode.value const availableHeight = computed(() => {
? 'height: calc(100vh - 15rem - env(safe-area-inset-bottom) - 7rem)' // 获取视口高度
: 'height: calc(100vh - 15rem - env(safe-area-inset-bottom)' const viewportHeight = window.innerHeight || document.documentElement.clientHeight
// navbar高度
const navbarHeight = 72
// 工具栏高度
const toolbarHeight = 88
// 底部导航栏高度
const footerHeight = appMode.value ? 80 : 16
// 安全区域高度
const safeAreaHeight =
parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-inset-bottom')) ||
parseFloat(getComputedStyle(document.documentElement).getPropertyValue('--safe-area-inset-top')) ||
0
// 计算可用高度,预留一些边距
const availableHeight = viewportHeight - navbarHeight - toolbarHeight - footerHeight - safeAreaHeight - 48
// 确保最小高度
return Math.max(availableHeight, 300)
}) })
// 分页提示 // 分页提示
@@ -509,7 +527,7 @@ onMounted(() => {
show-select show-select
:loading-text="t('transferHistory.loading')" :loading-text="t('transferHistory.loading')"
hover hover
:style="tableStyle" :style="{ height: `${availableHeight}px` }"
> >
<template #header.data-table-group> <template #header.data-table-group>
<span>{{ t('transferHistory.titleColumn') }}</span> <span>{{ t('transferHistory.titleColumn') }}</span>
@@ -608,7 +626,7 @@ onMounted(() => {
show-select show-select
:loading-text="t('transferHistory.loading')" :loading-text="t('transferHistory.loading')"
hover hover
:style="tableStyle" :style="{ height: `${availableHeight}px` }"
> >
<template #item.title="{ item }"> <template #item.title="{ item }">
<div class="d-flex align-center"> <div class="d-flex align-center">