From 45f77d31684cd0855dbfa5dc5e472418643af75a Mon Sep 17 00:00:00 2001 From: Timi Date: Tue, 22 Sep 2026 21:26:37 +0800 Subject: [PATCH] add PageTransition --- docs/.vitepress/components.ts | 7 + docs/components/index.md | 3 +- docs/components/page-transition.md | 37 +++ src/components/index.ts | 14 + src/components/page-transition/index.ts | 16 ++ src/components/page-transition/index.vue | 333 +++++++++++++++++++++++ src/components/page-transition/type.ts | 61 +++++ 7 files changed, 470 insertions(+), 1 deletion(-) create mode 100644 docs/components/page-transition.md create mode 100644 src/components/page-transition/index.ts create mode 100644 src/components/page-transition/index.vue create mode 100644 src/components/page-transition/type.ts diff --git a/docs/.vitepress/components.ts b/docs/.vitepress/components.ts index b8944bd..aaedf4c 100644 --- a/docs/.vitepress/components.ts +++ b/docs/.vitepress/components.ts @@ -36,6 +36,13 @@ export interface ComponentMeta { export const COMPONENT_LIST: ComponentMeta[] = [ // ---------- 布局组件 ---------- + { + name: "PageTransition", + title: "PageTransition 页面过渡", + description: "为 Vue Router 页面提供可配置的层级滑动过渡与按路由缓存能力。", + category: "布局组件", + entry: "src/components/page-transition/index.vue" + }, { name: "RootLayout", title: "RootLayout 根布局", diff --git a/docs/components/index.md b/docs/components/index.md index 527e76c..86222f6 100644 --- a/docs/components/index.md +++ b/docs/components/index.md @@ -1,11 +1,12 @@ # 组件总览 -共 15 个组件,分为布局、编辑器、交互与 AI 对话四类。 +共 16 个组件,分为布局、编辑器、交互与 AI 对话四类。 ## 布局组件 | 组件 | 说明 | | --- | --- | +| [PageTransition](/components/page-transition) | 为 Vue Router 页面提供可配置的层级滑动过渡与按路由缓存能力。 | | [RootLayout](/components/root-layout) | 移动端页面骨架,主体内容之外自动渲染版权与备案信息。 | | [Space](/components/space) | 控制子元素之间的间距与排列方向,支持分隔符。 | diff --git a/docs/components/page-transition.md b/docs/components/page-transition.md new file mode 100644 index 0000000..d2c4cb7 --- /dev/null +++ b/docs/components/page-transition.md @@ -0,0 +1,37 @@ +# PageTransition 页面过渡 + +为 Vue Router 页面提供可配置的页面过渡和按路由缓存能力。 + +## 基础用法 + +`PageTransition` 必须放在 `RouterView` 所在的路由布局中,并且自身需要有明确的宽高。 + +```vue + + + +``` + +组件默认根据路由层级选择 `push-left` 和 `push-right`。层级的解析顺序是:`transitionDepth` query、`depth` meta、动态层级 meta,最后回退到 `matched.length`。业务路由结构特殊时,直接传入 `get-route-depth`,不要让组件猜测业务规则。 + +## 缓存页面 + +`keep-alive` 支持布尔值或路由谓词。谓词返回 `true` 的页面会进入缓存,`keep-alive-max` 用于限制缓存数量。默认不缓存页面,避免通用布局意外保留业务表单状态。 + +## 自定义过渡 + +`transition` 默认值为 `auto`,也可以传入 `false` 禁用过渡、传入字符串使用自定义过渡名,或传入函数按目标路由和来源路由返回过渡名。组件内置 `push-left`、`push-right` 和 `fade`。 + +组件默认尊重系统的“减少动态效果”设置;如果业务必须保持页面翻页动画,可以设置 `:respect-reduced-motion="false"`。 + +## API + + diff --git a/src/components/index.ts b/src/components/index.ts index 9d34599..e1daeef 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,5 +1,6 @@ /** 导出所有组件 */ import RootLayout from "./root-layout"; +import PageTransition from "./page-transition"; import DurationPicker from "./duration-picker"; import CodeEditor from "./code-editor"; import TiptapEditor from "./tiptap-editor"; @@ -19,6 +20,7 @@ import { export default [ RootLayout, + PageTransition, DurationPicker, CodeEditor, TiptapEditor, @@ -37,6 +39,7 @@ export default [ export { RootLayout, + PageTransition, DurationPicker, CodeEditor, TiptapEditor, @@ -88,6 +91,17 @@ export type { SpaceSlots } from "./space"; +export type { + PageTransitionBackground, + PageTransitionClass, + PageTransitionKeepAliveMatcher, + PageTransitionNameResolver, + PageTransitionProps, + PageTransitionRoute, + PageTransitionRouteDepthResolver, + PageTransitionRouteKeyResolver +} from "./page-transition"; + export type { CodeEditorExpose } from "./code-editor"; diff --git a/src/components/page-transition/index.ts b/src/components/page-transition/index.ts new file mode 100644 index 0000000..1b4a1d5 --- /dev/null +++ b/src/components/page-transition/index.ts @@ -0,0 +1,16 @@ +import view from "./index.vue"; +import { WebToolkit } from "timi-web"; + +export type { + PageTransitionBackground, + PageTransitionClass, + PageTransitionKeepAliveMatcher, + PageTransitionNameResolver, + PageTransitionProps, + PageTransitionRoute, + PageTransitionRouteDepthResolver, + PageTransitionRouteKeyResolver +} from "./type"; + +export const PageTransition = WebToolkit.withInstall(view); +export default PageTransition; diff --git a/src/components/page-transition/index.vue b/src/components/page-transition/index.vue new file mode 100644 index 0000000..58d3773 --- /dev/null +++ b/src/components/page-transition/index.vue @@ -0,0 +1,333 @@ + + + + + diff --git a/src/components/page-transition/type.ts b/src/components/page-transition/type.ts new file mode 100644 index 0000000..68613c3 --- /dev/null +++ b/src/components/page-transition/type.ts @@ -0,0 +1,61 @@ +import type { StyleValue } from "vue"; +import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from "vue-router"; + +/** PageTransition 可接收的路由对象。 */ +export type PageTransitionRoute = RouteLocationNormalized | RouteLocationNormalizedLoaded; + +/** 根据路由计算页面层级,用于决定前进或后退动画。 */ +export type PageTransitionRouteDepthResolver = (route: PageTransitionRoute) => number | undefined; + +/** 根据路由生成页面 key。 */ +export type PageTransitionRouteKeyResolver = (route: PageTransitionRoute) => PropertyKey; + +/** 决定当前路由是否进入 keep-alive。 */ +export type PageTransitionKeepAliveMatcher = boolean | ((route: PageTransitionRoute) => boolean); + +/** 自定义过渡名称;返回 false 或传入 false 时不使用过渡。 */ +export type PageTransitionNameResolver = + | "auto" + | string + | false + | ((to: PageTransitionRoute, from: PageTransitionRoute) => string | false); + +/** 页面容器 class 的类型。 */ +export type PageTransitionClass = string | string[] | Record; + +/** 页面容器的背景色,可以按路由动态计算。 */ +export type PageTransitionBackground = string | ((route: PageTransitionRoute) => string | undefined); + +/** PageTransition 的公开属性。 */ +export interface PageTransitionProps { + /** 过渡名称;auto 会根据路由层级使用 push-left / push-right。 */ + transition?: PageTransitionNameResolver; + /** Vue Transition 的模式。 */ + transitionMode?: "out-in" | "in-out"; + /** 是否在首次渲染时播放过渡。 */ + appear?: boolean; + /** 是否尊重系统的减少动态效果设置,默认开启。 */ + respectReducedMotion?: boolean; + /** 是否缓存页面,也可以按路由决定。默认不缓存。 */ + keepAlive?: PageTransitionKeepAliveMatcher; + /** keep-alive 最多保留的页面数量。 */ + keepAliveMax?: number; + /** 自定义路由层级解析器。 */ + getRouteDepth?: PageTransitionRouteDepthResolver; + /** 路由 query 中的层级字段名,默认是 transitionDepth。 */ + routeDepthQueryKey?: string; + /** 路由 meta 中的固定层级字段名,默认是 depth。 */ + routeDepthMetaKey?: string; + /** 动态层级的起始层级字段名,默认是 baseDepth。 */ + routeDepthBaseMetaKey?: string; + /** 标记动态层级的 meta 字段名,默认是 dynamicDepth。 */ + routeDepthDynamicMetaKey?: string; + /** 自定义路由 key,默认使用 path,避免普通 query 变化重建页面。 */ + getRouteKey?: PageTransitionRouteKeyResolver; + /** 页面容器的背景色,默认使用 TDesign 页面背景变量。 */ + pageBackground?: PageTransitionBackground; + /** 页面容器 class。 */ + pageClass?: PageTransitionClass; + /** 页面容器 style。 */ + pageStyle?: StyleValue; +}