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方法以后再说!

你可能感兴趣的:(JavaScript)