栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > Web开发 > JavaScript

深入理解javascript动态插入技术

JavaScript 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

深入理解javascript动态插入技术

最近发现各大类库都能利用div.innerHTML=HTML片断来生成节点元素,再把它们插入到目标元素的各个位置上。这东西实际上就是insertAdjacentHTML,但是IE可恶的innerHTML把这优势变成劣势。首先innerHTML会把里面的某些位置的空白去掉,见下面运行框的结果:

复制代码 代码如下:



   
       
        <BR>            IE的innerHTML By 司徒正美<BR>       
       
   

   
       


       


   

另一个可恶的地方是,在IE中以下元素的innerHTML是只读的:col、 colgroup、frameset、html、 head、style、table、tbody、 tfoot、 thead、title 与 tr。为了收拾它们,Ext特意弄了个insertIntoTable。insertIntoTable就是利用DOM的insertBefore与appendChild来添加,情况基本同jQuery。不过jQuery是完全依赖这两个方法,Ext还使用了insertAdjacentHTML。为了提高效率,所有类库都不约而同地使用了文档碎片。基本流程都是通过div.innerHTML提取出节点,然后转移到文档碎片上,然后用insertBefore与appendChild插入节点。对于火狐,Ext还使用了createContextualFragment解析文本,直接插入其目标位置上。显然,Ext的比jQuery是快许多的。不过jQuery的插入的不单是HTML片断,还有各种节点与jQuery对象。下面重温一下jQuery的工作流程吧。

复制代码 代码如下:
append: function() {
  //传入arguments对象,true为要对表格进行特殊处理,回调函数
  return this.domManip(arguments, true, function(elem){
    if (this.nodeType == 1)
      this.appendChild( elem );
  });
},
domManip: function( args, table, callback ) {
  if ( this[0] ) {//如果存在元素节点
    var fragment = (this[0].ownerdocument || this[0]).createdocumentFragment(),
    //注意这里是传入三个参数
    scripts = jQuery.clean( args, (this[0].ownerdocument || this[0]), fragment ),
    first = fragment.firstChild;

    if ( first )
      for ( var i = 0, l = this.length; i < l; i++ )
        callback.call( root(this[i], first), this.length > 1 || i > 0 ?
      fragment.cloneNode(true) : fragment );

    if ( scripts )
      jQuery.each( scripts, evalscript );
  }

  return this;

  function root( elem, cur ) {
    return table && jQuery.nodeName(elem, "table") && jQuery.nodeName(cur, "tr") ?
      (elem.getElementsByTagName("tbody")[0] ||
      elem.appendChild(elem.ownerdocument.createElement("tbody"))) :
      elem;
  }
}
//elems为arguments对象,context为document对象,fragment为空的文档碎片
clean: function( elems, context, fragment ) {
  context = context || document;

  // !context.createElement fails in IE with an error but returns typeof 'object'
  if ( typeof context.createElement === "undefined" )
  //确保context为文档对象
    context = context.ownerdocument || context[0] && context[0].ownerdocument || document;

  // If a single string is passed in and it's a single tag
  // just do a createElement and skip the rest
  //如果文档对象里面只有一个标签,如
  //我们大概可能是在外面这样调用它$(this).append("")
  //这时就直接把它里面的元素名取出来,用document.createElement("div")创建后放进数组返回
  if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
    var match = /^<(w+)s*/?>$/.exec(elems[0]);
    if ( match )
      return [ context.createElement( match[1] ) ];
  }
  //利用一个div的innerHTML创建众节点
  var ret = [], scripts = [], div = context.createElement("div");
  //如果我们是在外面这样添加$(this).append("表格1","表格1","表格1")
  //jQuery.each按它的第四种支分方式(没有参数,有length)遍历aguments对象,callback.call( value, i, value )
  jQuery.each(elems, function(i, elem){//i为索引,elem为arguments对象里的元素
    if ( typeof elem === "number" )
      elem += '';

    if ( !elem )
      return;

    // Convert html string into DOM nodes
    if ( typeof elem === "string" ) {
      // Fix "XHTML"-style tags in all browsers
      elem = elem.replace(/(<(w+)[^>]*?)/>/g, function(all, front, tag){
        return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
          all :
          front + ">";
      });

      // Trim whitespace, otherwise indexOf won't work as expected
      var tags = elem.replace(/^s+/, "").substring(0, 10).toLowerCase();

      var wrap =
        // option or optgroup
        !tags.indexOf("        [ 1, "" ] ||

        !tags.indexOf("        [ 1, "

", "
" ] ||

        tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
        [ 1, "", "
" ] ||

        !tags.indexOf("        [ 2, "", "
" ] ||

        // matched above
      (!tags.indexOf("        [ 3, "", "
" ] ||

        !tags.indexOf("        [ 2, "", "
" ] ||

        // IE can't serialize and