足球博彩皇冠


足球博彩皇冠所有人都那么好
足球博彩皇冠我们自以为已经进入互联网时代,  信息越来越透明了,  马航事件却告诉我们:  所谓透明其实是假相——  发达的信息传播完全  可以被看不见的手所操控。  真相被交易着,于是依然扑朔迷离,  当事人的心理可以牺牲,  假戏可以继续演下去,  因为他们说,国家利益是更重要的利益。足球博彩皇冠时常,打开昔日的日记,一篇篇日记,记下了一位青年对爱情的憧憬,对爱情的追求,对爱情的向往。一首首诗歌,诗句里充满了爱的意,爱的暖,爱的美,爱的芳;诗句里洋溢着情的真,情的浓,情的韵,情的深。
足球博彩皇冠一次,我单位的一个老太太给朋友介绍了个姑娘,  见完面第二天,他兴高采烈地哼着歌去上班,  “爱江山更爱美人……”,大家听了大惊失色,  都互相询问他怎么会更爱媒人。足球博彩皇冠从此,早晨的英语晨读惹得过路人认为来了外国人;上午的语文和政治,恐怕错过了一个小注解;下午的历史和地理,重复着陌生的事件和难以理解的地名;摒弃了古怪的公式,整晚拉长着数字,一起消失在煤油灯里。
足球博彩皇冠有天闲聊,我跟老婆说到,让她下辈子投胎做男人,让她也知道下做男人的感觉,她瞬间来了一句,不就多个鸡,巴,吗?我尽然无言以对…足球博彩皇冠“你怎么一有钱就买包包啊?”“有钱当然买包包啊。你走在路上拿着爱马仕,经过的人都知道你有钱。你不能拉着每个人说:呵呵,姐昨晚吸了五万块的粉。对于我这种虚荣的人来说,得憋死。就跟搞了吴彦祖不让说一样,我图什么呀!”足球博彩皇冠相伴天涯不离分,刹叹孤身只一人。

皇冠足球比分

大发论坛时时彩平台尊龙娱乐是黑网吗海天国际娱乐城注册送钱凯发娱乐亚美国际娱乐城 金龙国际 www.am8.com 亚洲城娱乐 老k国际娱乐城 666k8.com 金威国际娱乐城 名人国际娱乐城 ag娱乐平台 V博娱乐城 澳门赌球 dedecms网上真钱赌博注册送钱e8889.com鸿海娱乐城返水申博138国际赌皇娱乐城58娱乐11元彩金捕鱼退现金的游戏朝阳棋牌百乐门国际黑彩平台排名华克山庄娱乐场

jQuery-1.9.1源码分析系列(十一) DOM操作

  DOM操作包括append、prepend、before、after、replaceWith、appendTo、prependTo、insertBefore、insertAfter、replaceAll。其核心处理函数是domManip。

  DOM操作函数中后五种方法使用的依然是前面五种方法,源码

jQuery.each({
        appendTo: "append",
        prependTo: "prepend",
        insertBefore: "before",
        insertAfter: "after",
        replaceAll: "replaceWith"
    }, function( name, original ) {
        jQuery.fn[ name ] = function( selector ) {
            var elems,
            i = 0,
            ret = [],
            insert = jQuery( selector ),
            last = insert.length - 1;

            for ( ; i <= last; i++ ) {
                elems = i === last ? this : this.clone(true);
                jQuery( insert[i] )[ original ]( elems );

                //现代浏览器调用apply会把jQuery对象当如数组,但是老版本ie需要使用.get()
                core_push.apply( ret, elems.get() );
            }

            return this.pushStack( ret );
        };
    });
View Code

  浏览器原生的插入节点的方法有两个:appendChild和inserBefore,jQuery利用这两个方法拓展了如下方法

  jQuery.fn.append使用this.appendChild( elem )

  jQuery.fn.prepend使用this.insertBefore( elem, this.firstChild )

  jQuery.fn.before使用this.parentNode.insertBefore( elem, this );

  jQuery.fn.after使用this.parentNode.insertBefore( elem, this.nextSibling );

  jQuery.fn.replaceWith 使用this.parentNode.insertBefore( elem, this.nextSibling);

  看一个例子的源码(jQuery.fn.append)

        append: function() {
            return this.domManip(arguments, true, function( elem ) {
                if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
                    this.appendChild( elem );
                }
            });
        }

  根据上面的源码。猜测domManip的作用是遍历当前jQuery对象所匹配的元素,然后每个元素调用传入的回调,并将要插入的节点(如果是字符串那么需要创建文档碎片节点)作为传入的回调的参数;并执行传入的回调。

  接下来分析domManip,看猜测是否正确。dom即Dom元素,Manip是Manipulate的缩写,连在一起的字面意思就是就是Dom操作。

 

