用户:
Nomen查看: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;
}
}
Nomen由于某些原因,NomenGUI停止更新与维护,但是NomenNode可能在未来进行小修改,目前NomenGUI因为其他问题已经归档
同时我也可以说一句,目前神岛的这一份GUI方案可能会在9月份大改(来自阿吉的回复),所以最好规范化接口和模块化为未来迁移做好准备
点赞0
评论