HumanBreak/docs/guide/ui-control.md
2024-03-01 19:52:30 +08:00

7.9 KiB
Raw Blame History

UI 系统

相比于上一页,本页主要注重于 UI 控制系统的说明,通过了解控制系统,你可以让你的 UI 以你想要的方式展现出来。

mainUi 与 fixedUi

样板一个提供了两种类型的 UI 控制器,分别是 mainUi fixedUi,它们两个都能控制 UI 的显示,但是显示方式有所不同。

对于 mainUi,它主要注重于主要 UI 的显示,使用它所显示的 UI 会有明显的嵌套关系。例如,从怪物手册中打开怪物详细信息界面,从设置中打开快捷键设置界面等,这些都是由父 UI 又打开了一个子 UI有嵌套关系。而同时如果关闭了一个 UI那么它的所有子级 UI 也会一并被关闭。

而对于 fixedUi,它所显示的 UI 不再拥有嵌套关系,所有 UI 的关系都是平等的,都会一并显示,关闭 UI 时也只会关闭当前 UI不会关闭其他 UI。例如像状态栏、自定义工具栏、标记怪物等 UI 就是基于 fixedUi 的。

这两个 UI 都是 UI 控制器类 UiController 的实例。

下面我们来说明一下显示与控制 UI 的流程。

注册 UI

想要让 UI 控制器知道你想打开哪个 UI首先就要注册 UI使用 register 函数:

function register(...list: GameUi[]): void

注册的 UI 要求是一个 GameUi 实例,可以通过 new 来创建:

interface GameUi {
    new(id: string, ui: Component): GameUi
}

这里的 id 指这个 UI 的名称,ui 表示这个 UI 的内容,需要是一个导出组件,或者是函数式组件(参考 Vue 官方文档的渲染函数页面)。注册 UI 是一个模式化的方式,一般直接照葫芦画瓢即可:

const { mainUi, fixedUi } = Mota.requireAll('var');
const { m } = Mota.requireAll('fn');
const { GameUi } = Mota.requireAll('class');

const myUI = m().export();
const myUI2 = m().export();

// 注册 UI
mainUi.register(new GameUi('myUI', myUI));
// 或者一次性注册多个
mainUi.register(
    new GameUi('myUI', myUI),
    new GameUi('myUI2', myUI2)
);

打开与关闭 UI

可以使用 open 函数来打开一个 UI

function open(ui: string, vBind?: any, vOn?: any): number

其中 ui 参数表示要打开的 UI后面两个参数请参考传递参数与监听。该函数会返回一个数字,表示被打开的 UI 的唯一标识符,注意每次打开 UI 都会生成一个新的标识符,即使打开的 UI 是同一个 UI。

// 打开刚刚注册的 UI
const num = mainUi.open('myUI');

如果想要关闭 UI可以使用下面这两个函数

function close(num: number): void
function closeByName(name: string): void

前者是根据 UI 的标识符关闭 UI后者是根据 UI 名称关闭 UI对于后者会将所有名称匹配的 UI 都关闭,如果是 mainUi 上,第一个匹配的 UI 之后的所有 UI 也会全部关闭。

mainUi.close(num);
mainUi.closeByName('myUI');

传递参数与监听

与在 UI 编写页面中传递参数与监听事件类似,打开 UI 的时候也可以传递参数或监听事件,通过 open 函数的后两个参数实现。

  • vBind参数:向 UI 传递参数
  • vOn参数:监听 UI 的 emits

这两个参数都要求传入一个对象,对于 vBind,键表示参数(props)名称,值表示其值,与 UI 编写不同的是不再需要传入函数。而对于 vOn,键表示名称,不再包含 on 作为前缀,直接填写 emits 的名称即可,值是一个函数,表示事件触发时执行的内容。

对于 vBind,一定会包括下面两个参数:

  • num: 本次打开的 UI 的标识符
  • ui: UI 实例,类型是 GameUi
