如何优雅的用js动态的添加html代码?

zeng_js
  • 274

如果需要在js里动态的加载一些html代码,一般会选择下面这样的方式

str="<div class="dialog"><div class="title"><img src="close.gif" alt="点击可以关闭" />亲爱的提示条</div><div class="content"><img src="delete.jpg" alt="" /><span>您真的要GG吗?</span></div><div class="bottom"><input id="Button2" type="button" value="确定" class="btn"/>&nbsp;&nbsp;<input id="Button3" type="button" value="取消" class="btn"/></div></div>"

但是感觉这样太丑了,可读性和可维护性都很差。有什么更加优雅和简洁的方式吗?

回复
阅读 69.3k
7 个回答
Humphry
  • 16.4k
✓ 已被采纳

把你想要的结构写在HTML里,用一个display:none的标签来包裹,一般而言,会使用:

  • 不设置为type="text/javascript"的script标签
  • textarea标签

<script type="text/html" id="theTemplate">
    <div class="dialog"><div class="title"><img src="close.gif" alt="点击可以关闭" />亲爱的提示条</div><div class="content"><img src="delete.jpg" alt="" /><span>您真的要GG吗?</span></div><div class="bottom"><input id="Button2" type="button" value="确定" class="btn"/>&nbsp;&nbsp;<input id="Button3" type="button" value="取消" class="btn"/></div></div>
</script>

<textarea id="theTemplate" style="display:none">
    <div class="dialog"><div class="title"><img src="close.gif" alt="点击可以关闭" />亲爱的提示条</div><div class="content"><img src="delete.jpg" alt="" /><span>您真的要GG吗?</span></div><div class="bottom"><input id="Button2" type="button" value="确定" class="btn"/>&nbsp;&nbsp;<input id="Button3" type="button" value="取消" class="btn"/></div></div>
</textarea>

使用这些标签,是为了避免这些不被直接使用的标签一被浏览器读取到就被渲染。而且这样做的话,里面的img的src也不会被浏览器自动获取。

如果你使用script标签,就可以如下代码得到它:

//使用script包裹
var template = document.getElementById("theTemplate").innerHTML ;
//使用textarea包裹
var template = document.getElementById("theTemplate").value ;

使用时textarea时要注意,textarea无法嵌套自身;script标签也无法自嵌套。

但如果文档结构是固定的,里面的数据需要动态填充呢?请参考面向数据编程

P.S. 对于innerHTML和value的使用可能会造成XSS。

动态添加HTML代码,前端若由模板导出,在JS里面写结构,或者在HTML里面写结构,这个结构对于黑客来说都是白盒的,白盒攻击相对简单,黑客可以通过阅读代码来看到哪一些代码可以被利用。比如$用户签名$,发现这里的用户签名是用户可控制的数据之后,黑客可以构造一个<img src="javascript:window.open()">之类的用户签名,未经过滤<>的话,就可以做到XSS。

因此,在面向数据编程里讲到的方案中,通过json进行动态匹配替换时,一定要保证后端输出的数据JSON里,<>等语义敏感的字符正确转义。

justjavac
  • 47.7k

https://github.com/janl/mustache.js

View:

{
  "name": {
    "first": "Michael",
    "last": "Jackson"
  },
  "age": "RIP"
}

Template:

*** {{name.first}} {{name.last}}
* {{age}}**

Output:

* Michael Jackson
* RIP

三种方案:

使用DOM

// 使用createElement创建元素
var dialog = document.createElement('div');
var img = document.createElement('img');
var btn = document.createElement('input');
var content = document.createElement('span');
// 添加class
dialog.className = 'dialog';
// 属性
img.src = 'close.gif';
// 样式
btn.style.paddingRight = '10px';
// 文本
span.innerHTML = '您真的要GG吗?';
// 在容器元素中放入其他元素
dialog.appendChild(img);
dialog.appendChild(btn);
dialog.appendChild(span);

关于添加class如果不考虑IE兼容性问题,可以使用classList方法,详细API在这里。 还有很多方法用于DOM操作,在这里

使用HTML5 template标签

<template id="dialog_tpl">
  <div class="dialog">
    <img src="" alt="">
    <input type="button" value="确认">
    <span></span>
  </div>
</template>

接着还是得使用DOM操作,只是不需要创建元素了,然后复制一份副本放入正文即可。

var dialog = document.querySelector('#dialog_tpl');
dialog.content.querySelector('img').src = 'close.gif';
dialog.content.querySelector('span').innerHTML = '您真的要GG吗?';
document.body.appendChild(dialog.content.cloneNode(true));

template标签是隐藏的,最多是用在列表中,可以产生多个副本。详细使用方法可以参考这篇文章。如果要兼容不支持template的浏览器,可以把content的部分写一个兼容方法,并且把template用CSS隐藏掉即可。

使用HTML模板

这里有各种模板,并且按语法风格分类。其实模板大同小异,就是动态修改模板文件使之成为一个可用的静态HTML文件,其实你也可以自己在需要的地方加载一部分HTML。只需要使用ajax请求一个情态的HTML文件并把返回的HTML代码放入当前的HTML中即可。

用javascript预编译模版。 我使用的是ejs,非常简单的库,几分钟看一下文档,立刻就能上手用。 国内的话还有artdialog的作者写的artTemplate,据说是最快的预编译模版。 这里有性能测试,优势十分明显: http://aui.github.io/artTemplate/

我用的是Jade。 可读性一等一的好。

如果不需要引入模版文件的依赖关系并保持HTML结构的可读性,我推荐楼主使用CoffeeScript。

为什么CoffeeScript可以解决楼主提出的问题呢?

因为它支持类似于Python的跨行字符串,这样很轻易的就能保持HTML结构的可读性,而不需要使用“+”或者采用拼数组的形式。

同时跨行字符串还支持嵌入变量和表达式,类似与PHP和Ruby的双引号。这样就避免了引入外部模版。

所以楼主的代码在CoffeeScript里面就变成了这样:

str = "
   ...
    <div>
       <img src=#{item.href} />
   </div>
   ...
"

上面的代码在WebStorm和Sublime Text中都可以得到很好的格式化支持,详细的使用例子可以看这里

CoffeeScript绝对是一个值得JavaScript爱好者投资的技术,有了它你甚至都能感觉到你写下的不是一行行的代码,而更像一行行的诗歌,每一行都那么地简洁和优雅。

惟爱玲
  • 1
新手上路,请多包涵
宣传栏