jQuery - 核心介紹

jQuery 函式

jQuery(),也可以寫成$(),兩者相同,jQuery 的起手式,也是最重要的函式核心,專門用來創建 jQuery 物件的加工廠,回傳的是特化過後 jQuery 物件。它不是一般我們認知的 JavaScript 物件,它可能會是一或多個的 DOM 元素集合。

當此函式建立 jQuery 物件,表示將選取元件集合,它會儲存一個參考值指向 DOM 樹中對應的元件節點,但並不會複製這些節點,這些集合會被封裝成 1 個或多個 DOM 元素,稱為 jQuery 選取元件集合(jQuery selection),取得後就可以使用 jQuery 提供的方法和屬性來操作這些元素。jQuery 物件只能使用 jQuery 提供的方法來操作它,因為它並不是 DOM 元素,不能使用 JavaScript 的方法,這點很重要

回傳是一個 jQuery.fn.init(n) 物件

jQuery()
// 縮寫
$()

那麼,有甚麼方法取得實際的 DOM,使用 JavaScript 方法?有的,jQuery 物件是類陣列(array-like)物件,這些被選到的 DOM 元素將被儲存為 jQuery 類陣列的元素集合,jQuery 物件有著像陣列的特性(但並不是真正陣列),一樣有 length 屬性,以及 0 到 length - 1 的特性。這表示它也可用標準的中括號[]陣列記號來存取 jQuery 物件的內容,也就是 DOM 元素,因此可以這樣做:

// 有五個 .box 被選取
$('.box') // 回傳 jQuery 物件,jQuery.fn.init(5) [div.box, div.box, div.box, div.box, div.box, prevObject: jQuery.fn.init(1)]

// 使用陣列中括號來取得 DOM
$('.box')[0]

// 使用 jQuery 提供的 get() 方法取得 DOM
$('.box').get(0)

jQuery 函式各種使用方式

jQuery()函式提供 JavaScript 封裝功能,這個封裝工廠可以為我們快速簡化 JavaScript 在網站設計的功能:

1. 傳入 CSS 選擇器(DOM 選擇)

jQuery( selector [, context ] )

這是最常使用的方式,傳入符合 CSS 規範的 selector 作為選擇的目標,回傳 jQuery 物件來操作。

$('.box').length

第二參數很少使用,它必須存在於上下文關係中,例如下方 this,span 是 .box 子元素才有作用。

<div class="box">
<span>1</span>
</div>
<script>
// 第一種式很少用
$('.box').on('click', function () {
$('span', this).css('background', 'red')
})

// 也可以使用 find 選擇到子元素
$('.box').on('click', function () {
$(this).find('span').css('background', 'red')
})

// 或是直接使用事件函式第二參數選擇
$('.box').on('click', 'span', function () {
$(this).css('background', 'red')
})
</script>

傳回來的是 jQuery 物件,只能用 jQuery 提供的方法來操作,不能用 JavaScript 的方法來操作。

2. 選擇元素操作(DOM 選擇)

jQuery( element )

除了 CSS 選擇器,也可以直接抓取 DOM 元素標籤的名稱。

$('body').css({
backgroundColor: 'black'
})

3. 建立一個元素(DOM 創建)

jQuery( html [, optionObject ] )

可直接傳入 html 標籤建立一個 html 元素, optionObject 是一個可選的物件,可直接設定 html 的屬性,而從 jQuery1.8 開始,所有$.fn.方法都可以指定。

// 第一個引數必須為 HTML 元素
// 第二個引數為可選物件,可以設定該元素的屬性 name/value。
$('<input>', {
type: 'text',
val: 'Test',
click: function () {
$(this).toggleClass('test')
},
focusin: function () {
$(this).addClass('active')
},
focusout: function () {
$(this).removeClass('active')
}
}).appendTo('form')

4. 複製陣列、物件

jQuery 函式可以複製陣列、物件,注意資料類型,尤其是 JSON 物件,它是被指向同一個記憶體位置,也就是說改變了一個,另一個也會更改。

// 複製 json 物件須注意,操作的都是相同的物件
let obj1 = {
a: 1,
b: 2,
c: 3
}
let obj2 = $(obj1)
obj1.a = 100 // obj2[0].a 也會更改為 200

5. 傳入一個函式(DOM 加載完成)

傳入一個函式給它,函式會在文件已經載入,DOM 準備就緒可供操作時被呼叫。

$(document).ready(function () {
// ready do
})

$(function () {
// ready do,與上方相同
})

// 3.50 支援 ES6
$(() => {})

回傳空的 jQuery 物件

length 為 0

