2-3 深入domManip(下)
本节编程练习不计算学习进度,请电脑登录imooc.com操作

深入domManip(下)

我们考虑下面的一个例子:

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操作结束后会统一执行

任务

  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
  5. <script src="http://code.jquery.com/jquery-latest.js"></script>
  6. <title>domManip</title>
  7. </head>
  8. <body>
  9.  
  10. <button id="test1">div.innerHTML</button>
  11. <button id="test2">$.append</button>
  12. <button id="test3">模拟append实现script加载</button>
  13.  
  14. <div id="test"></div>
  15.  
  16. <script type="text/javascript">
  17.  
  18. //代码不执行
  19. $("#test1").click(function() {
  20. var div = document.querySelectorAll('div')[0];
  21. div.innerHTML = "<script>alert('慕课网')";
  22. div.innerHTML = '代码不执行'
  23. })
  24.  
  25. //代码执行
  26. $("#test2").click(function() {
  27. var div = $('div')
  28. div.append("<script>alert('慕课网')").append('代码执行了')
  29. })
  30.  
  31.  
  32. $("#test3").click(function() {
  33. append(document.querySelectorAll('div')[0],"<script>alert('慕课网')" )
  34. })
  35.  
  36.  
  37.  
  38. //==========模拟实现script加载================
  39.  
  40. function buildFragment(elems, context) {
  41. var fragment = context.createDocumentFragment(),
  42. nodes = [],
  43. i = 0,
  44. elem,
  45. l = elems.length;
  46.  
  47. for (; i < l; i++) {
  48. elem = elems[i];
  49. //创一个元素div做为容器
  50. tmp = fragment.appendChild(context.createElement("div"));
  51. //放到文档碎片中
  52. tmp.innerHTML = elem;
  53. }
  54. return fragment;
  55. }
  56.  
  57. //关闭脚本执行
  58. function disableScript(elem) {
  59. elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
  60. return elem;
  61. }
  62.  
  63. //还原脚本
  64. function restoreScript(elem) {
  65. elem.removeAttribute("type");
  66. return elem;
  67. }
  68.  
  69. function domManip(parentEles, target, callback) {
  70. var l = parentEles.length;
  71. var iNoClone = l - 1;
  72. var scripts;
  73. var hasScripts;
  74. if (l) {
  75. var fragment = buildFragment([target], parentEles[0].ownerDocument);
  76. var first = fragment.firstChild.firstChild
  77. if (first) {
  78. //"<script type="false/">alert('慕课网')
  79. //增加false标记
  80. scripts = disableScript(first);
  81. hasScripts = true
  82. callback.call(parentEles, scripts);
  83. }
  84.  
  85. //执行脚本加载
  86. if(hasScripts){
  87. //去掉type锁定
  88. restoreScript(scripts);
  89. //开始执行脚本
  90. var code = scripts.textContent.replace(/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g, "");
  91. eval(code)
  92. }
  93.  
  94. }
  95.  
  96. }
  97.  
  98. function append(parentEles, target) {
  99. return domManip([parentEles], target, function(elem) {
  100. parentEles.appendChild(elem)
  101. });
  102. }
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109. </script>
  110. </body>
  111. </html>
下一节