首页 > 解决方案 > 如何从javascript中的模板构建html?

问题描述

我有模板,我需要构建 html。我可以解析每个元素,但在尝试构建所有 html 时卡住了。我的代码暂时不起作用。并且可能我的方式是错误的,它应该是另一种从模板制作 html 的方法。任何人都可以帮忙吗?

const data = ['html', [
  ['head', [
    ['title', 'titletext'],
  ]],
  ['body', { class: 'bodyClass' }, [
    ['h1', { class: 'headerClass' }, 'h1text'],
    ['div', [
      ['span', 'span1text'],
      ['span', 'span2text'],
    ]], 
  ]],  
]];

const tagBuilder = (tagArray) => {
  if (tagArray[1] instanceof Array) {
    return tagBuilder(tagArray[1]);
  }
  if (tagArray[1] instanceof Object) {
    return `<${tagArray[0]} class="${tagArray[1].class}">` + String(tagArray[2]) + `</${tagArray[0]}>`;
  } 
  return `<${tagArray[0]}>` + String(tagArray[1]) + `</${tagArray[0]}>`;
}

const htmpBuilder = (data) => {
  return data.map(element => tagBuilder(element));
};

document.getElementById("output").textContent = htmpBuilder(data);
<pre id="output">
</pre>

我需要的输出:

<html>
  <head>
    <title>titletext</title>
  </head>
  <body class="bodyClass">
    <h1 class="headerClass">h1text</h1>
    <div>
      <span>span1text</span>
      <span>span2text</span>
    </div>
  </body>
</html>

标签: javascript

解决方案


您可能会考虑使用对象创建一个结构 - 这样,您只需查找.class对象的属性,或对象的.contents属性,或对象的.tag属性,该过程可能会更有意义一眼。所涉及的唯一真正重要的逻辑是检查是否.contents是一个数组(在这种情况下,递归.map它们tagBuilder并通过空字符串连接):

const data = {
  tag: 'html',
  contents: [
    {
      tag: 'head',
      contents: [{
        tag: 'title',
        contents: 'titletext'
      }]
    }, {
      tag: 'body',
      class: 'bodyClass',
      contents: [{
        tag: 'h1',
        class: 'headerClass',
        contents: 'h1text'
      }, {
        tag: 'div',
        contents: [{
          tag: 'span',
          contents: 'span1text'
        }, {
          tag: 'span',
          contents: 'span2text'
        }]
      }]
    }
 ]
};
    

const tagBuilder = ({ tag, class: className, contents = '' }) => {
  const contentsStr = Array.isArray(contents)
    ? contents.map(tagBuilder).join('')
    : contents;
  return `<${tag}${className ? ` class="${className}"` : ''}>${contentsStr}</${tag}>`;
}

console.log(tagBuilder(data));

如果您也需要标签和漂亮打印的 HTML 之间的换行符(这通常无关紧要),那么indent也传递一个参数,该参数被添加到标签行的开头(以及结束标签行的开头,当该标签包含非文本子项):

const data = {
  tag: 'html',
  contents: [
    {
      tag: 'head',
      contents: [{
        tag: 'title',
        contents: 'titletext'
      }]
    }, {
      tag: 'body',
      class: 'bodyClass',
      contents: [{
        tag: 'h1',
        class: 'headerClass',
        contents: 'h1text'
      }, {
        tag: 'div',
        contents: [{
          tag: 'span',
          contents: 'span1text'
        }, {
          tag: 'span',
          contents: 'span2text'
        }]
      }]
    }
 ]
};
    

const tagBuilder = ({ tag, class: className, contents = '' }, indent = 0) => {
  const contentsStr = Array.isArray(contents)
    ? '\n' + contents.map(item => ' '.repeat(indent + 2) + tagBuilder(item, indent + 2)).join('\n') + '\n'
    : contents;
  return `<${tag}${className ? ` class="${className}"` : ''}>${contentsStr}${Array.isArray(contents) ? ' '.repeat(indent) : ''}</${tag}>`;
}

console.log(tagBuilder(data));

如果您必须使用原始data结构(我认为这是一个错误,因为它需要混淆逻辑),然后从数组中提取标签、内容和类名,然后执行完全相同的操作:

const data = ['html', [
  ['head', [
    ['title', 'titletext'],
  ]],
  ['body', { class: 'bodyClass' }, [
    ['h1', { class: 'headerClass' }, 'h1text'],
    ['div', [
      ['span', 'span1text'],
      ['span', 'span2text'],
    ]], 
  ]],  
]];

    

const tagBuilder = (arr, indent = 0) => {
  const tag = arr.shift();
  const className = !Array.isArray(arr[0]) && typeof arr[0] === 'object'
    ? arr.shift().class
    : '';
  const contents = arr.length
    ? arr.shift()
    : '';
  const contentsStr = Array.isArray(contents)
    ? '\n' + contents.map(item => ' '.repeat(indent + 2) + tagBuilder(item, indent + 2)).join('\n') + '\n'
    : contents;
  return `<${tag}${className ? ` class="${className}"` : ''}>${contentsStr}${Array.isArray(contents) ? ' '.repeat(indent) : ''}</${tag}>`;
}

console.log(tagBuilder(data));


推荐阅读