a. domManip: function( args, table, callback )解析


  args 待插入的DOM元素或HTML代码

  table 是否需要修正tbody,这个变量是优化的结果

  callback 回调函数,执行格式为callback.call( 目标元素即上下文, 待插入文档碎片/单个DOM元素 )

  先看流程,再看细节

  第一步,变量初始化。其中iNoClone在后面会用到,如果当前的jQuery对象所匹配的元素不止一个(n > 1)的话,意味着构建出来的文档碎片需要被n用到,则需要被克隆(n-1)次,加上碎片文档本身才够n次使用;value 是第一个参数args的第一个元素,后面会对value是函数做特殊处理;

var first, node, hasScripts,
    scripts, doc, fragment,
    i = 0,
    l = this.length,
    set = this,
    iNoClone = l - 1,
    value = args[0],
    isFunction = jQuery.isFunction( value );
View Code

  第二步,处理特殊下要将当前jQuery对象所匹配的元素一一调用domManip。这种特殊情况有两种:第一种,如果传入的节点是函数(即value是函数)则需要当前jQuery对象所匹配的每个元素都将函数计算出的值作为节点代入domManip中处理。第二种,webkit下,我们不能克隆文含有checked的文档碎片;克隆的文档不能重复使用,那么只能是当前jQuery对象所匹配的每个元素都调用一次domManip处理。

//webkit下,我们不能克隆文含有checked的档碎片
if ( isFunction || !( l <= 1 || typeof value !== "string" || jQuery.support.checkClone || !rchecked.test( value ) ) ) {
    return this.each(function( index ) {
        var self = set.eq( index );
        //如果args[0]是函数,则执行函数返回结果替换原来的args[0]
        if ( isFunction ) {
            args[0] = value.call( this, index, table ? self.html() : undefined );
        }
        self.domManip( args, table, callback );
    });
}

  第三步,处理正常情况,使用传入的节点构建文档碎片,并插入文档中。这里面构建的文档碎片就需要重复使用,区别于第二步的处理。这里面需要注意的是如果是script节点需要在加载完成后执行。顺着源码顺序看一下过程

  构建文档碎片

fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
first = fragment.firstChild;

if ( fragment.childNodes.length === 1 ) {
    fragment = first;
}

  分离出其中的script,这其中有一个函数disableScript更改了script标签的type值以确保安全,原来的type值是"text/javascript",改成了"true/text/javascript"或"false/text/javascript"

scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
hasScripts = scripts.length;

  文档碎片插入页面

for ( ; i < l; i++ ) {
    node = fragment;

    if ( i !== iNoClone ) {
        node = jQuery.clone( node, true, true );

        // Keep references to cloned scripts for later restoration
        if ( hasScripts ) {
            jQuery.merge( scripts, getAll( node, "script" ) );
        }
    }

    callback.call(
        table && jQuery.nodeName( this[i], "table" ) ?
        findOrAppend( this[i], "tbody" ) :
        this[i],
        node,
        i
        );
}

  执行script,分两种情况,远程的使用ajax来处理,本地的直接执行。

if ( hasScripts ) {
    doc = scripts[ scripts.length - 1 ].ownerDocument;

    // Reenable scripts
    jQuery.map( scripts, restoreScript );

    //在第一个文档插入使执行可执行脚本
    for ( i = 0; i < hasScripts; i++ ) {
        node = scripts[ i ];
        if ( rscriptType.test( node.type || "" ) &&
            !jQuery._data( node, "globalEval" ) && jQuery.contains( doc, node ) ) {

            if ( node.src ) {
                // Hope ajax is available...
                jQuery.ajax({
                    url: node.src,
                    type: "GET",
                    dataType: "script",
                    async: false,
                    global: false,
                    "throws": true
                });
            } else {
                jQuery.globalEval( ( node.text || node.textContent || node.innerHTML || "" ).replace( rcleanScript, "" ) );
            }
        }
    }
}

  

b. dom操作拓展


jQuery.fn.text

