Ruby's Louvre

每天学习一点点算法

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

javascript 包裹节点

模仿jQuey,创建几个包裹节点的方法,发现jQuery的方法很低效啊,下一次他又可以说这几个方法可以提升了多少多少了。原理基本是这样,如果传入的是字符串,那么让它们变成一个元素节点,不过这元素节点也可以有许多层,在最内层把要包裹的元素放进。把字符串变成元素节点的方法有如下几个。1,createElement,IE可以连元素属性也一起创建,但只能创建一层。2,innerHTML,不过需要对原来的字符串进行处理,IE与FF都有许多意想不到的默认行为,可以为你多加一点东西或少加一点东西。3,createContextualFragment,由于Opera的行为有点怪异,需要选中修改元素的位置。经日本人的测试,它转换字符串成节点的效率比innerHTML高多了,也安全多了,真是强者愈强,弱者愈弱。如果是传入元素节点,需要克隆一下,要不都变成wrapAll。如果是函数,把当前元素传进去,利用它的某些属性创建一个包裹元素。

最初的实验品(这里的wrapOuter相当于jQuery的wrap):

var parseHTML = function(str) {
  if(document.createRange){
    var range = document.createRange()
    range.setStartAfter(document.body)
    return range.createContextualFragment(str)
  }else{
    return document.createElement(str)
  }
}
var wrapOuter = function(target,html){
  var wrap =  parseHTML(html) ;
  target.parentNode.insertBefore(wrap,target);
  target.previousSibling.appendChild(target)
}

发现在Opera中出了些问题,range.setStartAfter(document.body)要改成我们的目标元素才行。再者,将插入包裹元素的方式由insertBefore改为replaceChild,提高效率。

var wrapOuter = function(target,html){
  var wrap = html
  if(Object.prototype.toString.call(html) === "[object String]"){
    if(document.createRange){
      var range=document.createRange();
      range.selectNodeContents(target);
      wrap = range.createContextualFragment(html).firstChild;
    }else {
      wrap = document.createElement(str);
    }
  }
  target.parentNode.replaceChild(wrap,target);
  wrap.appendChild(target)
}

//给每个匹配元素都增加一个父元素(包裹元素),
wrap:function(html){//html可以是元素节点,也可以是html片断
    var _wrap = function(target,html){
        var wrap;
        if(is(html,"String")){
            if(document.createRange){
                var range=document.createRange();
                range.selectNodeContents(target);
                wrap = range.createContextualFragment(html).firstChild;
            }else {
                wrap = document.createElement(html);
            }
        }else if(html.nodeType){
            wrap = html.cloneNode(true)
        }
        target.parentNode.replaceChild(wrap,target);
        wrap.appendChild(target)
    }
    if(is(html,"Function")){
        return this.each(function(el,index){
            _wrap(el, html.call(el,index));
        });
    }
    return this.each(function(el){
        _wrap(el,html)
    });
 
},

把创建包裹元素的方法抽象出来:

var _parseHTML = function(el,html){
    var wrap = html ;
    if(doc.createRange){
        var range=doc.createRange();
        range.selectNodeContents(el);
        var wrap = range.createContextualFragment(html).firstChild;
        range.detach();
        return wrap;
    }else {
        return  dom.parseHTML(html);
    }
}
//给每个匹配元素都增加一个父元素(包裹元素),
wrap:function(html){//html可以是元素节点,也可以是html片断
    var _wrap = function(target,html){
        var wrap = html ;
        if(!wrap.nodeType){
            wrap = dom._parseHTML(target,html);
        }else{
            wrap = html.cloneNode(true)
        }
        target.parentNode.replaceChild(wrap,target);
        wrap.insertBefore(target,null)
    }
    if(is(html,"Function")){
        return this.each(function(el,index){
            _wrap(el, html.call(el,index));
        });
    }
    return this.each(function(el){
        _wrap(el,html)
    });
 
},
wrapInner:function(html){
    var _wrap = function(target,html){
        var wrap = html ;
        if(!wrap.nodeType){
            wrap = dom._parseHTML(target,html);
        }else{
            wrap = html.cloneNode(true)
        }
        target.insertBefore(wrap,target.firstChild);
        for(var i=1,n=target.childNodes.length;i<n;i++){
            wrap.appendChild(target.childNodes[i],null)
        }
    }
    if(is(html,"Function")){
        return this.each(function(el,index){
            _wrap(el, html.call(el,index));
        });
    }
    return this.each(function(el){
        _wrap(el,html)
    });
},
//用一个标签包裹所有匹配元素
//做法:在第一个匹配元素上添加一个父元素(包裹),然后把其他匹配元素都转移到此父元素中来
//wrapAll(html) wrapAll(elem)
wrapAll:function(html){
    var wrap = html;
    if(!wrap.nodeType)
        wrap = dom._parseHTML(this[0],html);
    this[0].parentNode.replaceChild(wrap,this[0]);
    return this.each(function(el){
        wrap.insertBefore(el,null);
    });
},

jQuery官网看一下,发现它的包裹节点的方法升级了,每次可以包裹许多层了,而我的每次只能包一层。于是决定调用我原来的parseHTML方法,见这里

