我们考虑下面的一个例子:
var div = document.querySelectorAll('div')[0];
div.innerHTML = "<script>alert('慕课网')";
这样JavaScript 不会执行。换句话能插入script标签,但是不执行脚本代码,但是在早起的ie下面,如果设置了defer是另外,这个后面单独讲innerHTML的缺陷会提到
如果我们换成jQuery的appned方法:这样的处理代码就执行了,可见jQuery的方法内部可不是那么简单的处理了
$('div').append("<script>alert('慕课网')")
简单讲,如果.html()传入的字符串有
<script> <object> <embedt> <optiont> <style>
其中一个 .html()方法就不会用innerHTML 操作,而是用jQuery.append() 处理字符串塞入
.append()-> .domManip() -> buildFragment() ->clean() 这样的处理流程
clean() 中会动态产生一个div, 将div 的innerHTML 设为传入的字符串,再用getElementsByTagName('script') 的方式把所有的script 抓出来另行储存
clean() 执行完毕回到domManip() 中, domManip() 再将script 们一一拿出来执行
如果是外部js 就动态载入,如果是内联 js 就用eval()
总结下来,domManip主要就做了两件事:
1.根据用户传入的参数,创建了多个fragment,然后通过回调函数参数传入 2.控制script的执行过程,在创建fragment的时候不执行,最后dom操作结束后会统一执行
<!doctype html> <html> <head> <meta http-equiv="Content-type" content="text/html; charset=utf-8"/> <script src="http://code.jquery.com/jquery-latest.js"></script> <title>domManip</title> </head> <body> <button id="test1">div.innerHTML</button> <button id="test2">$.append</button> <button id="test3">模拟append实现script加载</button> <div id="test"></div> <script type="text/javascript"> //代码不执行 $("#test1").click(function() { var div = document.querySelectorAll('div')[0]; div.innerHTML = "<script>alert('慕课网')"; div.innerHTML = '代码不执行' }) //代码执行 $("#test2").click(function() { var div = $('div') div.append("<script>alert('慕课网')").append('代码执行了') }) $("#test3").click(function() { append(document.querySelectorAll('div')[0],"<script>alert('慕课网')" ) }) //==========模拟实现script加载================ function buildFragment(elems, context) { var fragment = context.createDocumentFragment(), nodes = [], i = 0, elem, l = elems.length; for (; i < l; i++) { elem = elems[i]; //创一个元素div做为容器 tmp = fragment.appendChild(context.createElement("div")); //放到文档碎片中 tmp.innerHTML = elem; } return fragment; } //关闭脚本执行 function disableScript(elem) { elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type; return elem; } //还原脚本 function restoreScript(elem) { elem.removeAttribute("type"); return elem; } function domManip(parentEles, target, callback) { var l = parentEles.length; var iNoClone = l - 1; var scripts; var hasScripts; if (l) { var fragment = buildFragment([target], parentEles[0].ownerDocument); var first = fragment.firstChild.firstChild if (first) { //"<script type="false/">alert('慕课网') //增加false标记 scripts = disableScript(first); hasScripts = true callback.call(parentEles, scripts); } //执行脚本加载 if(hasScripts){ //去掉type锁定 restoreScript(scripts); //开始执行脚本 var code = scripts.textContent.replace(/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g, ""); eval(code) } } } function append(parentEles, target) { return domManip([parentEles], target, function(elem) { parentEles.appendChild(elem) }); } </script> </body> </html>