refactor: UI 系统类型加强

This commit is contained in:
unanmed 2025-03-03 11:10:34 +08:00
parent 109e77d6a2
commit 5b2f42f692
4 changed files with 114 additions and 55 deletions

View File

@ -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<UIComponent>;
controller: IUIMountable;
}
const containerConfig = {
@ -13,18 +13,29 @@ const containerConfig = {
export const UIContainer = defineComponent<UIContainerProps>(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(
<b.ui.component {...b.vBind} key={b.key}></b.ui.component>
<b.ui.component
{...b.vBind}
controller={data}
instance={b}
key={b.key}
hidden={b.hidden}
></b.ui.component>
);
}
return elements.concat(
show.value.map(v => (
<v.ui.component {...v.vBind} key={v.key}></v.ui.component>
data.stack.map(v => (
<v.ui.component
{...v.vBind}
key={v.key}
controller={data}
instance={v}
hidden={v.hidden}
></v.ui.component>
))
);
};

View File

@ -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<C extends UIComponent> {
export interface IUICustomConfig {
/**
* UI
* @param ins UI
* @param stack UI UI
*/
open(ins: IUIInstance<C>, stack: IUIInstance<C>[]): void;
open(ins: IUIInstance, stack: IUIInstance[]): void;
/**
* UI
@ -49,7 +49,7 @@ export interface IUICustomConfig<C extends UIComponent> {
* @param stack UI UI
* @param index UI UI
*/
close(ins: IUIInstance<C>, stack: IUIInstance<C>[], index: number): void;
close(ins: IUIInstance, stack: IUIInstance[], index: number): void;
/**
* UI
@ -57,7 +57,7 @@ export interface IUICustomConfig<C extends UIComponent> {
* @param stack UI
* @param index UI UI
*/
hide(ins: IUIInstance<C>, stack: IUIInstance<C>[], index: number): void;
hide(ins: IUIInstance, stack: IUIInstance[], index: number): void;
/**
* UI
@ -65,32 +65,32 @@ export interface IUICustomConfig<C extends UIComponent> {
* @param stack UI
* @param index UI UI
*/
show(ins: IUIInstance<C>, stack: IUIInstance<C>[], index: number): void;
show(ins: IUIInstance, stack: IUIInstance[], index: number): void;
/**
* UI
* @param stack UI
*/
update(stack: IUIInstance<C>[]): void;
update(stack: IUIInstance[]): void;
}
interface UIControllerEvent {}
export class UIController<C extends UIComponent = UIComponent>
export class UIController
extends EventEmitter<UIControllerEvent>
implements IUIMountable<C>
implements IUIMountable
{
static controllers: Map<string, UIController> = new Map();
/** 当前的 ui 栈 */
readonly stack: IUIInstance<C>[] = reactive([]);
readonly stack: IUIInstance[] = reactive([]);
/** UI 显示方式 */
mode: UIMode = UIMode.LastOnlyStack;
/** 这个 UI 实例的背景,当这个 UI 处于显示模式时,会显示背景 */
background?: IGameUI<C>;
background?: IGameUI;
/** 背景 UI 实例 */
readonly backIns: ShallowRef<IUIInstance<C> | null> = shallowRef(null);
readonly backIns: ShallowRef<IUIInstance | null> = shallowRef(null);
/** 当前是否显示背景 UI */
readonly showBack: ComputedRef<boolean> = computed(
() => this.userShowBack.value && this.sysShowBack.value
@ -102,7 +102,7 @@ export class UIController<C extends UIComponent = UIComponent>
}
/** 自定义显示模式下的配置信息 */
private config?: IUICustomConfig<C>;
private config?: IUICustomConfig;
/** 是否维持背景 UI */
private keepBack: boolean = false;
/** 用户是否显示背景 UI */
@ -134,7 +134,7 @@ export class UIController<C extends UIComponent = UIComponent>
* UI
* @param back UI UI
*/
setBackground(back: IGameUI<C>) {
setBackground(back: IGameUI) {
this.background = back;
}
@ -171,13 +171,12 @@ export class UIController<C extends UIComponent = UIComponent>
};
}
/**
* ui
* @param ui ui
* @param vBind ui
*/
open(ui: IGameUI<C>, vBind: Props<C>) {
const ins = new UIInstance(ui, vBind);
open<T extends UIComponent>(
ui: IGameUI<T>,
vBind: UIProps<T>,
alwaysShow: boolean = false
): IUIInstance<T> {
const ins = new UIInstance(ui, vBind, alwaysShow);
switch (this.mode) {
case UIMode.LastOnly:
case UIMode.LastOnlyStack:
@ -196,11 +195,7 @@ export class UIController<C extends UIComponent = UIComponent>
return ins;
}
/**
* ui
* @param ui ui
*/
close(ui: UIInstance<C>) {
close(ui: IUIInstance) {
const index = this.stack.indexOf(ui);
if (index === -1) return;
switch (this.mode) {
@ -239,7 +234,16 @@ export class UIController<C extends UIComponent = UIComponent>
this.keepBack = false;
}
hide(ins: IUIInstance<C>): 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<C extends UIComponent = UIComponent>
}
}
show(ins: IUIInstance<C>): 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<C extends UIComponent = UIComponent>
* 使
* @param config
*/
showCustom(config: IUICustomConfig<C>) {
showCustom(config: IUICustomConfig) {
this.mode = UIMode.Custom;
this.config = config;
config.update(this.stack);
@ -300,10 +304,8 @@ export class UIController<C extends UIComponent = UIComponent>
* ui
* @param id ui
*/
static getController<T extends UIComponent>(
id: string
): UIController<T> | null {
const res = this.controllers.get(id) as UIController<T>;
static getController(id: string): UIController | null {
const res = this.controllers.get(id);
return res ?? null;
}
}

View File

@ -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<C extends UIComponent>
constructor(
ui: IGameUI<C>,
public vBind: Props<C>
public vBind: UIProps<C>,
public readonly alwaysShow: boolean = false
) {
super();
this.ui = markRaw(ui);
@ -30,13 +31,13 @@ export class UIInstance<C extends UIComponent>
/**
* UI
* @param data
* @param merge truefalse
* @param merge truefalse
*/
setVBind(data: Props<C>, merge: boolean = true) {
setVBind(data: Partial<Props<C>>, merge: boolean = true) {
if (merge) {
this.vBind = mergeProps(this.vBind, data) as Props<C>;
this.vBind = mergeProps(this.vBind, data) as UIProps<C>;
} else {
this.vBind = data;
this.vBind = data as UIProps<C>;
}
}

View File

@ -3,7 +3,17 @@ import { DefineComponent, DefineSetupFnComponent, Ref, ShallowRef } from 'vue';
export type UIComponent = DefineSetupFnComponent<any> | DefineComponent;
export interface IGameUI<C extends UIComponent> {
export interface UIComponentProps<T extends UIComponent = UIComponent> {
controller: IUIMountable;
instance: IUIInstance<T>;
}
export type UIProps<C extends UIComponent = UIComponent> = Omit<
Props<C>,
keyof UIComponentProps<C>
>;
export interface IGameUI<C extends UIComponent = UIComponent> {
/** 这个 UI 的名称 */
readonly name: string;
/** 这个 UI 的组件 */
@ -22,11 +32,11 @@ export interface IKeepController {
unload(): void;
}
export interface IUIMountable<C extends UIComponent> {
export interface IUIMountable {
/** 当前的 UI 栈 */
readonly stack: IUIInstance<C>[];
readonly stack: IUIInstance<UIComponent>[];
/** 当前的背景 UI */
readonly backIns: ShallowRef<IUIInstance<C> | null>;
readonly backIns: ShallowRef<IUIInstance<UIComponent> | null>;
/** 当前是否显示背景 UI */
readonly showBack: Ref<boolean>;
@ -34,13 +44,46 @@ export interface IUIMountable<C extends UIComponent> {
* UI
* @param ins UI
*/
hide(ins: IUIInstance<C>): void;
hide(ins: IUIInstance<UIComponent>): void;
/**
* UI
* @param ins UI
*/
show(ins: IUIInstance<C>): void;
show(ins: IUIInstance<UIComponent>): void;
/**
* UI
*/
hideBackground(): void;
/**
* UI
*/
showBackground(): void;
/**
* ui
* @param ui ui
* @param vBind ui
* @param alwaysShow ui ui
*/
open<T extends UIComponent>(
ui: IGameUI<T>,
vBind: UIProps<T>,
alwaysShow?: boolean
): IUIInstance<T>;
/**
* ui
* @param ui ui
*/
close(ui: IUIInstance<UIComponent>): void;
/**
* UI
*/
closeAll(ui?: IGameUI<UIComponent>): void;
/**
* UI
@ -48,15 +91,17 @@ export interface IUIMountable<C extends UIComponent> {
keep(): IKeepController;
}
export interface IUIInstance<C extends UIComponent> {
export interface IUIInstance<C extends UIComponent = UIComponent> {
/** 这个 ui 实例的唯一 key用于 vue */
readonly key: number;
/** 这个 ui 实例的 ui 信息 */
readonly ui: IGameUI<C>;
/** 传递给这个 ui 实例的响应式数据 */
readonly vBind: Props<C>;
readonly vBind: UIProps<C>;
/** 当前元素是否被隐藏 */
readonly hidden: boolean;
/** 是否永远保持开启 */
readonly alwaysShow: boolean;
/**
* ui