- 浏览: 1430423 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
luhouxiang:
写的很不错,学习了
Extjs 模块化动态加载js实践 -
kingkongtown:
如果想改成淘宝后台那样,可以在编辑器批量上传图片呢?
kissy editor 阶段体会 -
317966578:
兄弟我最近也在整jquery和caja 开放一些接口。在git ...
caja 原理 : 前端 -
liuweihug:
Javascript引擎单线程机制及setTimeout执行原 ...
setTimeout ,xhr,event 线程问题 -
辽主临轩:
怎么能让浏览器不进入 文档模式的quirks模式,进入标准的
浏览器模式与文本模式
老话题:
一般来说 innerHTML 只处理 html 即可,很方便代替冗余的dom操作,但是也有场合需要 从服务端返回一段代码+html一起付给innerHTML,
这种情况下script是并不执行的,有兴趣可以试试
<div id="scriptTest"> </div> <script type="text/javascript"> window.onload=function(){ document.getElementById("scriptTest").innerHTML="bbbb<script>alert(1);<"+"/"+"script>"; }; </script>
其原因就是:script解析与运行只在页面第一次加载过程中产生,页面加载完毕后,是不会执行script了。
而extjs 也考虑到了这个问题,比如:Ext.Element.update 不是简单的调用innerhtml ,它有 loadScripts 的参数配置,可以使得赋值给innerhtml的同时运行脚本。
Ext.Element.update (附注释):
update : function(html, loadScripts, callback){ if(typeof html == "undefined"){ html = ""; } //如果指明不包含脚本直接执行哦 if(loadScripts !== true){ this.dom.innerHTML = html; if(typeof callback == "function"){ callback(); } return this; } var id = Ext.id(); var dom = this.dom; html += '<span id="' + id + '"></span>'; //定时判断id span是否已经解析完毕,span 解析完了,那么html也解析完了,span在他前面么 //防止 html 脚本中引用到 html 中的元素 E.onAvailable(id, function(){ var hd = document.getElementsByTagName("head")[0]; //脚本识别 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig; //外部脚本识别 var srcRe = /\ssrc=([\'\"])(.*?)\1/i; var typeRe = /\stype=([\'\"])(.*?)\1/i; var match; //html中包含有脚本,提炼出来单独执行 while(match = re.exec(html)){ var attrs = match[1]; var srcMatch = attrs ? attrs.match(srcRe) : false; //外部脚本,在head中添加dom标签,动态载入脚本 if(srcMatch && srcMatch[2]){ var s = document.createElement("script"); s.src = srcMatch[2]; var typeMatch = attrs.match(typeRe); if(typeMatch && typeMatch[2]){ s.type = typeMatch[2]; } hd.appendChild(s); // 内部脚本直接运行 }else if(match[2] && match[2].length > 0){ if(window.execScript) { window.execScript(match[2]); } else { window.eval(match[2]); } } } //删除检测html节点载入完毕指示元素 var el = document.getElementById(id); if(el){Ext.removeNode(el);} if(typeof callback == "function"){ callback(); } }); //只赋值html即可,脚本在html解析完毕后单独运行 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, ""); return this; },
分析:
代码要点:
1.利用正则表达式抽出脚本单独执行。
2.防止脚本中引用插入html的元素,利用轮训等待html解析完毕后再执行脚本。(在html最后加一个指示元素)
3.IE 使用
window.execScript
使得脚本在脱离当前闭包,在全局域内运行,firefox则使用 window.eval
来脱离当前闭包,直接使用 eval
会使得在当前闭包运行。
缺点:
Ext update 不能保证脚本执行顺序问题,不像浏览器解析外部脚本有严格顺序(block特性),动态载入 互相依赖脚本 的话顺序得不到保证,解决的话,得利用队列,并根据ie的 readystatechange与firefox的onload判断脚本载入完毕
,手动保证脚本载入执行顺序,很麻烦。
改进:
由于 ext 中定时器要多次轮训判断制定 id 是否存在,其中的正则表达式其实可以缓存:
var RE_TAG = /<(\w+)/, RE_SIMPLE_TAG = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, RE_SCRIPT = /<script([^>]*)>([\s\S]*?)<\/script>/ig, RE_SCRIPT_SRC = /\ssrc=(['"])(.*?)\1/i, RE_SCRIPT_CHARSET = /\scharset=(['"])(.*?)\1/i; function setHTML(elem, html, loadScripts, callback) { if (!loadScripts) { setHTMLSimple(elem, html); S.isFunction(callback) && callback(); return; } var id = S.guid('ks-tmp-'); html += '<span id="' + id + '"></span>'; //see S.globalEval(text); //if text contains html() then will reset public shared RE_SCRIPT //so dupliacate our own var RE_SCRIPT_INNER = new RegExp(RE_SCRIPT); // 确保脚本执行时,相关联的 DOM 元素已经准备好 S.available(id, function() { var hd = S.get('head'), match, attrs, srcMatch, charsetMatch, t, s, text; //share between intervals RE_SCRIPT_INNER.lastIndex = 0; while ((match = RE_SCRIPT_INNER.exec(html))) { attrs = match[1]; srcMatch = attrs ? attrs.match(RE_SCRIPT_SRC) : false; // script via src if (srcMatch && srcMatch[2]) { s = doc.createElement('script'); s.src = srcMatch[2]; // set charset if ((charsetMatch = attrs.match(RE_SCRIPT_CHARSET)) && charsetMatch[2]) { s.charset = charsetMatch[2]; } s.async = true; // make sure async in gecko hd.appendChild(s); } // inline script else if ((text = match[2]) && text.length > 0) { S.globalEval(text); } } // 删除探测节点 (t = doc.getElementById(id)) && DOM.remove(t); // 回调 S.isFunction(callback) && callback(); }); setHTMLSimple(elem, html); }
不过需要注意的是:要复制RE_SCRIPT为RE_SCRIPT_INNER,在定时器间共享即可(每次设置 lastIndex ),不可全局共享,防止在动态执行的脚本中再调用html导致全局的RE_SCRIPT被重置!
PS: appendChild(elment) 与脚本
firefox 下当 elment 是通过 innerHTML 而包含 script 节点时,其内的脚本会执行:
// firefox 会执行 div = doc.createElement('DIV'); div.innerHTML = 'html 3<script>alert("set innerHTML via appendChild");<\/script>'; t.appendChild(div);
附录:
注意点:
1. innerHTML对于大部分 dom node 是可读可写的,但是也有例外 COL, COLGROUP, FRAMESET, HEAD, HTML, STYLE, TABLE, TBODY, TFOOT, THEAD, TITLE, TR 的innerhtml为只读。所以不能table.innerHTML= "<tr>....</tr>" 来插入行了,需要利用 div.innerHTML="<table><tr>...</tr></table>";得到 div.childNodes[0].childNodes 并插入到 table 中,以及对应 tr,thead 都有对应的嵌套标签包装,详见:KISSY.DOM.create
2.当使用 innerhtml 插入 html时,希望里面包含的 inline script 执行时,可以设置标签的defer 。(外联没用)。
3.当 html 只包含标签时,innerhtml不起作用:<script>为 NoScope元素,所以最好带个 scoped element ,例如文本节点或者input:
injectionDiv.innerHTML='<input type="hidden"/><script defer>alert("hello");</' + 'script>';
mozilla 的script机制 :一句话 defer 不保证,没用。
Have Your DOM and Script It Too
另外一种使得 html 与 script 打包运行的方法,非常巧妙。通过在原 html 后加一个 img 标签,在其 onload 内写代码即可,也省去了 extjs 例子中的 available 判断:
<p>This is the results of our Ajax call.</p> <img src="../images/loaded.gif" alt="" onload="alert('Now that I have your attention...');this.parentNode.removeChild(this);" />
发表评论
-
模块化高扩展性的前端框架 KISSY
2013-03-14 14:58 8534模块化高扩展性的前端框架 KISSY 注:本文为 2 ... -
构建前端 DSL
2012-10-11 22:10 5273目前在传统的软件开 ... -
KISSY kisses bootstrap navbar
2012-08-03 01:12 5947看了下 bootstrap 的导航菜单,立刻非常喜欢,注意是浅 ... -
promise api 与应用场景
2012-02-07 17:34 7266promise 是 commonjs 社区中提出的异步规范,其 ... -
unified event model
2011-10-14 23:02 1738为了处理原生事件在各 ... -
转载:瀑布流布局浅析
2011-09-29 19:02 2777简介 如果你经 ... -
cross domain request
2011-09-29 18:39 2779场景 跨域请求是随着 ... -
基于多继承的树设计
2011-09-18 03:42 2192分类 树是一种常见 ... -
caja 原理 : 前端
2011-09-01 16:48 6921作为前端开放的基础安全保证,caja 是目前比较合 ... -
ie 下 cloneNode 导致的属性克隆
2011-08-24 16:10 2402这个还是很值得记下,一直存在的很大隐患终于解决,由于在 ie& ... -
just another event model
2011-06-08 20:47 2116事件模型也算是客户端兼容性的一个长期问题,早期 jquery ... -
框架 build 系统介绍
2010-07-11 01:29 1576一个复杂的类库通常都包括很多子模块( jquery@git ... -
querySelectorAll 探讨
2010-07-01 22:35 4373随着css selector engine在越来越多的java ... -
再谈 attribute
2010-06-22 11:37 2557@slideshare 原生: ... -
事件机制探讨
2010-06-21 13:54 2170由于浏览器事件机制的不兼容性,譬如最常见的注册事件差异 ... -
利用Attribute重构:业务与UI分离
2010-06-08 16:54 1530很简单的一个应用 通过按钮来限制输入范围 ,这样的话再 ... -
yui3 loader的串行加载特性
2010-06-04 12:30 1764yui3 的沙箱机制可以在 ... -
yui3下的load事件触发
2010-06-01 13:31 3153以前的一些总结:页面l ... -
理解YUI3 extension:Base.create
2010-05-31 03:01 1950YUI3中为了避免不必要的类继承层次,以及摆脱利用原型链模拟的 ... -
google WebFont Loader 源码阅读
2010-05-22 01:04 2706资料: 关于新发 ...
相关推荐
如果你读过 MSDN,你会发现并非所有插入到 innerHTML 中的脚本都不能执行,如果这段脚本的 script 标签中包含了 defer 属性,IE 会正确的执行这些脚本程序。但不幸的是,Moziila/Firefox 和 Opera 可不吃这一套,...
主要介绍了innerHTML在IE中报错解决方案,需要的朋友可以参考下
innerHTML的简单应用
解决ajax返回innerHTML中javascript不能运行问题
在做 ajax 编程时,我们常常需要将 xmlhttp 获取到的页面内容通过 ... 如果你读过 MSDN,你会发现并非所有插入到 innerHTML 中的脚本都不能执行,如果这段脚本的 script 标签中包含了 defer 属性,
innerHTML的使用document.getElementById("id").innerHTML = "contenttext";
最近发现各大类库都能利用xxx[removed]=HTML片断来生成节点元素,再把它们插入到目标元素的各个位置上。这东西实际上就是insertAdjacentHTML,但是IE可恶的innerHTML把这优势变成劣势。
主要介绍了IE6-IE9中tbody的innerHTML不能赋值的解决方法,需要的朋友可以参考下
博文链接:https://aideqianfang.iteye.com/blog/246585
IE6/7/8/9中Table/Select的innerHTML不能赋值的解决方法,需要的朋友可以参考下。
innerself使用innerHTML的小视图+状态管理解决方案。 innerHTML很快。 如果您是《财富》 500强公司,甚至您的应用程序不仅仅只有少数视图,那还不够快。 但是它本身是一个使用innerHTML的小视图+状态管理解决方案。 ...
js中innerHTML与innerText的用法与区别
innerHTML 真的一个麻烦的东西。IE 和 firefox 对dom 处理的方式不是很一样。IE 对动态加载的很多dom 不支持动态更新。
超全面javaweb第4天-_08_innerHTML属性
解决问题 var jsCode = 需要执行的JS代码 var jsIframe = document.createElement(iframe); jsIframe.style.display = none;//把jsIframe隐藏起来 document.body.appendChild(jsIframe); with(window
NULL 博文链接:https://wuzhengxuan.iteye.com/blog/1263906