From 604ba2eec6c8391a5f6d5fd34b62b971a00726e2 Mon Sep 17 00:00:00 2001 From: jiangrui Date: Wed, 5 Mar 2025 12:29:47 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=E4=BC=98=E5=8C=96=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E7=AB=AF=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/components.d.ts | 1 - frontend/postcss.config.cjs | 2 +- .../src/components/mobile/FolderSelect.vue | 275 +++++++++---- .../src/components/mobile/ResourceCard.vue | 26 +- .../src/components/mobile/ResourceSelect.vue | 201 +++++++--- frontend/src/stores/douban.ts | 5 + frontend/src/styles/responsive.scss | 92 +++-- frontend/src/utils/index.ts | 13 + frontend/src/views/mobile/Douban.vue | 27 +- frontend/src/views/mobile/Home.vue | 10 +- frontend/src/views/mobile/Login.vue | 83 ++-- frontend/src/views/mobile/ResourceList.vue | 367 +++++++++++++----- 12 files changed, 793 insertions(+), 309 deletions(-) diff --git a/frontend/components.d.ts b/frontend/components.d.ts index 1e790f5..39ce718 100644 --- a/frontend/components.d.ts +++ b/frontend/components.d.ts @@ -57,7 +57,6 @@ declare module 'vue' { VanImage: typeof import('vant/es')['Image'] VanLoading: typeof import('vant/es')['Loading'] VanOverlay: typeof import('vant/es')['Overlay'] - VanPopover: typeof import('vant/es')['Popover'] VanPopup: typeof import('vant/es')['Popup'] VanSearch: typeof import('vant/es')['Search'] VanSwitch: typeof import('vant/es')['Switch'] diff --git a/frontend/postcss.config.cjs b/frontend/postcss.config.cjs index b6fb2cb..6399191 100644 --- a/frontend/postcss.config.cjs +++ b/frontend/postcss.config.cjs @@ -2,7 +2,7 @@ module.exports = { plugins: { "postcss-pxtorem": { rootValue({ file }) { - return file.indexOf("mobile") !== -1 || file.indexOf("vant") !== -1 ? 37.5 : 75; + return file.indexOf("vant") !== -1 || file.indexOf("mobile") !== -1 ? 50 : 75; }, propList: ["*"], exclude: (file) => { diff --git a/frontend/src/components/mobile/FolderSelect.vue b/frontend/src/components/mobile/FolderSelect.vue index 063b56b..0eb1799 100644 --- a/frontend/src/components/mobile/FolderSelect.vue +++ b/frontend/src/components/mobile/FolderSelect.vue @@ -1,38 +1,63 @@ - diff --git a/frontend/src/components/mobile/ResourceCard.vue b/frontend/src/components/mobile/ResourceCard.vue index d97b185..bffd683 100644 --- a/frontend/src/components/mobile/ResourceCard.vue +++ b/frontend/src/components/mobile/ResourceCard.vue @@ -7,7 +7,7 @@
@@ -125,10 +125,10 @@ const toggleExpand = (id: string) => { } .resource-card { - padding: var(--spacing-base); + padding: 5px 10px; &__item { - margin-bottom: var(--spacing-base); + margin-bottom: 12px; background: var(--theme-other_background); border-radius: var(--border-radius-lg); overflow: hidden; @@ -138,8 +138,8 @@ const toggleExpand = (id: string) => { .item { &__content { display: flex; - gap: var(--spacing-base); - padding: var(--spacing-base); + gap: 16px; + padding: 16px; } } @@ -240,11 +240,21 @@ const toggleExpand = (id: string) => { &__action { display: flex; justify-content: flex-end; + padding: 4px 0; .van-button { - font-size: 12px; - height: 24px; - padding: 0 12px; + font-size: 13px; + height: 32px; + padding: 0 20px; + + :deep(.van-button__text) { + font-weight: 500; + font-size: 14px; + } + + &:active { + opacity: 0.8; + } } } } diff --git a/frontend/src/components/mobile/ResourceSelect.vue b/frontend/src/components/mobile/ResourceSelect.vue index 0c6f94f..c890add 100644 --- a/frontend/src/components/mobile/ResourceSelect.vue +++ b/frontend/src/components/mobile/ResourceSelect.vue @@ -1,81 +1,184 @@ - diff --git a/frontend/src/stores/douban.ts b/frontend/src/stores/douban.ts index 4914ea7..e1129c6 100644 --- a/frontend/src/stores/douban.ts +++ b/frontend/src/stores/douban.ts @@ -5,6 +5,7 @@ import { ElMessage } from "element-plus"; interface StoreType { hotList: HotListItem[]; + loading: boolean; currentParams: CurrentParams; } @@ -16,6 +17,7 @@ interface CurrentParams { export const useDoubanStore = defineStore("douban", { state: (): StoreType => ({ hotList: [], + loading: false, currentParams: { type: "movie", tag: "热门", @@ -24,6 +26,7 @@ export const useDoubanStore = defineStore("douban", { actions: { async getHotList() { + this.loading = true; try { const params = { type: this.currentParams.type, @@ -40,6 +43,8 @@ export const useDoubanStore = defineStore("douban", { } } catch (error) { ElMessage.error(error || "获取热门列表失败"); + } finally { + this.loading = false; } }, setCurrentParams(currentParams: CurrentParams) { diff --git a/frontend/src/styles/responsive.scss b/frontend/src/styles/responsive.scss index de2e7cc..8fddd6b 100644 --- a/frontend/src/styles/responsive.scss +++ b/frontend/src/styles/responsive.scss @@ -1,47 +1,77 @@ +@mixin text-ellipsis { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + // 响应式布局工具类 @mixin mobile { - @media screen and (max-width: 768px) { - @content; - } + @media screen and (max-width: 768px) { + @content; + } } @mixin tablet { - @media screen and (min-width: 769px) and (max-width: 1024px) { - @content; - } + @media screen and (min-width: 769px) and (max-width: 1024px) { + @content; + } } @mixin desktop { - @media screen and (min-width: 1025px) { - @content; - } + @media screen and (min-width: 1025px) { + @content; + } } // 通用样式变量 :root { - // 字体大小 - --font-size-xs: 12px; - --font-size-sm: 14px; - --font-size-base: 16px; - --font-size-lg: 18px; - --font-size-xl: 20px; + // 字体大小 - 整体缩小约25% + --font-size-xs: 20px; // 原24px + --font-size-sm: 22px; // 原26px + --font-size-base: 24px; // 原28px + --font-size-lg: 28px; // 原32px + --font-size-xl: 32px; // 原36px + // 间距 - 也相应缩小 + --spacing-xs: 6px; // 原8px + --spacing-sm: 10px; // 原12px + --spacing-base: 14px; // 原16px + --spacing-lg: 20px; // 原24px + --spacing-xl: 28px; // 原32px + + // 圆角 - 适当调整 + --border-radius-sm: 6px; // 原8px + --border-radius-base: 10px; // 原12px + --border-radius-lg: 14px; // 原16px + --border-radius-xl: 20px; // 原24px + + // 移动端特殊变量 + @include mobile { + --font-size-base: 14px; + --spacing-base: 12px; + } +} + +// 移动端适配 +@media screen and (max-width: 768px) { + :root { // 间距 - --spacing-xs: 4px; - --spacing-sm: 8px; - --spacing-base: 16px; - --spacing-lg: 24px; - --spacing-xl: 32px; + --spacing-xs: 3px; + --spacing-sm: 5px; + --spacing-base: 7px; + --spacing-lg: 10px; + --spacing-xl: 14px; + + // 字体大小 + --font-size-xs: 10px; + --font-size-sm: 11px; + --font-size-base: 12px; + --font-size-lg: 14px; + --font-size-xl: 16px; // 圆角 - --border-radius-sm: 4px; - --border-radius-base: 8px; - --border-radius-lg: 16px; - --border-radius-xl: 24px; - - // 移动端特殊变量 - @include mobile { - --font-size-base: 14px; - --spacing-base: 12px; - } -} \ No newline at end of file + --border-radius-sm: 3px; + --border-radius-base: 5px; + --border-radius-lg: 7px; + } +} diff --git a/frontend/src/utils/index.ts b/frontend/src/utils/index.ts index 4fcb218..87a013e 100644 --- a/frontend/src/utils/index.ts +++ b/frontend/src/utils/index.ts @@ -14,3 +14,16 @@ export function isMobileDevice() { window.innerWidth <= 768 ); } + +export function throttle any>(fn: T, delay: number): T { + let lastTime = 0; + + return function (this: any, ...args: Parameters) { + const now = Date.now(); + + if (now - lastTime >= delay) { + fn.apply(this, args); + lastTime = now; + } + } as T; +} diff --git a/frontend/src/views/mobile/Douban.vue b/frontend/src/views/mobile/Douban.vue index e27df08..864a15e 100644 --- a/frontend/src/views/mobile/Douban.vue +++ b/frontend/src/views/mobile/Douban.vue @@ -1,7 +1,12 @@ @@ -174,6 +179,24 @@ const getRateColor = (rate: string | number) => { } } } + + // 加载状态 + &__loading { + position: fixed; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + background: var(--theme-background); + z-index: 1; + + :deep(.van-loading) { + padding: 16px 24px; + background: rgba(0, 0, 0, 0.7); + border-radius: 8px; + color: #fff; + } + } } // 深度修改 Vant 组件样式 diff --git a/frontend/src/views/mobile/Home.vue b/frontend/src/views/mobile/Home.vue index 9a90e22..c244c6e 100644 --- a/frontend/src/views/mobile/Home.vue +++ b/frontend/src/views/mobile/Home.vue @@ -31,7 +31,7 @@ 搜索 - 影视 + 热门 设置 @@ -118,6 +118,8 @@ const handleLogout = () => { // 布局 min-height: 100vh; background: var(--theme-background); + display: flex; + flex-direction: column; // 头部搜索 &__header { @@ -159,9 +161,11 @@ const handleLogout = () => { // 主内容区 - 调整顶部间距 &__content { padding-top: 64px; // 搜索框高度(48px) + 上下padding(8px * 2) - padding-bottom: calc(50px + var(--safe-area-bottom)); // tabbar高度 + 底部安全区域 - min-height: 100vh; + padding-bottom: 100px; // tabbar高度 + 底部安全区域 box-sizing: border-box; + flex: 1; + overflow-y: auto; + -webkit-overflow-scrolling: touch; } // 加载状态 diff --git a/frontend/src/views/mobile/Login.vue b/frontend/src/views/mobile/Login.vue index 3d9341e..e565638 100644 --- a/frontend/src/views/mobile/Login.vue +++ b/frontend/src/views/mobile/Login.vue @@ -7,7 +7,7 @@
@@ -156,7 +156,6 @@ const handleSubmit = async () => {