jQuery.fn.text: function( value ) {
    return jQuery.access( this, function( value ) {
        return value === undefined ?
        jQuery.text( this ) :
        this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );
    }, null, value, arguments.length );
}

   最终执行value === undefined ? jQuery.text( this ) : this.empty().append( ( this[0] && this[0].ownerDocument || document ).createTextNode( value ) );

  其中jQuery.text = Sizzle.getText;

 

jQuery.fn.html

  函数使用jQuery.access来处理

   jQuery.fn.html: function( value ) {
            return jQuery.access( this, function( value ) {...}, null, value, arguments.length );
        }

  如果没有参数表示是取值

if ( value === undefined ) {
    return elem.nodeType === 1 ?
    elem.innerHTML.replace( rinlinejQuery, "" ) :
    undefined;
}

  否则看是否能用innerHTML添加内容。点击参考兼容问题

//看看我们是否可以走了一条捷径,只需使用的innerHTML
//需要执行的代码script|style|link等不能使用innerHTML
//htmlSerialize:确保link节点能使用innerHTML正确序列化,这就需要在IE浏览器的包装元素
//leadingWhitespace:IE strips使用.innerHTML需要以空白开头
//不是需要额外添加结束标签或外围包装标签的元素
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
    ( jQuery.support.htmlSerialize || !rnoshimcache.test( value )  ) &&
    ( jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
    !wrapMap[ ( rtagName.exec( value ) || ["", ""] )[1].toLowerCase() ] ) {

    value = value.replace( rxhtmlTag, "<1></2>" );

    try {
        for (; i < l; i++ ) {
                //移除元素节点和缓存,阻止内存泄漏
                elem = this[i] || {};
                if ( elem.nodeType === 1 ) {
                    jQuery.cleanData( getAll( elem, false ) );
                    elem.innerHTML = value;
                }
            }

            elem = 0;

        //如果使用innerHTML抛出异常,使用备用方法
    } catch(e) {}
}

  如果不能使用innerHTML或使用不成功(抛出异常),则使用备用方法append

//备用方法,使用append添加节点
if ( elem ) {
    this.empty().append( value );
}

  

jQuery.fn.wrapAll(用单个标签将所有匹配元素包裹起来)

   处理步骤:

  传入参数是函数则将函数结果传入

if ( jQuery.isFunction( html ) ) {
  return this.each(function(i) {
    jQuery(this).wrapAll( html.call(this, i) );
  });
}

  创建包裹层

//获得包裹标签 The elements to wrap the target around
var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);
if ( this[0].parentNode ) {
  wrap.insertBefore( this[0] );
}

  用包裹裹住当前jQuery对象

wrap.map(function() {
  var elem = this;
  while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {
    elem = elem.firstChild;
  }
 
  return elem;
}).append( this );

  注意:当前jQuery对象匹配的元素最好只有一个,如果有多个的话不推荐使用,这种情况慎用,后面举例可以看到。

  简单的例子,原DOM为(后面都使用这个例子)

<div id='center' class="center">
    <div id='ss' class="center">
        <input type='submit' id='left' class="left">
    </div>
</div>
<div class="right">我是right</div>

  ('#center').wrapAll("<p></p>")后,dom变成了

<p>
  <
div id="center" class="center">     <div id="ss" class="center">       <input type="submit" id="left" class="left">     </div>   </div>
</
p> <div class="right">我是right</div>

  慎用:如果当前jQuery所匹配的元素不止一个,例如原DOM执行('div').wrapAll(“<p></p>”)后结果DOM变成

<p>
  <
div id="center" class="center"></div>
  <
div id="ss" class="center"> <input type="submit" id="left" class="left"> </div>
  <
div class="right">我是right</div>
</
p>

  看到结果了吧,本来#center是#ss的父节点,结果变成了#ss的兄弟节点。

 

jQuery.fn.wrapInner(在每个匹配元素的所有子节点外部包裹指定的HTML结构)

  处理步骤:

  传入参数是函数则将函数结果传入

if ( jQuery.isFunction( html ) ) {
    return this.each(function(i) {
        jQuery(this).wrapInner( html.call(this, i) );
    });
}

  遍历jQuery对象数组,获取每个元素包含的内容(所有子节点)contents,然后使用warpAll包裹住contents

return this.each(function() {
    var self = jQuery( this ),
    contents = self.contents();

    if ( contents.length ) {
        contents.wrapAll( html );

    } else {
        self.append( html );
    }
});

  还是使用上面的例子中的原DOM,执行('div').wrapInner('<p></p>')后结果DOM变成

<div id="center" class="center">
  <p>
    <div id="ss" class="center">
      <p>
        <input type="submit" id="left" class="left">
      </p>
    </div>
  </p>