$(null) // jQuery.fn.init {}
$(undefined) //jQuery.fn.init {}
$('') //jQuery.fn.init {}
$([]) // jQuery.fn.init []

ready 和 load 的區別

  • $(document).ready()
    會在 HTML 結構載入後,並且 DOM 就緒後呼叫,但不包含圖片。觸發時間較早,使用了 JavaScript 的 DOMContentLoaded 事件。

  • window.onload
    會在 HTML 結構載入後,DOM 就緒後,頁面渲染結束(iframe、img 圖片加載完成)後呼叫,也就是整份網頁讀取完成,使用了 JavaScript 的 load 事件。

    由此可知,ready 發生於 load 之前。

document.readyState

另外還有一個是 readystatechange 事件,可以藉由 document.readyState 描述文件讀取狀態,分為以下:

  • loading:document 正在讀取中
  • interactive:文件已經完成讀取和解析,但是其他的子資源,如「圖片樣式層次表」,仍然在讀取。這個狀態表示 DOMContentLoaded 事件已經被觸發。
  • complete:文件及子資源都完成讀取。這個狀態表示 load 事件即將被觸發。

readystatechange 事件在 document 上觸發時可以判斷 readyState 數值的改變,例如以下:

// readystatechange 替代 DOMContentLoaded
document.onreadystatechange = function () {
if (document.readyState == 'interactive') {
initApplication()
}
}

// readystatechange 替代 load
document.onreadystatechange = function () {
if (document.readyState == 'complete') {
initApplication()
}
}

$() 與 querySelectorAll()

兩者皆取一個 CSS 選擇器作為它們的引數,並回傳一個「類陣列物件」。jQuery 的實作會在有支援的瀏覽器中使用 querySelectorAll(),如果使用 $() 來取代 querySelectorAll()有個好處,$() 回傳的類陣列物件是一個 jQuery 物件,它比 querySelectorAll() 所回傳的類陣列物件(一個 NodeList)有用多了,因為 jQuery 物件還可以使用 jQuery 的方法。

選擇方法 回傳物件 是否新物件
$() jQuery
querySelectorAll() NodeList()
getElementsByTagName HTMLCollection()
getElementsByClassName() HTMLCollection()
querySelector() 元素本身
getElementById() 元素本身
  • NodeList 與 HTMLCollection 這兩個物件是唯讀的類陣列物件(array-like objects),具有 length 屬性可被迴圈索引逐一讀取(但無法寫入)。
  • 使用 $() 選擇元素時,jQuery 都會幫你獨立一個記憶體位置,且每一個都是全新的 jQuery 物件,要特別注意,濫用會造成記憶體的浪費。
// jQuery
let a = document.querySelectorAll('.col')
let b = document.querySelectorAll('.col')
console.log('jQuery', a === b) // false

// JavaScript querySelectorAll
let c = $('.col')
let d = $('.col')
console.log('querySelectorAll', c === d) // false

// JavaScript querySelector
let e = document.querySelector('#wrap')
let f = document.querySelector('#wrap')
console.log('querySelector', e === f) // true

// JavaScript getElementsByTagName
let g = document.getElementsByTagName('div')
let h = document.getElementsByTagName('div')
console.log('getElementsByTagName', g === h) // true

// JavaScript getElementsByClassName
let i = document.getElementsByClassName('col')
let j = document.getElementsByClassName('col')
console.log('getElementsByClassName', i === j) // true

// JavaScript getElementById
let k = document.getElementById('wrap')
let l = document.getElementById('wrap')
console.log('getElementById', k === l) // true

鍊式串接(Chaining)

鍊式串接,又稱為方法鍊,是方法間以句點(.)連續串接,可針對單一選擇器執行多個處理。jQuery 大部分的方法其回傳值都是回傳處理後的 jQuery 物件,也就是 return 該物件,並且會記錄在一個叫 prevObject 的物件(指上一層),它是紀錄鍊式上一層的 jQuery 物件,可以在選擇到 jQuery 物件時可以看到它。其中,end() 方法就是指向 prevObject,可以一直 end() 到虛無沒東西 S.fn.init {} 。但也有回傳非 jQuery 物件的方法,如果在方法鍊中使用 next()、end()方法,可能會因此改變處理目標的選擇器,回到原本狀態。

  • 可以幫助遍歷遨遊 DOM 結構樹,爬樹方便。
  • 可以讓動畫更豐富。
  • 鍊式中一個方法無法正確執行時,後續的方法也不會被執行。
// != 這種選擇是 jQ 獨創的用法,CSS沒有,最好符合CSS規範做選擇
$('li[id!="one"]').hide().delay(500).fadeIn(1400).css({
'background-color': '#F00'
})