如何解决将嵌套数组转换为HTML结构
几天以来,我一直在考虑这个“简单”的练习,并且真的陷入了困境。这真让我发疯。 我需要将嵌套数组转换为HTML。这是一个数组示例:
const data = ['html',[
['head',[
['title','Your title text goes here'],]],['body',{ class: 'container' },[
['h1',{ class: 'header' },'h1 text'],['div',[
['span','span text2'],['span','span text3'],]];
,预期结果应该是这样的:
<html>
<head>
<title>your title text</title>
</head>
<body class="container">
<h1 class="header">h1 text</h1>
<div>
<span>span text2</span>
<span>span text3</span>
</div>
</body>
</html>
我从一个辅助函数开始(从数组创建每个标签),现在看起来是这样:
const tagBuilder = (arr) => {
console.log(arr)
// ['div']; ==> <div></div>
if(arr.length === 1) {
return `<${arr[0]}></${arr[0]}>`
}
// Maximum length of the pure array (without nested children) is - 3
return arr.length === 3
// ['h1','html builder example']
? `<${arr[0]} class="${arr[1].class}">${arr[2]}</${arr[0]}>`
// ['h1',{ class: 'header' }]
: arr.length === 2 && typeof arr[1] === 'object'
? `<${arr[0]} class="${arr[1].class}"></${arr[0]}>`
// ['h1','header - text']
: `<${arr[0]}>${arr[1]}</${arr[0]}>`
}
到目前为止效果很好。当我尝试创建实际的HTML构建器函数时,棘手的部分开始。我想遍历数组的每个元素,检查它是否有一个嵌套元素(子元素),保存指定的标签,然后更深入。
const buildHTML = (array) => {
let acc = ""
const iterator = (arr) => {
for(const el of arr) {
}
}
iterator(array)
return acc;
}
到目前为止,我可以迭代并保存没有嵌套数组的HTML结构,但是当Array有子级时,它会中断。我正在尝试“减少”并嵌套“地图”,但没有运气。您能给我指出解决方案还是正确的探索方法?我的猜测是最终功能应如下所示:
const textAndArrChild = ['div','span text3']];
// <div><span>span text3</span></div>
const tagBuilder = (arr) => {
// ['div']; ==> <div></div>
if(arr.length === 1) {
return `<${arr[0]}></${arr[0]}>`
}
// Maximum length of the pure array (without nested children) is - 3
return arr.length === 3
// ['h1','header - text']
: `<${arr[0]}>${arr[1]}</${arr[0]}>`
}
const buildHTML = (array) => {
return array.reduce((acc,el,index,arr) => {
if(typeof el === 'string' && Array.isArray(arr[index + 1])) {
acc = tagBuilder([el]);
// return acc += el.map(buildHTML) // TODO cause error
// need to iterate through the nested array
} else {
// insert pure tags from an array into the acc
}
return acc;
},"")
}
console.log(buildHTML(textAndArrChild))
解决方法
⚠️
⚠️⚠️
⚠️⚠️⚠️
除非这是一个练习,否则切勿以这种方式生成HTML!这是巨大的安全风险。考虑使用默认情况下进行编码/转义的模板库,例如mustache。
⚠️⚠️⚠️
⚠️⚠️
⚠️
如果您愿意更改表示标记的数据结构,则可以使此操作变得简单一些:
[tag-name tag-attribute children*]
其中子元素是字符串或其他标记数据结构。示例:
['html',{},['head',['title','Your title text goes here']],['body',{ class: 'container' },['h1',{ class: 'header' },'h1 text'],['div',['span','span text2'],'span text3']]]]
我们在子级周围使用了不必要的包装器[]
来交换必需的属性参数,如果不需要的话,该参数只是{}
。恕我直言,还不错。
如果遵守此约定,我们可以这样声明tag
函数:
const tag = (name,attr,...children) => {
// ...
};
因为我们将使用嵌套标签,所以生成完整标记的自然解决方案是使用递归:
const tag = (name,...children) => `
<${name} ${Object.entries(attr).map(([n,v]) => `${n}="${v}"`).join(' ')}>
${children.map(child => typeof child === 'string' ? child : tag(...child)).join("\n")}
</${name}>
`;
console.log(tag(...markup))
<script>
const markup =
['html','span text3']]]];
</script>
,
您可以使其变得更加简单。如果我们不考虑格式化缩进,它可能看起来像这样。
const data = ['html',[
['head',[
['title','Your title text goes here'],]],[
['h1',[
['span','span text3'],]];
const render = data =>{
let tag,attributes,childrens;
if(data.length === 2){
[tag,childrens] = data;
} else if(data.length === 3){
[tag,childrens] = data;
}
let attrStr = ""
for(let attr in attributes){
attrStr += " " + attr + '="' + attributes[attr] + '"';
}
let childrenStr = ""
if(typeof childrens !== "string"){
for(let children of childrens){
childrenStr += render(children);
}
} else {
childrenStr = childrens;
}
return (`<${tag}${attrStr}>${childrenStr}</${tag}>`)
}
console.log(render(data))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。