javascript - 渲染到文档嵌套的 dom 节点
问题描述
我一直在研究如何将 html 渲染到文档中,主要是为了好玩和学习。我看到了如何反应,并且大多数 vdom/hyperscript 实现都递归地呈现嵌套节点。想知道如何使用数组实现类似的功能。
所以,如果我有一个返回渲染方法的函数,它会输出一个数组。
function Comp() {
return {
render: function () {
return [
"<div>",
' <button name="button-test" type="button">test</button>',
SubComp(),
"</div>",
];
},
postRender: function (dom) {
dom
.querySelector("button[name=button-test]")
.addEventListener("click", function () {
console.log("haha");
});
},
};
}
function SubComp() {
return {
render: function () {
return [
"<div>",
' <button name="button-does-nothing" type="button">nothing</button>',
"</div>",
];
},
};
}
在上面的示例中,我可以忽略 postrender 方法,从 Comp 内部调用 SubComp().render() 方法并执行以下操作:
document.getElementById('someid').innerHTML(Comp().render().flat(Infinity).join(''));
然后在执行任何与 dom 相关的东西之后。这将嵌套我放入的任何内容。但是,例如,如果我想专门为该节点或 html 的一部分附加 dom 事件,我也会失去处理每个函数的能力。
所以我的问题是,有没有人知道我可以通过为每个函数提供可用的 dom 节点来实现这一点。然后我可以执行它的 postrender 方法(或当节点准备好时我想要使用的 wtv),然后才将它嵌套到它可能具有的外部节点中。
同样,这更像是一种练习和学习,所以请尽量不要向我推荐库或框架。
PS:如果有人知道如何,在运行时将返回的数组转换为超脚本对象也对我有用。
非常感谢。
解决方案
这就是我想出的。
我认为这可以通过减少来改善。这我目前走了多远,没有做太多的测试,但它似乎有效。
<!DOCTYPE html>
<html lang="en">
<head>
<script>
function render(component) {
if (component.preRender) {
component.preRender();
}
var thisComponent = component.render();
var thisDom = document.createElement('div');
var children = [];
thisComponent.forEach(function (c, index) {
if (typeof c === 'object' && c.hasOwnProperty('render')) {
children.push(render(c, thisDom.querySelector('div')));
thisComponent[index] = '<div id="child' + (children.length) + '"></div>';
}
});
var parsedDom = new DOMParser().parseFromString(thisComponent.flat(Infinity).join(''), 'text/html').body.childNodes;
var length = parsedDom.length;
for (var i = 0; i < length; i += 1) {
thisDom.appendChild(parsedDom[0]);
}
if (component.postRender) {
component.postRender(thisDom);
}
children.forEach(function (child, index) {
while (child.firstChild) {
var tchild = child.removeChild(child.firstChild);
thisDom.querySelector('[id=child' + (index + 1) + ']').parentElement.insertBefore(tchild, thisDom.querySelector('[id=child' + (index + 1) + ']'));
}
thisDom.querySelector('[id=child' + (index + 1) + ']').remove();
});
return thisDom;
}
</script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app"></div>
</body>
</html>
<script>
function Component() {
return {
render: function () {
return [
' <button name="button-test" type="button">test click me</button>',
'<div id="test">',
SubComponent(),
"</div>",
];
},
postRender: function (dom) {
dom
.querySelector("button[name=button-test]")
.addEventListener("click", function () {
console.log("this was added while detached haha");
});
},
};
}
function SubComponent() {
return {
render: function () {
return [
' <button name="button-does-nothing" type="button">nothing</button>',
SubSubComp(),
];
},
};
}
function SubSubComp() {
return {
render: function () {
return [
' <button name="button-does-nothing-too" type="button">does nothing as well</button>',
];
},
};
}
document.getElementById("app").appendChild(render(Component()));
</script>
因此,如果有人可以帮助改进代码,我也会接受作为答案。
另一件事,你们知道操纵分离的dom有多快吗?还是有这方面的基准?我发现只有 dom 附加到浏览器。
推荐阅读
- java - 如何将 JSON 消息转换为具有可为空字段的 avro 模式的有效 JSON?
- stored-procedures - 在我的 MySQL 存储过程中使用事务和更新查询如何确保更新完成
- hibernate - 如何使用 spring-data-jpa 和复合键保存多对多关系
- java - 如何计算肯定会在某个点结束的无限循环的时间复杂度?
- node.js - 如何从这些输入中获取数据
- prestashop - 如何修复 ContextErrorException:警告:声明
- c# - C# 引用指针
- python - 如何在 CodeHS 8.4.12:图书馆员,第 2 部分中仅打印姓氏?
- azure - 如何使用 Docker-Compose 将多个 Web Api 容器部署到 Azure
- r - 从单个 XML 创建多个 XML2 过滤