欧美亚洲中文,在线国自产视频,欧洲一区在线观看视频,亚洲综合中文字幕在线观看

      1. <dfn id="rfwes"></dfn>
          <object id="rfwes"></object>
        1. 站長資訊網(wǎng)
          最全最豐富的資訊網(wǎng)站

          jQuery的設(shè)計(jì)模式是什么

          jQuery中的設(shè)計(jì)模式有:1、組合模式,描述了一組對象可像單個(gè)對象一樣的對待;2、適配器模式;3、外觀模式;4、觀察者模式;5、迭代器模式;6、惰性初始模式;7、代理模式;8、建造者模式。

          jQuery的設(shè)計(jì)模式是什么

          本教程操作環(huán)境:windows7系統(tǒng)、jquery3.5版本、Dell G3電腦。

          推薦教程:jQuery教程

          jQuery中的設(shè)計(jì)模式

          jQuery是目前最流行的JavaScript DOM操作庫,它提供了一個(gè)在安全和跨瀏覽器的方式下與DOM交互的抽象層。有意思的是,這個(gè)庫也可以作為一個(gè)例子,來展示設(shè)計(jì)模式如何有效的創(chuàng)建既可讀又易用的API。

          雖然在很多情況下,撰寫jQuery的主要貢獻(xiàn)者并沒有打算使用特定的模式,但是這些設(shè)計(jì)模式確實(shí)存在,而且對我們學(xué)習(xí)來說,非常有用。

          組合模式

          組合模式 描述了一組對象可像單個(gè)對象一樣的對待。

          這允許我們能統(tǒng)一的處理單個(gè)對象或多個(gè)對象。這意味著無論是一個(gè)對象還是一千個(gè)對象我們都能以同樣的行為來處理。

          在Jquery中,當(dāng)我們在一個(gè)節(jié)點(diǎn)或多個(gè)節(jié)點(diǎn)上應(yīng)用方法時(shí),我們都能以相同的方式來選擇并返回JQuery對象。

          下面這個(gè)演示我們將使用Jquery的選擇器。對單一元素(比如擁有唯一ID的元素)或擁有相同標(biāo)簽或Class的一組元素添加名為active的class,對待它們使用上并無不同:

          // 單一節(jié)點(diǎn) $( "#singleItem" ).addClass( "active" ); $( "#container" ).addClass( "active" );  // 一組節(jié)點(diǎn) $( "div" ).addClass( "active" ); $( ".item" ).addClass( "active" ); $( "input" ).addClass( "active" );

          JQuery的addClass()實(shí)現(xiàn)中直接使用原生的for循環(huán)、Jquery的JQuery.each()、Jquery.fn.each來迭代一個(gè)集合以達(dá)到能同時(shí)處理一個(gè)或一組元素的目的。請看下面的例子:

           addClass: function( value ) {   var classNames, i, l, elem,     setClass, c, cl;    if ( jQuery.isFunction( value ) ) {     return this.each(function( j ) {       jQuery( this ).addClass( value.call(this, j, this.className) );     });   }    if ( value && typeof value === "string" ) {     classNames = value.split( rspace );      for ( i = 0, l = this.length; i < l; i++ ) {       elem = this[ i ];        if ( elem.nodeType === 1 ) {         if ( !elem.className && classNames.length === 1 ) {           elem.className = value;          } else {           setClass = " " + elem.className + " ";            for ( c = 0, cl = classNames.length; c < cl; c++ ) {             if ( !~setClass.indexOf( " " + classNames[ c ] + " " ) ) {               setClass += classNames[ c ] + " ";             }           }           elem.className = jQuery.trim( setClass );         }       }     }   }    return this; }

          適配器模式

          適配器模式 將一個(gè)對象或者類的接口翻譯成某個(gè)指定的系統(tǒng)可以使用的另外一個(gè)接口。

          適配器基本上允許本來由于接口不兼容而不能一起正常工作的對象或者類能夠在一起工作.適配器將對它接口的調(diào)用翻譯成對原始接口的調(diào)用,而實(shí)現(xiàn)這樣功能的代碼通常是最簡的。

          我們可能已經(jīng)用過的一個(gè)適配器的例子就是jQuery的jQuery.fn.css()方法,這個(gè)方法幫助規(guī)范了不同瀏覽器之間樣式的應(yīng)用方式,使我們使用簡單的語法,這些語法被適配成為瀏覽器背后真正支持的語法:

          // Cross browser opacity: // opacity: 0.9;  Chrome 4+, FF2+, Saf3.1+, Opera 9+, IE9, iOS 3.2+, Android 2.1+ // filter: alpha(opacity=90);  IE6-IE8  // Setting opacity $( ".container" ).css( { opacity: .5 } );  // Getting opacity var currentOpacity = $( ".container" ).css('opacity');

          將上面的代碼變得可行的相應(yīng)的jQuery核心css鉤子在下面:

          get: function( elem, computed ) {  // IE uses filters for opacity  return ropacity.test( (        computed && elem.currentStyle ?            elem.currentStyle.filter : elem.style.filter) || "" ) ?    ( parseFloat( RegExp.$1 ) / 100 ) + "" :    computed ? "1" : ""; },  set: function( elem, value ) {  var style = elem.style,    currentStyle = elem.currentStyle,    opacity = jQuery.isNumeric( value ) ?          "alpha(opacity=" + value * 100 + ")" : "",    filter = currentStyle && currentStyle.filter || style.filter || "";   // IE has trouble with opacity if it does not have layout  // Force it by setting the zoom level  style.zoom = 1;   // if setting opacity to 1, and no other filters  //exist - attempt to remove filter attribute #6652  if ( value >= 1 && jQuery.trim( filter.replace( ralpha, "" ) ) === "" ) {     // Setting style.filter to null, "" & " " still leave    // "filter:" in the cssText if "filter:" is present at all,    // clearType is disabled, we want to avoid this style.removeAttribute    // is IE Only, but so apparently is this code path...    style.removeAttribute( "filter" );     // if there there is no filter style applied in a css rule, we are done    if ( currentStyle && !currentStyle.filter ) {      return;    }  }   // otherwise, set new filter values  style.filter = ralpha.test( filter ) ?    filter.replace( ralpha, opacity ) :    filter + " " + opacity; } };

          外觀模式

          正如我們早前在書中提過的, 沒面模式為一個(gè)龐大的(可能更復(fù)雜的)代碼結(jié)構(gòu)提供了一個(gè)更簡單的抽象接口。

          門面在jQuery庫中能夠經(jīng)常見到,它們?yōu)殚_發(fā)者處理DOM節(jié)點(diǎn),動(dòng)畫或者令人特別感興趣的跨域Ajax提供了簡單的實(shí)現(xiàn)入口。

          下面的代碼是jQuery $.ajax()方法的門面:

          $.get( url, data, callback, dataType ); $.post( url, data, callback, dataType ); $.getJSON( url, data, callback ); $.getScript( url, callback );

          這些方法背后真正執(zhí)行的代碼是這樣的:

          // $.get() $.ajax({   url: url,   data: data,   dataType: dataType }).done( callback );  // $.post $.ajax({   type: "POST",   url: url,   data: data,   dataType: dataType }).done( callback );  // $.getJSON() $.ajax({   url: url,   dataType: "json",   data: data, }).done( callback );  // $.getScript() $.ajax({   url: url,   dataType: "script", }).done( callback );

          更有趣的是,上面代碼中的門面實(shí)際上是它們自身具有的能力,它們隱藏了代碼背后很多復(fù)雜的操作。

          這是因?yàn)閖Query.ajax()在jQuery核心代碼中的實(shí)現(xiàn)是一段不平凡的代碼,至少是這樣的。至少它規(guī)范了XHR(XMLHttpRequest)之間的差異而且讓我們能夠簡單的執(zhí)行常見的HTTP動(dòng)作(比如:get、post等),以及處理延遲等等。

          由于顯示與上面所講的門面相關(guān)的代碼將會(huì)占據(jù)整個(gè)章節(jié),這里僅僅給出了jQuery核心代碼中規(guī)劃化XHR的代碼:

          // Functions to create xhrs function createStandardXHR() {   try {     return new window.XMLHttpRequest();   } catch( e ) {} }  function createActiveXHR() {   try {     return new window.ActiveXObject( "Microsoft.XMLHTTP" );   } catch( e ) {} }  // Create the request object jQuery.ajaxSettings.xhr = window.ActiveXObject ?   /* Microsoft failed to properly    * implement the XMLHttpRequest in IE7 (can't request local files),    * so we use the ActiveXObject when it is available    * Additionally XMLHttpRequest can be disabled in IE7/IE8 so    * we need a fallback.    */   function() {     return !this.isLocal && createStandardXHR() || createActiveXHR();   } :   // For all other browsers, use the standard XMLHttpRequest object   createStandardXHR;   ...

          下面的代碼也處于實(shí)際的jQuery XHR(jqXHR)實(shí)現(xiàn)的上層,它是我們實(shí)際上經(jīng)常打交道的方便的門面:

          // Request the remote document    jQuery.ajax({      url: url,      type: type,      dataType: "html",      data: params,      // Complete callback (responseText is used internally)      complete: function( jqXHR, status, responseText ) {        // Store the response as specified by the jqXHR object        responseText = jqXHR.responseText;        // If successful, inject the HTML into all the matched elements        if ( jqXHR.isResolved() ) {          // Get the actual response in case          // a dataFilter is present in ajaxSettings          jqXHR.done(function( r ) {            responseText = r;          });          // See if a selector was specified          self.html( selector ?            // Create a dummy div to hold the results            jQuery("  <div>     ")              // inject the contents of the document in, removing the scripts              // to avoid any 'Permission Denied' errors in IE              .append(responseText.replace(rscript, ""))               // Locate the specified elements              .find(selector) :             // If not, just inject the full result            responseText );        }         if ( callback ) {          self.each( callback, [ responseText, status, jqXHR ] );        }      }    });     return this;  }  </div>

          觀察者模式

          另一個(gè)我們之前提到過的模式就是觀察者(發(fā)布/訂閱)模式.這種模式下,系統(tǒng)中的對象可以在關(guān)注的事件發(fā)生的時(shí)候給其他對象發(fā)送消息,也可以被其他對象所通知。

          jQuery核心庫很多年前就已經(jīng)提供了對于類似于發(fā)布/訂閱系統(tǒng)的支持,它們稱之為定制事件。

          jQuery的早期版本中,可以通過使用jQuery.bind()(訂閱),jQuery.trigger()(發(fā)布),和jQuery.unbind()(取消訂閱)來使用這些定制事件,但在近期的版本中,這些都可以通過使用jQuery.on(),jQuery.trigger()和jQuery.off()來完成。

          下面我們來看一下實(shí)際應(yīng)用中的一個(gè)例子:

          // Equivalent to subscribe(topicName, callback) $( document ).on( "topicName" , function () {     //..perform some behaviour });  // Equivalent to publish(topicName) $( document ).trigger( "topicName" );  // Equivalent to unsubscribe(topicName) $( document ).off( "topicName" );

          對于jQuery.on()和jQuery.off()的調(diào)用最后會(huì)經(jīng)過jQuery的事件系統(tǒng),與Ajax一樣,由于它們的實(shí)現(xiàn)代碼相對較長,我們只看一下實(shí)際上事件處理器是在哪兒以及如何將定制事件加入到系統(tǒng)中的:

          jQuery.event = {    add: function( elem, types, handler, data, selector ) {      var elemData, eventHandle, events,       t, tns, type, namespaces, handleObj,       handleObjIn, quick, handlers, special;      ...      // Init the element's event structure and main handler,     //if this is the first     events = elemData.events;     if ( !events ) {       elemData.events = events = {};     }     ...      // Handle multiple events separated by a space     // jQuery(...).bind("mouseover mouseout", fn);     types = jQuery.trim( hoverHack(types) ).split( " " );     for ( t = 0; t < types.length; t++ ) {        ...        // Init the event handler queue if we're the first       handlers = events[ type ];       if ( !handlers ) {         handlers = events[ type ] = [];         handlers.delegateCount = 0;          // Only use addEventListener/attachEvent if the special         // events handler returns false         if ( !special.setup || special.setup.call( elem, data,         //namespaces, eventHandle ) === false ) {           // Bind the global event handler to the element           if ( elem.addEventListener ) {             elem.addEventListener( type, eventHandle, false );            } else if ( elem.attachEvent ) {             elem.attachEvent( "on" + type, eventHandle );           }         }       }

          對于那些喜歡使用傳統(tǒng)的命名方案的人, Ben Alamn對于上面的方法提供了一個(gè)簡單的包裝,然后為我們提供了jQuery.publish(),jQuery.subscribe和jQuery.unscribe方法。我之前在書中提到過,現(xiàn)在我們可以完整的看一下這個(gè)包裝器。

          (function( $ ) {    var o = $({});    $.subscribe = function() {     o.on.apply(o, arguments);   };    $.unsubscribe = function() {     o.off.apply(o, arguments);   };    $.publish = function() {     o.trigger.apply(o, arguments);   };  }( jQuery ));

          在近期的jQuery版本中,一個(gè)多目的的回調(diào)對象(jQuery.Callbacks)被提供用來讓用戶在回調(diào)列表的基礎(chǔ)上寫新的方案。另一個(gè)發(fā)布/訂閱系統(tǒng)就是一個(gè)使用這個(gè)特性寫的方案,它的實(shí)現(xiàn)方式如下:

          var topics = {};  jQuery.Topic = function( id ) {     var callbacks,         topic = id && topics[ id ];     if ( !topic ) {         callbacks = jQuery.Callbacks();         topic = {             publish: callbacks.fire,             subscribe: callbacks.add,             unsubscribe: callbacks.remove         };         if ( id ) {             topics[ id ] = topic;         }     }     return topic; };

          然后可以像下面一樣使用:

          // Subscribers $.Topic( "mailArrived" ).subscribe( fn1 ); $.Topic( "mailArrived" ).subscribe( fn2 ); $.Topic( "mailSent" ).subscribe( fn1 );  // Publisher $.Topic( "mailArrived" ).publish( "hello world!" ); $.Topic( "mailSent" ).publish( "woo! mail!" );  //  Here, "hello world!" gets pushed to fn1 and fn2 //  when the "mailArrived" notification is published //  with "woo! mail!" also being pushed to fn1 when //  the "mailSent" notification is published.  // Outputs: // hello world! // fn2 says: hello world! // woo! mail!

          迭代器模式

          迭代器模式中,迭代器(允許我們遍歷集合中所有元素的對象)順序迭代一個(gè)集合對象中的元素而無需暴漏其底層形式。

          迭代器封裝了這種特別的迭代操作的內(nèi)部結(jié)構(gòu),就jQuery的jQuery.fn.each()迭代器來說,我們實(shí)際上可以使用jQuery.each()底層的代碼來迭代一個(gè)集合,而無需知道或者理解后臺(tái)提供這種功能的代碼是如何實(shí)現(xiàn)的。

          這種模式可以被理解為門面模式的一種特例,在這里我們只處理與迭代有關(guān)的問題。

          $.each( ["john","dave","rick","julian"] , function( index, value ) {   console.log( index + ": "" + value); });  $( "li" ).each( function ( index ) {   console.log( index + ": " + $( this ).text()); });

          這里我們可以看到j(luò)Query.fn.each()的代碼:

          // Execute a callback for every element in the matched set. each: function( callback, args ) {   return jQuery.each( this, callback, args ); }

          在jQuery.each()方法后面的代碼提供了兩種迭代對象的方法:

          each: function( object, callback, args ) {   var name, i = 0,     length = object.length,     isObj = length === undefined || jQuery.isFunction( object );    if ( args ) {     if ( isObj ) {       for ( name in object ) {         if ( callback.apply( object[ name ], args ) === false ) {           break;         }       }     } else {       for ( ; i < length; ) {         if ( callback.apply( object[ i++ ], args ) === false ) {           break;         }       }     }    // A special, fast, case for the most common use of each   } else {     if ( isObj ) {       for ( name in object ) {         if ( callback.call( object[ name ], name, object[ name ] ) === false ) {           break;         }       }     } else {       for ( ; i < length; ) {         if ( callback.call( object[ i ], i, object[ i++ ] ) === false ) {           break;         }       }     }   }    return object; };

          惰性初始模式

          延遲初始化 是一種允許我們延遲初始化消耗資源比較大的進(jìn)程,直到需要他們的時(shí)候(才初始化)。這其中的一個(gè)例子就是jQuery的.ready()方法,它在DOM節(jié)點(diǎn)加載完畢之后會(huì)執(zhí)行一個(gè)回調(diào)方法。

          $( document ).ready( function () {      //ajax請求不會(huì)執(zhí)行,直到DOM加載完成      var jqxhr = $.ajax({       url: "http://domain.com/api/",       data: "display=latest&order=ascending"     })     .done( function( data ) ){         $(".status").html( "content loaded" );         console.log( "Data output:" + data );     });  });

          jQuery.fn.ready()底層是通過byjQuery.bindReady()來實(shí)現(xiàn)的, 如下所示:

          bindReady: function() {   if ( readyList ) {     return;   }    readyList = jQuery.Callbacks( "once memory" );    // Catch cases where $(document).ready() is called after the   // browser event has already occurred.   if ( document.readyState === "complete" ) {     // Handle it asynchronously to allow scripts the opportunity to delay ready     return setTimeout( jQuery.ready, 1 );   }    // Mozilla, Opera and webkit support this event   if ( document.addEventListener ) {     // Use the handy event callback     document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false );      // A fallback to window.onload, that will always work     window.addEventListener( "load", jQuery.ready, false );    // If IE event model is used   } else if ( document.attachEvent ) {     // ensure firing before onload,     // maybe late but safe also for iframes     document.attachEvent( "onreadystatechange", DOMContentLoaded );      // A fallback to window.onload, that will always work     window.attachEvent( "onload", jQuery.ready );      // If IE and not a frame     // continually check to see if the document is ready     var toplevel = false;      try {       toplevel = window.frameElement == null;     } catch(e) {}      if ( document.documentElement.doScroll && toplevel ) {       doScrollCheck();     }   } },

          即使不直接在jQuery核心文件中使用,有些開發(fā)者通過一些插件也可能熟悉懶加載的概念,延遲加載和攬初始化一樣有效,它是一種在需要的時(shí)候(比如:當(dāng)用戶瀏覽到了頁面底部的時(shí)候)才加載頁面數(shù)據(jù)的技術(shù)。最近幾年,這種模式已經(jīng)變得非常顯著并且現(xiàn)在可以再Twitter和Facebook的UI里面zhaoda。

          代理模式

          在我們需要在一個(gè)對象后多次進(jìn)行訪問控制訪問和上下文,代理模式是非常有用處的。

          當(dāng)實(shí)例化一個(gè)對象開銷很大的時(shí)候,它可以幫助我們控制成本,提供更高級的方式去關(guān)聯(lián)和修改對象,就是在上下文中運(yùn)行一個(gè)特別的方法。

          在jQuery核心中,一個(gè)jQUery.proxy()方法在接受一個(gè)函數(shù)的輸入和返回一個(gè)一直具有特殊上下文的新的實(shí)體時(shí)存在。這確保了它在函數(shù)中的值時(shí)我們所期待的的值。

          一個(gè)使用該模式的例子,在點(diǎn)擊事件操作時(shí)我們利用了定時(shí)器。設(shè)想我用下面的操作優(yōu)先于任何添加的定時(shí)器:

          $( "button" ).on( "click", function () {   // 在這個(gè)函數(shù)中,'this'代表了被當(dāng)前被點(diǎn)擊的那個(gè)元素對象   $( this ).addClass( "active" ); });

          如果想要在addClass操作之前添加一個(gè)延遲,我們可以使用setTiemeout()做到。然而不幸的是這么操作時(shí)會(huì)有一個(gè)小問題:無論這個(gè)函數(shù)執(zhí)行了什么在setTimeout()中都會(huì)有個(gè)一個(gè)不同的值在那個(gè)函數(shù)中。而這個(gè)值將會(huì)關(guān)聯(lián)window對象替代我們所期望的被觸發(fā)的對象。

          $( "button" ).on( "click", function () {   setTimeout(function () {     // "this" 無法關(guān)聯(lián)到我們點(diǎn)擊的元素     // 而是關(guān)聯(lián)了window對象     $( this ).addClass( "active" );   }); });

          為解決這類問題,我們使用jQuery.proxy()方法來實(shí)現(xiàn)一種代理模式。通過調(diào)用它在這個(gè)函數(shù)中,使用這個(gè)函數(shù)和我們想要分配給它的this,我們將會(huì)得到一個(gè)包含了我們所期望的上下文中的值。如下所示:

          $( "button" ).on( "click", function () {      setTimeout( $.proxy( function () {         // "this" 現(xiàn)在關(guān)聯(lián)了我們想要的元素         $( this ).addClass( "active" );      }, this), 500);      // 最后的參數(shù)'this'代表了我們的dom元素并且傳遞給了$.proxy()方法 });

          jQuery代理方法的實(shí)現(xiàn)如下:

          // Bind a function to a context, optionally partially applying any  // arguments.  proxy: function( fn, context ) {    if ( typeof context === "string" ) {      var tmp = fn[ context ];      context = fn;      fn = tmp;    }     // Quick check to determine if target is callable, in the spec    // this throws a TypeError, but we will just return undefined.    if ( !jQuery.isFunction( fn ) ) {      return undefined;    }     // Simulated bind    var args = slice.call( arguments, 2 ),      proxy = function() {        return fn.apply( context, args.concat( slice.call( arguments ) ) );      };     // Set the guid of unique handler to the same of original handler, so it can be removed    proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;     return proxy;  }

          建造者模式

          處理DOM時(shí),我們常常想要去動(dòng)態(tài)的構(gòu)建新的元素–這是一個(gè)會(huì)讓我們希望構(gòu)建的元素最終所包含的標(biāo)簽,屬性和參數(shù)的復(fù)雜性有所增長的過程。

          定義復(fù)雜的元素時(shí)需要特別的小心,特別是如果我們想要在我們元素標(biāo)簽的字面意義上(這可能會(huì)亂成一團(tuán))擁有足夠的靈活性,或者取而代之去獲得

          贊(0)
          分享到: 更多 (0)
          網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)