const myUI = m()
    .defineProps({
        id: String,
        // 直接由 UI 控制系统打开的 UI 必须拥有这两个参数
        num: Number,
        ui: GameUi
    })
    .defineEmits(['myEmits'])
    .export();
// ...此处省略注册
mainUi.open(
    'myUi',
    {
        id: 'redSlime' // 传入 id 参数,值为 'redSlime',直接是值即可,不需要是函数
    },
    {
        // 监听 myEmits 事件,触发时在控制台打印 'emitted!'
        myEmits: () => {
            console.log('emitted!');
        }
    }
)

显示方式

对于 mainUi,有两种显示方式,分别是全部显示与仅显示最后一个 UI可以通过下面两个函数设置

function showAll(): void
function showEnd(): void

其中前者是设置为全部显示,后者是只显示最后一个。在大部分时刻,mainUi 都是处于全部显示的状态。

mainUi.showAll();
mainUi.open('myUI');
mainUi.open('myUI2'); // 此时 myUI 与 myUI2 都会显示

mainUi.showEnd(); // 此时只会显示 myUI2因为它是最后一个打开的

防闪烁处理

如果你把所有 UI 全部关闭,然后立刻打开一个新的 UI会出现闪烁现象观感很差于是样板提供了下面这个函数用于防闪烁处理

function holdOn(): { end(): void }

它的作用是暂时维持下一次 UI 全部关闭时不会引起闪烁现象,之后便失效(注意只会触发一次)。该功能的原理是在调用后,如果 UI 全部关闭,那么维持 UI 根组件不会关闭,从而防止了闪烁现象。如果调用之后一直没有新的 UI 打开,那么会引起一直处于 UI 根组件打开状态,导致 UI 假死,请注意避免这种情况。

对于返回值,它是一个对象,包含一个 end 方法,调用后可以立刻关闭 UI即结束这一次的维持。

const num = mainUi.open('myUI');

// 防闪烁
const { end } = mainUi.holdOn();
mainUi.close(num);
// 这时 UI 整体不会被关闭,除非调用 end或者打开新的 UI
mainUi.open('myUI2');
// 此时防闪烁功能便会失效

高级用法

获取 GameUi 实例

可以使用 get 函数获取已经注册的 GameUi 实例:

function get(id: string): GameUi

例如,我们注册了 myUI 这个 UI可以这样获取

const myUI = mainUi.get('myUI');

事件监听

GameUiUiController 都继承自 EventEmitter(详见事件触发系统)。

对于 GameUi,它有下列事件可以被监听:

  • open(): 这个 UI 被打开时触发,无参数
  • close(): 这个 UI 被关闭时触发,无参数

对于 UiController,它有下列事件可以被监听:

  • focus(before, after): 当 UI 被聚焦时触发,before 参数表示之前聚焦的内容,也可能不存在被聚焦的内容,会是 nullafter 参数表示聚焦至哪一个 UI。该事件会在 mainUi.focusByNum 或者 mainUi.focus 函数执行后触发,这两个函数在样板中没有调用案例,如果需要可以自行调用。该事件继承自类 Focus 的事件。
  • unfocus(before): 取消任何聚焦时触发,与 focus 事件类似。该事件继承自类 Focus 的事件。
  • add(item): 打开新 UI 时触发,参数是打开的 UIGameUi 实例。该事件继承自类 Focus 的事件。
  • pop(item): 弹出最后一个 UI 时触发,参数是被弹出的 GameUi 实例。注意关闭 UI 不会触发此事件,因为关闭 UI 会使用 splice 而不是 pop。该事件继承自类 Focus 的事件。
  • splice(spliced): 当 UI 被截断(关闭)时触发,参数是被关闭的 UI 数组。该事件继承自类 Focus 的事件。
  • start(): 当 UI 根组件被打开时触发。当 UI 控制器从没有任何 UI 变成有至少一个 UI 被显示时,也即当没有 UI 打开的情况下任何 UI 被打开时,会触发此事件。无参数。
  • end(): 当 UI 根组件被关闭时触发,即当所有 UI 都被关闭时触发。无参数。