From d6cb616337081f2be4e4575a4e1dd14b0acb8c29 Mon Sep 17 00:00:00 2001 From: toom1996 Date: Sun, 13 Sep 2026 21:39:50 +0800 Subject: [PATCH] update --- .workbuddy/memory/2026-09-13.md | 57 ++ .workbuddy/memory/MEMORY.md | 69 ++- _tmp_build.log | Bin 4966 -> 0 bytes src/components/AuthModal.astro | 2 +- src/components/Index.astro | 932 ++++++++++++++++++------------- src/components/Item.astro | 86 +-- src/components/RunwayLooks.astro | 5 +- src/components/StreetSnap.astro | 77 ++- src/components/StreetSnaps.astro | 3 +- src/i18n/dictionary.ts | 58 +- src/i18n/utils.ts | 4 +- src/layouts/Layout.astro | 8 +- src/lib/api.ts | 270 +-------- src/lib/auth.ts | 185 ++++++ src/lib/crypto.ts | 36 ++ src/lib/favorites.ts | 2 +- src/lib/history.ts | 3 +- src/lib/locale.ts | 34 ++ src/pages/cn/account.astro | 3 +- src/pages/cn/item/[id].astro | 24 +- src/pages/cn/login.astro | 2 +- src/pages/en/account.astro | 3 +- src/pages/en/item/[id].astro | 24 +- src/pages/en/login.astro | 2 +- 24 files changed, 1076 insertions(+), 813 deletions(-) create mode 100644 .workbuddy/memory/2026-09-13.md delete mode 100644 _tmp_build.log create mode 100644 src/lib/auth.ts create mode 100644 src/lib/crypto.ts create mode 100644 src/lib/locale.ts diff --git a/.workbuddy/memory/2026-09-13.md b/.workbuddy/memory/2026-09-13.md new file mode 100644 index 0000000..cee9855 --- /dev/null +++ b/.workbuddy/memory/2026-09-13.md @@ -0,0 +1,57 @@ +# 2026-09-13 工作日志 + +## 首页图片加载状态 + Swiper 初始化优化(14:5x)✅ +用户建议对首页 Index.astro 的 Hot Brand / Street Style 图片加载与 Swiper 初始化做一层优化(7 点)。改动: +- **统一图片状态初始化逻辑**:Hot Brand `hs-img-box` 与 Street Style `ss-img-box` 两份完全重复的内联 `x-data="{loaded,error,init()检查complete+naturalWidth,handleLoad,handleError}"` 抽成共享 Alpine 组件 `imgLoader`,在 ` \ No newline at end of file + // 销毁已有实例:防止重复初始化 / View Transitions 重新进入时旧实例泄漏 + function destroySwipers() { + for (const swiper of swipers) { + if (!swiper.destroyed) swiper.destroy(true, true) + } + swipers = [] + } + + function initSwipers() { + destroySwipers() + document.querySelectorAll(".hs-swiper").forEach((el) => { + const prevBtn = el.parentElement?.querySelector(".hs-prev") + const nextBtn = el.parentElement?.querySelector(".hs-next") + const swiper = new Swiper(el, { + modules: [Navigation, FreeMode, Keyboard], + slidesPerView: "auto", + spaceBetween: 4, + grabCursor: true, + speed: 220, + freeMode: { enabled: true, sticky: true, momentumBounce: false, momentumRatio: 0.5 }, + keyboard: { enabled: true }, + navigation: { prevEl: prevBtn, nextEl: nextBtn, disabledClass: "swiper-button-disabled" }, + observer: true, + observeParents: true, + observeSlideChildren: true, + resizeObserver: true, + }) + swipers.push(swiper) + }) + scheduleSwiperUpdate() + } + + // 统一入口:延后一帧,避免首次进入时 DOM / Alpine / Swiper 初始化时序互相抢 + function setupSwipers() { + requestAnimationFrame(() => initSwipers()) + } + + // 首次普通加载:等 DOMContentLoaded + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", setupSwipers, { once: true }) + } else { + setupSwipers() + } + + // Astro View Transitions 客户端导航进入:重新初始化 + document.addEventListener("astro:page-load", setupSwipers) + + // Tab 切换后重算尺寸(事件委托,兼容 View Transitions 后的新 DOM) + document.addEventListener("click", (e) => { + if (e.target.closest(".tab")) { + setTimeout(scheduleSwiperUpdate, 60) + } + }) + + // 浏览器尺寸变化 + window.addEventListener("resize", scheduleSwiperUpdate) + + // 图片加载完成(每张图的 Alpine 组件 dispatch "img-ready")后更新 Swiper + window.addEventListener("img-ready", scheduleSwiperUpdate) + + /* ---------------- 共享图片加载状态组件 ---------------- */ + // Hot Brand 与 Street Style 复用同一份逻辑: + // 1) init() 检查 complete + naturalWidth,缓存已完成的图片立即置位,不一直显示骨架; + // 2) 保留 @load / @error,处理 Alpine 初始化之后才完成的图片。 + document.addEventListener("alpine:init", () => { + Alpine.data("imgLoader", () => ({ + loaded: false, + error: false, + init() { + const img = this.$el.querySelector("img") + if (!img) return + if (img.complete) { + this.loaded = img.naturalWidth > 0 + this.error = img.naturalWidth === 0 + if (this.loaded || this.error) this.$dispatch("img-ready") + } + }, + handleLoad() { + this.error = false + this.loaded = true + this.$dispatch("img-ready") + }, + handleError() { + this.loaded = false + this.error = true + this.$dispatch("img-ready") + }, + })) + }) + diff --git a/src/components/Item.astro b/src/components/Item.astro index d531f5c..0b3a700 100644 --- a/src/components/Item.astro +++ b/src/components/Item.astro @@ -45,7 +45,7 @@ for (const d of (article?.details ?? []) as { look_index?: number; images?: unkn } // 未登录预览上限:详情页(图集)未登录最多展示前 PREVIEW_LIMIT 张图片;其余由登录门禁提示, -// 已登录(客户端 loadFull 拉全量)或图片本就不超上限时全部展示。前 PREVIEW_LIMIT 张服务端已渲染(SEO/无 JS 友好)。 +// 已登录(客户端 loadAuthedState 拉全量)或图片本就不超上限时全部展示。前 PREVIEW_LIMIT 张服务端已渲染(SEO/无 JS 友好)。 const PREVIEW_LIMIT = 5 const previewImages = images.slice(0, PREVIEW_LIMIT) @@ -214,7 +214,7 @@ const homeHref = href(locale, ROUTES.home) )) } - {/* 登录后追加的额外图片:extraImages 由客户端 loadFull() 在已登录时填充,未登录为空不渲染 */} + {/* 登录后追加的额外图片:extraImages 由客户端 loadAuthedState() 在已登录时填充,未登录为空不渲染 */}