</div>
<div class="right">
  <p>
    我是right
  </p>
</div>

 

jQuery.fn.wrap(在每个匹配元素外部包裹指定的HTML结构)

  对jQuery的每个元素分别使用wrapAll包裹一下

return this.each(function(i) {
    jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
});

  执行('div').wrap('<p></p>')后结果DOM变成

<p>
  <div id="center" class="center">
    <p>
      <div id="ss" class="center">
        <input type="submit" id="left" class="left">
      </div>
    </p>
  </div>
</p>
<p>
  <div class="right">我是right</div>
</p>

 

jQuery.fn.unwrap(移除每个匹配元素的父元素)

  使用replaceWith用匹配元素父节点的所有子节点替换匹配元素的父节点。当然了父节点是body/html/document肯定是移除不了的

return this.parent().each(function() {
    if ( !jQuery.nodeName( this, "body" ) ) {
        jQuery( this ).replaceWith( this.childNodes );
    }
}).end();

  执行('div').wrap()后结果DOM变成

<div id="ss" class="center">
  <input type="submit" id="left" class="left">
</div>
<div class="right">我是right</div>

  

jQuery.fn.remove(从文档中移除匹配的元素)

  你还可以使用选择器进一步缩小移除的范围,只移除当前匹配元素中符合指定选择器的部分元素。

  与detach()相比,remove()函数会同时移除与元素关联绑定的附加数据( data()函数 )和事件处理器等(detach()会保留)。

for ( ; (elem = this[i]) != null; i++ ) {
    if ( !selector || jQuery.filter( selector, [ elem ] ).length > 0 ) {
        // detach传入的参数keepData为true,不删除缓存
        if ( !keepData && elem.nodeType === 1 ) {
            //清除缓存
            jQuery.cleanData( getAll( elem ) );
        }

        if ( elem.parentNode ) {
            if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
                setGlobalEval( getAll( elem, "script" ) );
            }
            elem.parentNode.removeChild( elem );
        }
    }
}

  可以看到其中有一个重要的函数cleanData该方法是用来清除缓存:遍历每一个节点元素,对每一个节点元素做一下处理:

  1.获取当前元素对应的缓存

id = elem[ internalKey ];
data = id && cache[ id ];

  2.如果有绑定事件,则遍历解绑事件

if ( data.events ) {
    for ( type in data.events ) {
        if ( special[ type ] ) {
            jQuery.event.remove( elem, type );

        //这是一个快捷方式,以避免jQuery.event.remove的开销
        } else {
            jQuery.removeEvent( elem, type, data.handle );
        }
    }
}

  3.如果jQuery.event.remove没有移除cache,则手动移除cache。其中IE需要做一些兼容处理,而且最终会将删除历史保存如core_deletedIds中

//当jQuery.event.remove没有移除cache的时候,移除cache
if ( cache[ id ] ) {

    delete cache[ id ];

    //IE不允许从节点使用delete删除expando特征,
    //也能对文件节点使用removeAttribute函数;
    //我们必须处理所有这些情况下,
    if ( deleteExpando ) {
        delete elem[ internalKey ];

    } else if ( typeof elem.removeAttribute !== core_strundefined ) {
        elem.removeAttribute( internalKey );

    } else {
        elem[ internalKey ] = null;
    }

    core_deletedIds.push( id );
}

 

jQuery.fn.detach

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

 

jQuery.fn.empty(清空每个匹配元素内的所有内容(所有子节点))

  函数将会移除每个匹配元素的所有子节点(包括文本节点、注释节点等所有类型的节点),会清空相应的缓存数据。

for ( ; (elem = this[i]) != null; i++ ) {
    //防止内存泄漏移除元素节点缓存
    if ( elem.nodeType === 1 ) {
        jQuery.cleanData( getAll( elem, false ) );
    }

    //移除所有子节点
    while ( elem.firstChild ) {
        elem.removeChild( elem.firstChild );
    }

    // IE<9,select节点需要将option置空
    if ( elem.options && jQuery.nodeName( elem, "select" ) ) {
        elem.options.length = 0;
    }
}

 

jQuery.fn.clone(克隆当前匹配元素集合的一个副本,并以jQuery对象的形式返回)

  克隆是一个比较重要的功能,下一章再细细分析

 

  如果觉得本文不错,请点击右下方【推荐】!

posted @ 2015-11-24 18:03 chua1989 阅读(...) 评论(...) 编辑 收藏