From 5b2f42f692b127137241d19fb9aebc79ac3172db Mon Sep 17 00:00:00 2001 From: unanmed <1319491857@qq.com> Date: Mon, 3 Mar 2025 11:10:34 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20UI=20=E7=B3=BB=E7=BB=9F=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E5=8A=A0=E5=BC=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/system/ui/container.tsx | 25 ++++++++---- src/core/system/ui/controller.ts | 70 ++++++++++++++++---------------- src/core/system/ui/instance.ts | 13 +++--- src/core/system/ui/shared.ts | 61 ++++++++++++++++++++++++---- 4 files changed, 114 insertions(+), 55 deletions(-) diff --git a/src/core/system/ui/container.tsx b/src/core/system/ui/container.tsx index 41cf988..dafcd89 100644 --- a/src/core/system/ui/container.tsx +++ b/src/core/system/ui/container.tsx @@ -1,9 +1,9 @@ -import { computed, defineComponent, VNode } from 'vue'; -import { IUIMountable, UIComponent } from './shared'; +import { defineComponent, VNode } from 'vue'; +import { IUIMountable } from './shared'; import { SetupComponentOptions } from '@/module'; export interface UIContainerProps { - controller: IUIMountable; + controller: IUIMountable; } const containerConfig = { @@ -13,18 +13,29 @@ const containerConfig = { export const UIContainer = defineComponent(props => { const data = props.controller; const back = data.backIns; - const show = computed(() => data.stack.filter(v => !v.hidden)); return (): VNode[] => { const elements: VNode[] = []; const b = back.value; if (b && data.showBack.value && !b.hidden) { elements.push( - + ); } return elements.concat( - show.value.map(v => ( - + data.stack.map(v => ( + )) ); }; diff --git a/src/core/system/ui/controller.ts b/src/core/system/ui/controller.ts index e11f048..517a494 100644 --- a/src/core/system/ui/controller.ts +++ b/src/core/system/ui/controller.ts @@ -5,9 +5,9 @@ import { IKeepController, IUIInstance, IUIMountable, - UIComponent + UIComponent, + UIProps } from './shared'; -import { Props } from '@/core/render'; import { UIInstance } from './instance'; import { computed, @@ -35,13 +35,13 @@ export const enum UIMode { Custom } -export interface IUICustomConfig { +export interface IUICustomConfig { /** * 打开一个新的 UI * @param ins 要打开的 UI 实例 * @param stack 当前的 UI 栈,还未将 UI 实例加入栈中 */ - open(ins: IUIInstance, stack: IUIInstance[]): void; + open(ins: IUIInstance, stack: IUIInstance[]): void; /** * 关闭一个 UI @@ -49,7 +49,7 @@ export interface IUICustomConfig { * @param stack 当前的 UI 栈,还未将 UI 实例移除 * @param index 这个 UI 实例在 UI 栈中的索引 */ - close(ins: IUIInstance, stack: IUIInstance[], index: number): void; + close(ins: IUIInstance, stack: IUIInstance[], index: number): void; /** * 隐藏一个 UI @@ -57,7 +57,7 @@ export interface IUICustomConfig { * @param stack 当前的 UI 栈 * @param index 这个 UI 实例在 UI 栈中的索引 */ - hide(ins: IUIInstance, stack: IUIInstance[], index: number): void; + hide(ins: IUIInstance, stack: IUIInstance[], index: number): void; /** * 显示一个 UI @@ -65,32 +65,32 @@ export interface IUICustomConfig { * @param stack 当前的 UI 栈 * @param index 这个 UI 实例在 UI 栈中的索引 */ - show(ins: IUIInstance, stack: IUIInstance[], index: number): void; + show(ins: IUIInstance, stack: IUIInstance[], index: number): void; /** * 更新所有 UI 的显示,一般会在显示模式更改时调用 * @param stack 当前的 UI 栈 */ - update(stack: IUIInstance[]): void; + update(stack: IUIInstance[]): void; } interface UIControllerEvent {} -export class UIController +export class UIController extends EventEmitter - implements IUIMountable + implements IUIMountable { static controllers: Map = new Map(); /** 当前的 ui 栈 */ - readonly stack: IUIInstance[] = reactive([]); + readonly stack: IUIInstance[] = reactive([]); /** UI 显示方式 */ mode: UIMode = UIMode.LastOnlyStack; /** 这个 UI 实例的背景,当这个 UI 处于显示模式时,会显示背景 */ - background?: IGameUI; + background?: IGameUI; /** 背景 UI 实例 */ - readonly backIns: ShallowRef | null> = shallowRef(null); + readonly backIns: ShallowRef = shallowRef(null); /** 当前是否显示背景 UI */ readonly showBack: ComputedRef = computed( () => this.userShowBack.value && this.sysShowBack.value @@ -102,7 +102,7 @@ export class UIController } /** 自定义显示模式下的配置信息 */ - private config?: IUICustomConfig; + private config?: IUICustomConfig; /** 是否维持背景 UI */ private keepBack: boolean = false; /** 用户是否显示背景 UI */ @@ -134,7 +134,7 @@ export class UIController * 设置背景 UI * @param back 这个 UI 控制器的背景 UI */ - setBackground(back: IGameUI) { + setBackground(back: IGameUI) { this.background = back; } @@ -171,13 +171,12 @@ export class UIController }; } - /** - * 打开一个 ui - * @param ui 要打开的 ui - * @param vBind 传递给这个 ui 的响应式数据 - */ - open(ui: IGameUI, vBind: Props) { - const ins = new UIInstance(ui, vBind); + open( + ui: IGameUI, + vBind: UIProps, + alwaysShow: boolean = false + ): IUIInstance { + const ins = new UIInstance(ui, vBind, alwaysShow); switch (this.mode) { case UIMode.LastOnly: case UIMode.LastOnlyStack: @@ -196,11 +195,7 @@ export class UIController return ins; } - /** - * 关闭一个 ui - * @param ui 要关闭的 ui 实例 - */ - close(ui: UIInstance) { + close(ui: IUIInstance) { const index = this.stack.indexOf(ui); if (index === -1) return; switch (this.mode) { @@ -239,7 +234,16 @@ export class UIController this.keepBack = false; } - hide(ins: IUIInstance): void { + closeAll(ui?: IGameUI): void { + if (!ui) { + this.stack.splice(0); + } else { + const list = this.stack.filter(v => v.ui === ui); + list.forEach(v => this.close(v)); + } + } + + hide(ins: IUIInstance): void { const index = this.stack.indexOf(ins); if (index === -1) return; if (this.mode === UIMode.Custom) { @@ -249,7 +253,7 @@ export class UIController } } - show(ins: IUIInstance): void { + show(ins: IUIInstance): void { const index = this.stack.indexOf(ins); if (index === -1) return; if (this.mode === UIMode.Custom) { @@ -290,7 +294,7 @@ export class UIController * 使用自定义的显示模式 * @param config 自定义显示模式的配置 */ - showCustom(config: IUICustomConfig) { + showCustom(config: IUICustomConfig) { this.mode = UIMode.Custom; this.config = config; config.update(this.stack); @@ -300,10 +304,8 @@ export class UIController * 获取一个元素上的 ui 控制器 * @param id 要获取的 ui 控制器的唯一标识符 */ - static getController( - id: string - ): UIController | null { - const res = this.controllers.get(id) as UIController; + static getController(id: string): UIController | null { + const res = this.controllers.get(id); return res ?? null; } } diff --git a/src/core/system/ui/instance.ts b/src/core/system/ui/instance.ts index ddd2468..530d517 100644 --- a/src/core/system/ui/instance.ts +++ b/src/core/system/ui/instance.ts @@ -1,5 +1,5 @@ import { Props } from '@/core/render'; -import { IGameUI, IUIInstance, UIComponent } from './shared'; +import { IGameUI, IUIInstance, UIComponent, UIProps } from './shared'; import EventEmitter from 'eventemitter3'; import { markRaw, mergeProps } from 'vue'; @@ -21,7 +21,8 @@ export class UIInstance constructor( ui: IGameUI, - public vBind: Props + public vBind: UIProps, + public readonly alwaysShow: boolean = false ) { super(); this.ui = markRaw(ui); @@ -30,13 +31,13 @@ export class UIInstance /** * 设置这个 UI 实例的响应式数据的值 * @param data 要设置的值 - * @param merge 是将传入的值与原先的值合并(true),还是将当前值覆盖掉原先的值(false) + * @param merge 是将传入的值与原先的值合并(true),还是将当前值覆盖掉原先的值(false),默认合并 */ - setVBind(data: Props, merge: boolean = true) { + setVBind(data: Partial>, merge: boolean = true) { if (merge) { - this.vBind = mergeProps(this.vBind, data) as Props; + this.vBind = mergeProps(this.vBind, data) as UIProps; } else { - this.vBind = data; + this.vBind = data as UIProps; } } diff --git a/src/core/system/ui/shared.ts b/src/core/system/ui/shared.ts index d91ec67..639ea24 100644 --- a/src/core/system/ui/shared.ts +++ b/src/core/system/ui/shared.ts @@ -3,7 +3,17 @@ import { DefineComponent, DefineSetupFnComponent, Ref, ShallowRef } from 'vue'; export type UIComponent = DefineSetupFnComponent | DefineComponent; -export interface IGameUI { +export interface UIComponentProps { + controller: IUIMountable; + instance: IUIInstance; +} + +export type UIProps = Omit< + Props, + keyof UIComponentProps +>; + +export interface IGameUI { /** 这个 UI 的名称 */ readonly name: string; /** 这个 UI 的组件 */ @@ -22,11 +32,11 @@ export interface IKeepController { unload(): void; } -export interface IUIMountable { +export interface IUIMountable { /** 当前的 UI 栈 */ - readonly stack: IUIInstance[]; + readonly stack: IUIInstance[]; /** 当前的背景 UI */ - readonly backIns: ShallowRef | null>; + readonly backIns: ShallowRef | null>; /** 当前是否显示背景 UI */ readonly showBack: Ref; @@ -34,13 +44,46 @@ export interface IUIMountable { * 隐藏一个 UI * @param ins 要隐藏的 UI 实例 */ - hide(ins: IUIInstance): void; + hide(ins: IUIInstance): void; /** * 显示一个 UI * @param ins 要显示的 UI 实例 */ - show(ins: IUIInstance): void; + show(ins: IUIInstance): void; + + /** + * 隐藏背景 UI + */ + hideBackground(): void; + + /** + * 显示背景 UI + */ + showBackground(): void; + + /** + * 打开一个 ui + * @param ui 要打开的 ui + * @param vBind 传递给这个 ui 的响应式数据 + * @param alwaysShow 这个 ui 是否保持开启,对于需要叠加显示的 ui 非常有用 + */ + open( + ui: IGameUI, + vBind: UIProps, + alwaysShow?: boolean + ): IUIInstance; + + /** + * 关闭一个 ui + * @param ui 要关闭的 ui 实例 + */ + close(ui: IUIInstance): void; + + /** + * 关闭所有或指定类型的所有 UI + */ + closeAll(ui?: IGameUI): void; /** * 维持背景,直到下次所有 UI 都被关闭 @@ -48,15 +91,17 @@ export interface IUIMountable { keep(): IKeepController; } -export interface IUIInstance { +export interface IUIInstance { /** 这个 ui 实例的唯一 key,用于 vue */ readonly key: number; /** 这个 ui 实例的 ui 信息 */ readonly ui: IGameUI; /** 传递给这个 ui 实例的响应式数据 */ - readonly vBind: Props; + readonly vBind: UIProps; /** 当前元素是否被隐藏 */ readonly hidden: boolean; + /** 是否永远保持开启 */ + readonly alwaysShow: boolean; /** * 隐藏这个 ui