猫史档案馆


NomenGUI & NomenNode: 何不以DOM的形式便捷的管理你的GUI界面?

用户:NomenNomen查看:2 回复:8 评论:2 创建时间:2023-07-18T10:22:37


这里是没有开场白的Nomen,相信大家很多人都用过yee还是145的GUI模板了(忘了具体是谁了qwq

但是大家也可能意识到,这种方式管理GUI界面过于抽象,并且过于散杂,所以,我根据我学了半个小时的DOM JS写出了全新的现版本GUI解决方案——节点与文档树

相信大家对DOM有所了解,在此不多赘述

实例代码:

world.onPlayerJoin(async ({ entity }) => {
    let root = new NomenGUI(entity); // 如果你觉得原来的根节点长得不好,可以自行创建新节点作为第二参数,但是千万确保这个根节点的id是NomenGUIE-Root
    await root.init(); // 初始化文档
    root.root.appendChild(new NomenNode({ // 创建一个元素,id为awa2,然后插入到文档中
        display: true,
        "data": {
            "name": "label",
            "attributes": {
                "text": "awa2",
                "fontSize": 40,
                "color": "#FF0000",
                "top": 0,
                "height": 10,
                "width": 600
            },
            "id": "awa2" // id可自定义,但是必须是全局喵里必须是玩家实体
    }))
    let u = new NomenNode({ // 创建一个元素awa3,然后插入到文档中
        display: true,
        "data": {
            "name": "label",
            "attributes": {
                "text": "awa3: 我是另一个awa",
                "fontSize": 40,
                "color": "#FF0000",
                "top": 120,
                "height": 10,
                "width": 600
            },
            "id": "awa3"
        },
        entity: entity
    });
    u.appendChild(new NomenNode({ // 在awa3下创建子元素awa4
        display: true,
        "data": {
            "name": "label",
            "attributes": {
                "text": "我是awa3的子节点,相对于awa3下挪动了114像素",
                "fontSize": 40,
                "color": "#FF0000",
                "top": 114,
                "height": 10,
                "width": 600
            },
            "id": "awa4"
        },
        entity: entity
    }));
    root.root.appendChild(u); // 将awa3插入到文档中
    u.setAttribute("text", "我是变化后的awa3,但是如果你觉得Nomen是一个很棒的人,那么,我觉得这件事情真的是是太酷辣"); // 更改awa3的text属性
    // 更多的节点方法已被支持,可以查阅DOM JS以获得更多信息
    await root.refresh(); // 重新计算文档信息
    await root.render(); // 重新初始化文档的显示

    // 或者实时修改当前元素在文档中信息
    await u.setAttributeSync("text","这是一个被实事修改的新值");

    // 还有删除元素
    root.root.removeChild(u);
    // 任何非同步操作都需要重新计算和重新显示
    await root.refresh(); // 重新计算文档信息
    await root.render(); // 重新初始化文档的显示
})

NomenGUI@1.0.0 & NomenNode@1.0.0:

class NomenNode {
    constructor({ display, bindings, data, children, entity, name }) {
        if (!entity) throw new Error("Entity is required");
        this.display = display;
        this.bindings = bindings;
        this.data = data;
        this.entity = entity;
        this.children = children || [];
        this.name = name;
        this.id = data.id || "_";
    }
    appendChild(child) {
        if (!(child instanceof NomenNode)) return;
        this.children.push(child);
        return this.children.length;
    }
    cloneNode(deep) {
        return new NomenNode({
            display: this.display,
            bindings: this.bindings,
            data: this.data,
            children: deep === true ? (this.children.map(v => v.cloneNode(true))) : this.children,
            entity: this.entity
        });
    }
    contains(otherNode) {
        return this.children.includes(otherNode);
    }
    hasChildNodes() {
        return !!this.children.length;
    }
    isSameNode(otherNode) {
        return this === otherNode;
    }
    insertBefore(newNode, referenceNode) {
        if (!(newNode instanceof NomenNode) || !~this.children.indexOf(referenceNode)) return;
        this.children.splice(this.children.indexOf(referenceNode), 0, newNode);
    }
    removeChild(child) {
        if (!~this.children.indexOf(child)) return;
        this.children.splice(this.children.indexOf(child), 1);
    }
    replaceChild(newChild, oldChild) {
        if (!(newChild instanceof NomenNode) || !~this.children.indexOf(oldChild)) return;
        this.children.splice(this.children.indexOf(oldChild), 1, newChild)
    }
    toData(isChild) {
        return isChild ? {
            attributes: { ...this.data.attributes, id: this.id, },
            name: this.data.name,
            children: this.hasChildNodes() ? this.children.map(v => v.toData(true)) : undefined
        } : {
            display: this.display,
            data: {
                attributes: { ...this.data.attributes, id: this.id, },
                name: this.data.name,
                children: this.hasChildNodes() ? this.children.map(v => v.toData(true)) : undefined
            },
        }
    }
    setAttribute(name, value) {
        this.data.attributes[name] = value;
    }
    getAttribute(name) {
        return this.data.attributes[name]
    }
    async setAttributeSync(name, value) {
        this.setAttribute(name, value);
        return await gui.setAttribute(this.entity, `#${this.data.id}`, name, value);
    }
    async getAttributeSync(name) {
        return await gui.getAttribute(this.entity, `#${this.data.id}`, name);
    }
}

class NomenGUI {
    constructor(entity, root) {
        if (NomenGUI.instance) return NomenGUI.instance;
        NomenGUI.instance = this;
        this.root = null;
        this.entity = entity;
        this._defalutroot = root instanceof NomenNode ? root : undefined;
    }
    async init(nodes) {
        if (this.root) return;
        this.nodes = nodes;
        this.bin = {};
        let size = await this.getSize();
        this.root = this._defalutroot || new NomenNode({
            display: true,
            data: {
                name: "label",
                id: "NomenGUIE-Root",
                attributes: {
                    "height": size.height,
                    "width": size.width,
                }
            },
            children: nodes ? nodes.filter(v => v instanceof NomenNode) : undefined,
            entity: this.entity
        });
    }
    async render() {
        await gui.remove(this.entity, "#NomenGUIE-Root");
        await gui.init(this.entity, this.bin);
    }
    async getSize() {
        let t = this;
        await gui.init(this.entity, {
            "NomenGUI-DSize": {
                display: true,
                data: `<dialog percentWidth="100" percentHeight="100" id="fullscreen"></dialog>`
            }
        });
        return {
            width: await gui.getAttribute(t.entity, "#fullscreen", "width"),
            height: await gui.getAttribute(t.entity, "#fullscreen", "height"),
            _remove: await gui.remove(t.entity, "#NomenGUI-DSize")
        };
    }
    async refresh(node) {
        if (!node) node = this.root;
        let size = await this.getSize();
        this.root.setAttribute("height", size.height);
        this.root.setAttribute("width", size.width);
        this.bin[`NomenGUIE${node.id}`] = node.toData();
    }
    static instance = null;
    static getInstance() {
        return this.instance;
    }
}


回复

上一页1 页 / 共 1下一页
NomenNomen

照例沙发

现在还是初代版本,有bug很正常qwq

点赞2


评论


神岛吉吉喵神岛吉吉喵

emotion_编程猫_点赞

点赞3


评论


Function函数Function函数

好耶!

点赞1


评论


yee剑走天下yee剑走天下

我没发过GUI模板啊(是编码和145还有小宏的(

点赞0


评论


LZ编编编编程猫LZ编编编编程猫

nomen竟然也出了获取屏幕分辨率的方法了))

点赞0


评论


LZ编编编编程猫LZ编编编编程猫

顶顶

点赞0


评论


NomenNomen

由于某些原因,NomenGUI停止更新与维护,但是NomenNode可能在未来进行小修改,目前NomenGUI因为其他问题已经归档

同时我也可以说一句,目前神岛的这一份GUI方案可能会在9月份大改(来自阿吉的回复),所以最好规范化接口和模块化为未来迁移做好准备

点赞0


评论


飞阁_Pallad飞阁_Pallad

不知道能不能有button option 之类可以互动的元素)

点赞0


评论