如果說 jQuery 有一點壞的話,那就是它的入門水平低得驚人,以至於它往往會吸引那些對 JavaScript 沒有一點了解的人。現在,一方面,這太棒了。然而,另一方面,它也會導致一些,坦白說,令人厭惡的糟糕程式碼(其中一些是我自己寫的!)。
不過沒關係;糟糕得可怕的代碼甚至會讓你的祖母喘不過氣來,這是一種成年儀式。關鍵是要翻過山,這就是我們今天教學要討論的內容。
請務必記住,大多數方法都會傳回 jQuery 物件。這非常有用,並且允許我們經常使用的連結功能。
$someDiv .attr('class', 'someClass') .hide() .html('new stuff');
知道 jQuery 物件總是被傳回,我們有時可以使用它來刪除多餘的程式碼。例如,考慮以下程式碼:
var someDiv = $('#someDiv'); someDiv.hide();
我們之所以「快取」
someDiv
元素的位置,是為了將我們必須遍歷該元素的 DOM 的次數限制為一次。
上面的程式碼完全沒問題;但是,您可以輕鬆地將兩條線合併為一條線,同時獲得相同的結果。
var someDiv = $('#someDiv').hide();
這樣,我們仍然隱藏 someDiv
元素,但如我們所知,該方法也傳回 jQuery 物件——然後透過 someDiv
變數來引用該物件。
只要你的選擇器不是糟糕到離譜,jQuery 就會盡可能地優化它們,而且你通常不需要太擔心它們。不過,話雖如此,您可以進行一些改進,從而稍微提高腳本的效能。
一種這樣的解決方案是在可能的情況下使用 find()
方法。如果沒有必要的話,關鍵是不要強迫 jQuery 使用它的 Sizzle 引擎。當然,有時這是不可能的——但這沒關係;但是,如果您不需要額外的開銷,就不要尋找它。
// Fine in modern browsers, though Sizzle does begin "running" $('#someDiv p.someClass').hide(); // Better for all browsers, and Sizzle never inits. $('#someDiv').find('p.someClass').hide();
最新的現代瀏覽器支援
QuerySelectorAll
,它允許您傳遞類似 CSS 的選擇器,而不需要 jQuery。 jQuery 本身也會檢查此函數。
但是,較舊的瀏覽器(即 IE6/IE7)不提供支持,這是可以理解的。這意味著這些更複雜的選擇器會觸發 jQuery 的完整 Sizzle 引擎,雖然很出色,但確實會帶來更多的開銷。
Sizzle 是一大堆我可能永遠無法理解的精彩程式碼。然而,在一句話中,它首先將您的選擇器變成一個由選擇器的每個組件組成的「陣列」。
// Rough idea of how it works ['#someDiv, 'p'];
然後,從右到左,開始使用正規表示式破解每個項目。這也意味著選擇器的最右側部分應盡可能具體 - 例如,id
或標記名稱。
底線,如果可能的話:
find()
方法。這樣,我們就可以繼續使用瀏覽器的原生功能,而不是使用 Sizzle。 也可以為選擇器新增上下文,例如:
$('.someElements', '#someContainer').hide();
此程式碼指示 jQuery 在 jQuery 中使用 someElements
類別(它們是 someContainer
的子級)包裝所有元素的集合。使用上下文是限制 DOM 遍歷的一種有用方法,但在幕後,jQuery 使用 find
方法來取代。
$('#someContainer') .find('.someElements') .hide();
// HANDLE: $(expr, context) // (which is just equivalent to: $(context).find(expr) } else { return jQuery( context ).find( selector ); }
$(this)
在不了解各種 DOM 屬性和功能的情況下,很容易不必要地濫用 jQuery 物件。例如:
$('#someAnchor').click(function() { // Bleh alert( $(this).attr('id') ); });
如果我們對 jQuery 物件的唯一需求是存取錨標記的 id
屬性,那麼這是浪費的。最好堅持使用“原始”JavaScript。
$('#someAnchor').click(function() { alert( this.id ); });
請注意,應該始終透過 jQuery 存取三個屬性:「src」、「href」和「style」。這些屬性需要在舊版的 IE 中使用
getAttribute
。
// jQuery Source var rspecialurl = /href|src|style/; // ... var special = rspecialurl.test( name ); // ... var attr = !jQuery.support.hrefNormalized && notxml && special ? // Some attributes require a special call on IE elem.getAttribute( name, 2 ) : elem.getAttribute( name );
更糟的是重複查詢 DOM 和建立多個 jQuery 物件的過程。
$('#elem').hide(); $('#elem').html('bla'); $('#elem').otherStuff();
希望您已經意識到這段程式碼的效率有多低。如果沒有,也沒關係;我們都在學習。答案是要么實現鏈接,要么“緩存” #elem
的位置。
// This works better $('#elem') .hide() .html('bla') .otherStuff(); // Or this, if you prefer for some reason. var elem = $('#elem'); elem.hide(); elem.html('bla'); elem.otherStuff();
Ready
方法使用 jQuery 監聽文件何時準備好進行操作是非常簡單的。
$(document).ready(function() { // let's get up in heeya });
不過,您很可能遇到過不同的、更令人困惑的包裝函數。
$(function() { // let's get up in heeya });
尽管后者的可读性稍差,但上面的两个片段是相同的。不相信我?只需检查 jQuery 源代码即可。
// HANDLE: $(function) // Shortcut for document ready if ( jQuery.isFunction( selector ) ) { return rootjQuery.ready( selector ); }
rootjQuery
只是对根 jQuery(document)
的引用。当您将选择器传递给 jQuery 函数时,它将确定您传递的选择器类型:字符串、标记、id、函数等。如果传递了函数,jQuery 将调用其 ready()
方法,并将您的匿名函数作为选择器传递。
如果开发用于分发的代码,补偿任何可能的名称冲突始终很重要。如果在您的脚本之后导入的某些脚本也具有 $
函数,会发生什么情况?坏东西!
答案是要么调用 jQuery 的 noConflict()
,要么将代码存储在自调用匿名函数中,然后将 jQuery 传递给它。
var j = jQuery.noConflict(); // Now, instead of $, we use j. j('#someDiv').hide(); // The line below will reference some other library's $ function. $('someDiv').style.display = 'none';
请小心使用此方法,并在分发代码时尽量不要使用它。这真的会让脚本的用户感到困惑! :)
(function($) { // Within this function, $ will always refer to jQuery })(jQuery);
底部的最后一个括号自动调用该函数 - function(){}()
。然而,当我们调用该函数时,我们还传递了 jQuery,然后用 $
表示。
Ready
方法传递$ jQuery(document).ready(function($) { // $ refers to jQuery }); // $ is either undefined, or refers to some other library's function.
请记住 - jQuery 只是 JavaScript。不要假设它有能力弥补你的错误编码。 :)
这意味着,正如我们必须优化 JavaScript for
语句等内容一样,jQuery 的 each
方法也是如此。我们为什么不呢?它只是一个辅助方法,然后在幕后创建 for
语句。
// jQuery's each method source 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 ( var value = object[0]; i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} } } return object; }
someDivs.each(function() { $('#anotherDiv')[0].innerHTML += $(this).text(); });
anotherDiv
var someDivs = $('#container').find('.someDivs'), contents = []; someDivs.each(function() { contents.push( this.innerHTML ); }); $('#anotherDiv').html( contents.join('') );
这样,在 each
(for) 方法中,我们执行的唯一任务就是向数组添加一个新键...而不是查询 DOM,两次获取元素的 innerHTML
属性,等等
这篇技巧总体上更多地基于 JavaScript,而不是特定于 jQuery。 重点是要记住 jQuery 并不能弥补糟糕的编码。
当我们这样做时,针对此类情况的另一种选择是使用文档片段。
var someUls = $('#container').find('.someUls'), frag = document.createDocumentFragment(), li; someUls.each(function() { li = document.createElement('li'); li.appendChild( document.createTextNode(this.innerHTML) ); frag.appendChild(li); }); $('#anotherUl')[0].appendChild( frag );
这里的关键是,有多种方法可以完成这样的简单任务,并且每种方法在浏览器之间都有自己的性能优势。您越坚持使用 jQuery 并学习 JavaScript,您可能还会发现您更频繁地引用 JavaScript 的本机属性和方法。如果是这样,那就太棒了!
jQuery 提供了令人惊叹的抽象级别,您应该利用它,但这并不意味着您被迫使用它的方法。例如,在上面的片段示例中,我们使用 jQuery 的 each
方法。如果您更喜欢使用 for
或 while
语句,那也没关系!
尽管如此,请记住 jQuery 团队已经对该库进行了大量优化。关于 jQuery 的
each()
与本机for
语句的争论是愚蠢而琐碎的。如果您在项目中使用 jQuery,请使用它们的帮助器方法来节省时间。这就是他们存在的目的! :)
如果您现在才开始深入研究 jQuery,它为我们提供的各种 AJAX 方法可能会让人感到有点畏惧;尽管他们不需要。事实上,它们中的大多数只是简单的辅助方法,直接路由到 $.ajax
。
作为示例,让我们回顾一下 getJSON
,它允许我们获取 JSON。
$.getJSON('path/to/json', function(results) { // callback // results contains the returned data object });
在幕后,该方法首先调用 $.get
。
getJSON: function( url, data, callback ) { return jQuery.get(url, data, callback, "json"); }
$.get
然后编译传递的数据,并再次调用“master”(某种意义上的)$.ajax
方法。
get: function( url, data, callback, type ) { // shift arguments if data argument was omited if ( jQuery.isFunction( data ) ) { type = type || callback; callback = data; data = null; } return jQuery.ajax({ type: "GET", url: url, data: data, success: callback, dataType: type }); }
最后,$.ajax
执行了大量工作,使我们能够在所有浏览器上成功发出异步请求!
这意味着您也可以直接使用
$.ajax
方法来处理您的所有 AJAX 请求。其他方法只是辅助方法,无论如何最终都会执行此操作。所以,如果你愿意的话,就可以去掉中间人。无论如何,这都不是一个重要的问题。
$.getJSON('path/to/json', function(results) { // callback // results contains the returned data object });
$.ajax({ type: 'GET', url : 'path/to/json', data : yourData, dataType : 'json', success : function( results ) { console.log('success'); }) });
现在您已经学习了一些 JavaScript,并且已经了解,例如,在锚标记上,您可以直接访问属性值:
var anchor = document.getElementById('someAnchor'); //anchor.id // anchor.href // anchor.title // .etc
唯一的问题是,当您使用 jQuery 引用 DOM 元素时,这似乎不起作用,对吗?当然不是。
// Fails var id = $('#someAnchor').id;
因此,如果您需要访问 href
属性(或任何其他本机属性或方法),您有多种选择。
// OPTION 1 - Use jQuery var id = $('#someAnchor').attr('id'); // OPTION 2 - Access the DOM element var id = $('#someAnchor')[0].id; // OPTION 3 - Use jQuery's get method var id = $('#someAnchor').get(0).id; // OPTION 3b - Don't pass an index to get anchorsArray = $('.someAnchors').get(); var thirdId = anchorsArray[2].id;
get
方法特别有用,因为它可以将 jQuery 集合转换为数组。
当然,对于我们的绝大多数项目,我们不能仅仅依赖 JavaScript 来完成诸如验证或 AJAX 请求之类的事情。当 JavaScript 关闭时会发生什么?正是出于这个原因,一种常见的技术是检测 AJAX 请求是否是使用您选择的服务器端语言发出的。
jQuery 通过在 $.ajax
方法中设置标头,使这变得异常简单。
// Set header so the called script knows that it's an XMLHttpRequest // Only send the header if it's not a remote XHR if ( !remote ) { xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest"); }
设置此标头后,我们现在可以使用 PHP(或任何其他语言)检查此标头,并进行相应操作。为此,我们检查 $_SERVER['HTTP_X_REQUESTED_WITH']
的值。
function isXhr() { return $_SERVER['HTTP_X_REQUESTED_WITH'] === 'XMLHttpRequest'; }
有没有想过为什么/如何可以互换使用 jQuery
和 $
?要找到答案,请查看 jQuery 源代码,然后滚动到最底部。在那里,您会看到:
window.jQuery = window.$ = jQuery;
当然,整个 jQuery 脚本都包含在一个自执行函数中,这允许脚本尽可能地限制全局变量的数量。但这也意味着 jQuery 对象在包装匿名函数之外不可用。
为了解决这个问题,jQuery 被暴露给全局 window
对象,并且在此过程中,还会创建一个别名 - $
-。
HTML5 Boilerplate 提供了一个漂亮的单行代码,如果由于某种奇怪的原因您选择的 CDN 出现故障,它将加载 jQuery 的本地副本。
<!-- Grab Google CDN jQuery. fall back to local if necessary --> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script> <script>!window.jQuery && document.write('<script src="js/jquery-1.4.2.min.js"><\/script>')</script>
“表述”上面的代码:如果 window.jQuery 未定义,则从 CDN 下载脚本时一定出现问题。在这种情况下,请继续到 &&
运算符的右侧,并插入链接到本地版本 jQuery 的脚本。
高级会员:下载此视频(必须登录)
订阅我们的 YouTube 页面以观看所有视频教程!
<script> $('p:first').data('info', 'value'); // populates $'s data object to have something to work with $.extend( jQuery.expr[":"], { block: function(elem) { return $(elem).css("display") === "block"; }, hasData : function(elem) { return !$.isEmptyObject( $(elem).data() ); } } ); $("p:hasData").text("has data"); // grabs paras that have data attached $("p:block").text("are block level"); // grabs only paragraphs that have a display of "block" </script>
注意:
jQuery.expr[':']
只是jQuery.expr.filters
的别名。
从 jQuery 1.4 开始,我们现在只能将单个函数传递给 hover
方法。以前,in 和 out 方法都是必需的。
$('#someElement').hover(function() { // mouseover }, function() { // mouseout });
$('#someElement').hover(function() { // the toggle() method can be used here, if applicable });
请注意,这不是旧协议与新协议的比较。很多时候,您仍然需要将两个函数传递给 hover
,这是完全可以接受的。但是,如果您只需要切换某些元素(或类似的元素),则传递单个匿名函数将节省一些字符左右!
从 jQuery 1.4 开始,我们现在可以传递一个对象作为 jQuery 函数的第二个参数。当我们需要向 DOM 中插入新元素时,这非常有用。例如:
$('<a />') .attr({ id : 'someId', className : 'someClass', href : 'somePath.html' });
$('</a>', { id : 'someId', className : 'someClass', href : 'somePath.html' });
这不仅可以节省一些字符,而且还可以使代码更加简洁。除了元素属性之外,我们甚至可以传递 jQuery 特定的属性和事件,例如 click
或 text
。
以上是提升您技能的 14 個 jQuery 技巧、提醒和最佳實踐的詳細內容。更多資訊請關注PHP中文網其他相關文章!