JQuery源码阅读1=>detach同级上

作者: 小遁哥 | 来源:发表于2018-04-22 11:21 被阅读2次

    $element.remove(selector)

    JQuery中大部分DOM操作API,都支持传递选择器对原集合进行过滤,不传则意味着全部

    很多方法作为公共函数,会应用到不同的场景,其中还结合了构建JQuery的核心对象。在阅读源码的过程中可以针对指定场景简单的了解下,不要过分尝试解读,比如access、clearData、buildFragment、domManip等

    1 detach和remove

    两者都用于移除,detach不会移除元素上的事件和数据。通过JQuery绑定、存储的。

    detach: function( selector ) {
        return remove( this, selector, true );
    },
    
    remove: function( selector ) {
        return remove( this, selector );
    },
    

    1.1 remove

    function remove( elem, selector, keepData ) {
    var node,
                //根据selector对elem集合进行过滤,不建议将需要逻辑处理的赋值写在一个;号里,调试器在调试代码时,一步会走一个;号
        nodes = selector ? jQuery.filter( selector, elem ) : elem,
        i = 0;
    
    for ( ; ( node = nodes[ i ] ) != null; i++ ) {
        if ( !keepData && node.nodeType === 1 ) {
                //getAll( node ) 获取node节点下的全部元素包括自身。
               //jQuery.cleanData清除事件和数据 
            jQuery.cleanData( getAll( node ) );
        }
            
        if ( node.parentNode ) {
              // jQuery.contains  当前document是否包含node
            if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
                                //标记脚本已经执行过一次
                setGlobalEval( getAll( node, "script" ) );
            }
                        //移除元素
            node.parentNode.removeChild( node );
        }
    }
    
    return elem;
    

    }

    1.2 getAll函数的源码

    function getAll( context, tag ) {
    //content 是DOM元素  tag是标签的名字
    // Support: IE <=9 - 11 only
    // Use typeof to avoid zero-argument method invocation on host objects (#15151)
    var ret;
    
    if ( typeof context.getElementsByTagName !== "undefined" ) {
        ret = context.getElementsByTagName( tag || "*" );
    
    } else if ( typeof context.querySelectorAll !== "undefined" ) {
        ret = context.querySelectorAll( tag || "*" );
    
    } else {
        ret = [];
    }
        //nodeName( context, tag )  context的节点名是否与tag相等,这个名字取得...
    if ( tag === undefined || tag && nodeName( context, tag ) ) {
                //将ret数组的内容放到[context]中
        return jQuery.merge( [ context ], ret );
    }
    
    return ret;
    }
    

    tag || "*" 的执行逻辑是 从左到右执行,一个表达式可以转化为true时(Bollean(tag))时,返回这个表达式的结果,不再继续执行。

    2 empty

    empty: function() {
        var elem,
            i = 0;
    
        for ( ; ( elem = this[ i ] ) != null; i++ ) {
            if ( elem.nodeType === 1 ) {
                                      
                                //防止内存泄漏  清除绑定事件和数据
                // Prevent memory leaks
                jQuery.cleanData( getAll( elem, false ) );
                                //清除子节点
                // Remove any remaining nodes
                elem.textContent = "";
            }
        }
    
        return this;
    },
    

    3 clone

      clone: function( dataAndEvents, deepDataAndEvents ) {
                //这里是非常值得提倡的地方,deepDataAndEvents默认是和dataAndEvents值一致,这符合大部分人对一个元素克隆行为的认知,而没有采取deepDataAndEvents不传默认就是false的写法!
        dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
        deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
                //jQuery.fn.map(this.map) => JQuery.map  map可以理解为"映射",将数据逐一处理后,返回结果的集合。 jQuery.fn.map  将返回的结果传给了pushStack,用于记录框架操作过的DOM元素
        return this.map( function() {
                        //在这里完成克隆
            return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
        } );
    },
    

    4 html

    access作为"预处理"函数用在很多地方,比如对传进来的函数求值,以及处理多个dom元素的情况等。
    在调试的过程中,如果我们不想进入这个函数中,可以在回调函数内部打一个断点,在按下F8,便可直接跳到新的断点处,再次调试时直接按F10就可以走到断点处

    html: function( value ) {
        return access( this, function( value ) {
            var elem = this[ 0 ] || {},
                i = 0,
                l = this.length;
    
            if ( value === undefined && elem.nodeType === 1 ) {
                                //获取值
                return elem.innerHTML;
            }
    
            // See if we can take a shortcut and just use innerHTML
                       //rnoInnerhtml = <script|<style|<link/i  
                      //rtagName = /<([a-z][^\/\0>\x20\t\r\n\f]+)/i  获取标签名
                      /*wrapMap 是对一些特殊元素进行包裹
                              比如td、option,td包裹上<table><tbody><tr></tr></tbody>
    </table>
                              这里是可以防止的情况有,a.不生效  比如执行下列语句$(p)[0].innerHTML= "<td></td>" 不会报错也不会有效果,b.自动生成一些标签,
    $("table"),innerHTML = "<td></td>"  会自动生成<tbody><tr></tr></tbody>
                       */
            if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
                !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
                                //对标html字符串进行一些预处理 比如<span/> 会成为<span></span>
                value = jQuery.htmlPrefilter( value );
    
                try {
                    for ( ; i < l; i++ ) {
                        elem = this[ i ] || {};
    
                        // Remove element nodes and prevent memory leaks
                        if ( elem.nodeType === 1 ) {
                                                       //清除绑定的事件和数据
                            jQuery.cleanData( getAll( elem, false ) );
                                                        //elem.innerHTML = ”div“是可以的
                            elem.innerHTML = value;
                        }
                    }
    
                    elem = 0;
    
                // If using innerHTML throws an exception, use the fallback method
                } catch ( e ) {}
            }
    
            if ( elem ) {
                                //不能通过innerHTML直接添加的通过一下方式添加 比如
                                //$("div.shadow").html($("<div>"))
                this.empty().append( value );
            }
        }, null, value, arguments.length );
    },
    

    给大家推荐一款正则表达式的可视化工具
    https://regexper.com/

    相关文章

      网友评论

        本文标题:JQuery源码阅读1=>detach同级上

        本文链接:https://www.haomeiwen.com/subject/yegxlftx.html