var wrap = function(html){//html可以是元素节点,也可以是html片断
  var _wrap = function(target,html){
    var wrap = html ;
    if(!wrap.nodeType){
      if(doc.createRange){
        var range=doc.createRange();
        range.selectNodeContents(target);
        wrap = range.createContextualFragment(html).firstChild;
      }else{
        wrap = dom.parseHTML(html,null,true).firstChild
      }
    }else{
      wrap = html.cloneNode(true)
    }
    target.parentNode.replaceChild(wrap,target);
    while ( wrap.firstChild && wrap.firstChild.nodeType === 1 ) {
      wrap = wrap.firstChild;
    }
    wrap.insertBefore(target,null)
  }
  if(is(html,"Function")){
    return this.each(function(el,index){
      _wrap(el, html.call(el,index));
    });
  }
  return this.each(function(el){
    _wrap(el,html)
  });
   
}
//把每一个匹配元素的子节点都用东西包裹起来
var wrapInner = function(html){
  var _wrap = function(target,html){
    var wrap = html ;
    if(!wrap.nodeType){
      wrap = dom.parseHTML(html,null,true).firstChild
    }else{
      wrap = html.cloneNode(true)
    }
    target.insertBefore(wrap,target.firstChild);
    while ( wrap.firstChild && wrap.firstChild.nodeType === 1 ) {
      wrap = wrap.firstChild;
    }
    for(var i=1,n=target.childNodes.length;i<n;i++){
      wrap.appendChild(target.childNodes[i],null)
    }
  }
  if(is(html,"Function")){
    return this.each(function(el,index){
      _wrap(el, html.call(el,index));
    });
  }
  return this.each(function(el){
    _wrap(el,html)
  });
}
//用一个标签包裹所有匹配元素
//做法:在第一个匹配元素上添加一个父元素(包裹),然后把其他匹配元素都转移到此父元素中来
//wrapAll(html) wrapAll(elem)
var wrapAll = function(html){
  var wrap = html;
  if(!wrap.nodeType){
    if(doc.createRange){
      var range = doc.createRange();
      range.selectNodeContents(this[0]);
      wrap = range.createContextualFragment(html).firstChild;
    }else{
      wrap = dom.parseHTML(html,null,true).firstChild
    }
  } else{
    wrap = html.cloneNode(true)
  }
  this[0].parentNode.replaceChild(wrap,this[0]);
  while ( wrap.firstChild && wrap.firstChild.nodeType === 1 ) {
    wrap = wrap.firstChild;
  }
  return this.each(function(el){
    wrap.insertBefore(el,null);
  });
}

发现有许多重复代码,再抽象一下,对外人来说,彻底的不知所云,想必jQuery也是这样一步步搞到晦涩难懂的。

dom.mixin(dom[fn],(function(){
    
    var wrapHelper = function(target,html ){
        var wrap = html ;
        if(!wrap.nodeType){
            if(document.createRange){
                var range=dom.doc.createRange();
                range.selectNodeContents(target);
                wrap = range.createContextualFragment(html).firstChild;
            } else{
                wrap = dom.parseHTML(html,null,true).firstChild
            }
        }else{
            wrap = html.cloneNode(true)
        }
        var insertor = wrap;
        while ( insertor.firstChild && insertor.firstChild.nodeType === 1 ) {
            insertor = insertor.firstChild;
        }
        return [wrap,insertor]
    }
    
    //用一个标签包裹所有匹配元素
    //做法:在第一个匹配元素上添加一个父元素(包裹),然后把其他匹配元素都转移到此父元素中来
    //wrapAll(html) wrapAll(elem)
    var wrapAll = function(html){
        if ( dom.isFunction( html ) ) {
            return this.each(function(el,index) {
                dom(this).wrapAll( html.call(this, index));
            });
        }
        var arr = wrapHelper(this[0],html);
        var wrap = arr[0],insertor =arr[1];
        this[0].parentNode.replaceChild(wrap,this[0]);
        return this.each(function(el){
            insertor.insertBefore(el,null);
        });
    }
  //给每个匹配元素都增加一个父元素(包裹元素),
    var wrap= function( html ) {
        return this.each(function() {
            dom( this ).wrapAll( html );
        });
    }
    //把每一个匹配元素的子节点都用东西包裹起来
    var wrapInner = function(html){
        var _wrap = function(target,html){
            var arr = wrapHelper(target,html);
            var wrap = arr[0],insertor =arr[1];
            target.insertBefore(wrap,target.firstChild);
            for(var i=1,n=target.childNodes.length;i<n;i++){
                insertor.appendChild(target.childNodes[i],null)
            }
        }
        if(is(html,"Function")){
            return this.each(function(el,index){
                _wrap(el, html.call(el,index));
            });
        }
        return this.each(function(el){
            _wrap(el,html)
        });
    }
    return {
        wrapAll:wrapAll,
        wrap:wrap,
        wrapInner:wrapInner
    }
})());

unwrap方法以后再说!

如果您觉得此文有帮助,可以打赏点钱给我支付宝1669866773@qq.com ,或扫描二维码

posted on   司徒正美  阅读(3033)  评论(1编辑  收藏  举报

编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示