温馨提示:本文翻译自stackoverflow.com,查看原文请点击:其他 - How to build html from template in javaScript?
javascript

其他 - 如何从javaScript中的模板构建HTML?

发布于 2020-03-27 15:35:38

我有模板,我需要构建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>

查看更多

查看更多

提问者
Lex27
被浏览
11
CertainPerformance 2020-01-31 19:35

You might consider creating a structure with objects instead - that way, you can just look up the .class property of the object, or the .contents property of the object, or the .tag property of the object, the process will probably make a whole lot more sense at a glance. The only real non-trivial logic involved is checking if the .contents is an array (in which case, recursively .map them by tagBuilder and join by the empty string):

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));

If you need newlines between tags and pretty-printed HTML too (which usually shouldn't matter), then pass along an indent parameter too, which gets added to the start of tag lines (and the start of end-tag lines, when that tag contains non-text children):

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结构(由于逻辑混乱,我会认为这是一个错误),然后从数组中提取标记,内容和className,然后执行完全相同的操作:

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));