隨手扎
什麼是jQuery?前端框架盛行還需要JavaScript函式庫嗎?
- 本篇首發於ALPHACamp Blog(2020-03-25)
- 2020-04-05 更新
前端框架盛行還需要JavaScript函式庫嗎?
如果你想透過本篇文章,直截了當的知道該不該使用jQuery,可能要讓你失望了。
很難說到底應不應該使用jQuery,可能在某些情況下使用jQuery仍是最好的選擇。即使是現在的流行的三大前端框架,也是依照情況與需求使用。
了解jQuery到底是什麼、前端框架是什麼,會比要不要使用jQuery更有意義。本篇帶你看看我了解的jQuery前世今生
瀏覽器發展歷史上出現過幾次大混戰。儘管後來有了W3C(全球資訊網協會/World Wide Web Consortium)進行標準的制定,各個瀏覽器廠商仍開發各自瀏覽器的「特異功能」吸引使用者與開發者。這些特異功能促使了瀏覽器標準的進步,也照成了開發上的困難。
為解決網路應用中不同平台、技術和開發者帶來的不相容問題,保障網路資訊的順利和完整流通,全球資訊網協會制定了一系列標準並督促網路應用開發者和內容提供者遵循這些標準。1
2006年1月,jQuery
推出了第一個版本,隨後變成為了最受歡迎的JavaScript函式庫之一2。附帶一題,我們現在熟悉的HTML5標準是在2014年正式定稿推出3,即使是現在,每年瀏覽器的標準也是快速地在變動。在後文我會在說明為何開頭我想提到這兩件事情。
什麼是jQuery? 從常見功能來看
jQuery之所以受歡迎,是因為他提供了一系列簡單方便,而且兼容的操作,省去開發人員的部份煩惱。這裡舉幾個簡單的例子:
選取器
現代瀏覽器標準分成三個部份:
- HTML
- CSS
- ECMAScript / JavaScript
其中第三個就是常聽到的JS/Javascript。目前更正式的名稱是ECMAScript,也是今天主要jQuery主要的基礎。不同於瀏覽器腳本(Script)的標準,CSS2在以前就提供豐富易用的選擇器,讓設計人員撰寫樣式表(stylesheet)
h1{
color: blue;
}
ul li{
color: blue;
}
#my-id{
color: blue;
}
.my-class{
color: blue;
}
#my-id li{
color: blue;
}
但是起初瀏覽器腳本,僅有提供以下三個可以存取網頁內容節點的API:
document.getElementById()
document.getElementsByTagName()
document.getElementsByClassName()
要取得h1
標籤、#my-id
元素節點或是.my-class
類別節點們並不困難。不過ul li
和#my-id li
就麻煩了…會需要這樣做:
// #my-id li
document.getElementById("my-id").getElementsByTagName("li");
// ul li
var ul_collect = document.getElementsByTagName("ul");
var li_arr = [];
for(var i = 0; i < ul_collect.length; i++){
li_collect = ul_collect[i].getElementsByTagName("li");
for(var j = 0; j < li_collect.length; j++){
li_arr.push(li_collect[j]);
}
}
可以看出以前使用原生API…是多麻煩……但是透過jQuery可以這樣做:
// #my-id li
$("#my-id li");
// ul li
$("ul li");
Ajax
Ajax全名Asynchronous JavaScript and XML。從全名可以知道他與JavaScript和XML脫不了關係,是一種非同步通訊技術。這樣的技術讓使用瀏覽器瀏覽網頁時,可以局部的更新內容,而無須重新取得所有頁面訊息,做到更好的瀏覽體驗。
最開始需要XMLHttpRequest
去取得需要更新的內容,在透過js更新。從MDN可以看到一個已經算是簡單的例子:
<!-- an example from https://developer.mozilla.org/zh-TW/docs/Web/Guide/AJAX/Getting_Started -->
<button id="ajaxButton" type="button">Make a request</button>
<script>
(function() {
var httpRequest;
document.getElementById("ajaxButton").addEventListener('click', makeRequest);
function makeRequest() {
httpRequest = new XMLHttpRequest();
if (!httpRequest) {
alert('Giving up :( Cannot create an XMLHTTP instance');
return false;
}
httpRequest.onreadystatechange = alertContents;
httpRequest.open('GET', 'test.html');
httpRequest.send();
}
function alertContents() {
if (httpRequest.readyState === XMLHttpRequest.DONE) {
if (httpRequest.status === 200) {
alert(httpRequest.responseText);
} else {
alert('There was a problem with the request.');
}
}
}
})();
</script>
Great…有這樣技術很棒,但寫起來對開發人員真痛…一樣看看jQuery給的範例:
// an example from https://api.jquery.com/jQuery.ajax/
$.ajax({
url: "https://fiddle.jshell.net/favicon.png",
beforeSend: function( xhr ) {
xhr.overrideMimeType( "text/plain; charset=x-user-defined" );
}
})
.done(function( data ) {
if ( console && console.log ) {
console.log( "Sample of data:", data.slice( 0, 100 ) );
}
});
瀏覽器裡Ajax允許三種方法 - HEAD、GET和POST。明確使用可以在加以簡化,以GET為例:
// an example from https://api.jquery.com/jQuery.get/
$.get( "ajax/test.html", function( data ) {
$( ".result" ).html( data );
alert( "Load was performed." );
});
事件綁定
接著說說事件綁定。
正常要綁定事件有三種方式:
- inline event:
<h1 onclick="console.log('click')" id="my-id">Hello</h1>
addEventListener
var elm = document.getElementById("my-id");
elm.addEventListener("click", ()=>{
console.log("click event by addEventListener");
});
- JS設定 inline event
要注意這種方式會覆寫掉直接寫在HTML裡的inline event。
var elm = document.getElementById("my-id");
elm.onclick= ()=>{ // override onclick
console.log("click event bind onclick");
};
要設定click事件處理,可以透過jQuery
這樣寫:
$("#my-id").click(()=>{
console.log("click event by jQuery");
});
事件觸發
另外要觸發一些已定義事件,使用jQuery
也很簡單。先來看看不使用應該怎麼做:
var elm = document.getElementById("my-id"); //document.querySelector("#my-id")
click_event = new CustomEvent('click');
elm.dispatchEvent(click_event);
jQuery
只需要一行:
$("#my-id").click()
屬性操作
jQuery還提供一些常使用的屬性操作的簡化方法。這裡舉className和data-開頭的屬性來舉例:
className屬性操作
變更元素類別(添加或刪除),在Bootstrap算是常見的使用方式。一樣先來看看不使用jQuery
要怎麼做:
//document.querySelector("#my-id").classList.add("red")
var elm = document.getElementById("my-id");
var class_list = elm.className;
class_list = class_list.split();
class_list.push("red");
elm.className = class_list.join(" ");
jQuery
一樣只需要一行:
$("#my-id").addClass("red")
尤其對於複數元素的時候使用,更看的出其方便性。
不巧的是getElementsByTagName
等的回傳值,HTMLCollection
並沒有forEach
操作。要處理稍微有些麻煩:
// document.querySelectorAll("li").forEach(e => e.classList.add("red"));
var elms = document.getElementsByTagName('li');
for(var i = 0; i < elms.length; i++){
var class_list = elms[i].className;
class_list = class_list.split();
class_list.push("red");
elms[i].className = class_list.join(" ");
}
但是jQuery
處理好了:
$("li").addClass("red")
取得data-屬性
data-
開頭的自訂屬性算是標準的一部分,在有些情況經常使用。
<div id="my-id2" data-target="#target"></div>
直接比較看看使用jQuery
和不使用的樣子。
不使用jQuery
console.log(document.getElementById("my-id2").getAttribute("data-target")); // => "#target"
使用jQuery
console.log($("#my-id2").data("target")); // => "#target"
我想,你應該也會比較喜歡使用jQuery
的方式吧?
文件載入事件處理綁定
最後,提一個雖然不太常見的需求,但是有必要知道的事情。
網頁瀏覽器處裡網頁的流程會經過:取得原始碼、解析、掛載軟染頁面過執行JS。這過程中也可能在去載入其他資源,如link
的CSS檔案、圖檔、音樂等。要注意的是,JS的執行可能在DOM建立好之前,這時期會無法透過getElementXXX
等操作取得DOM上的元素節點,因此可能會需要註冊事件在載入文件之後,才執行JS:
function event_handler(){
console.log('ready');
}
window.addEventListener("load", event_handler);
同樣的,比起上面不使用jQuery
的方式,下面的看起來更簡潔。
function event_handler(){
console.log('ready');
}
$(document).ready(event_handler);
小節
簡而言之,jQuery
是一個簡化瀏覽器API的JS函式庫 ,提供了一系列簡單方便的操作,看完上面例子相信你也會認同。不過jQuery畢竟是一個從2006年就開始的專案,這期間網頁技術變化可不小,除了HTML5的正式推出,JavaScript也經歷重大改版ECMAScript 2015(ES6),此外瀏覽器也在更新,更有新的網頁設計思想提出。所以接著來看看jQuery的挑戰者。
jQuery與三大前端框架
實際上拿前端框架與jQuery
比較並沒有什麼意義,因為兩個設計出發點不同。來看看React官網的說明:
React and Web Components are built to solve different problems. Web Components provide strong encapsulation for reusable components, while React provides a declarative library that keeps the DOM in sync with your data. The two goals are complementary. As a developer, you are free to use React in your Web Components, or to use Web Components in React, or both.
React 和 Web Component 是為了解決不同的問題所建立的。Web Component 為了可重複使用的 component 提供了強大的封裝,而 React 提供了一個宣告式函式庫,使 DOM 與你的資料保持同步。這兩個目標是相輔相成的。作為開發人員,你可以自由地在 Web Component 中使用 React,或在 React 中使用 Web Component,或兩者都是。 4
對,雖然我找的是在說Web Component,但可以看到「 React 提供了一個宣告式函式庫,使 DOM 與你的資料保持同步。 」。React以一種維持狀態(state
)的方式,保持資料的同步。實際上前端三大框架Angular、React和Vue的設計理念在這塊都有些像。
這種設計方式,讓原本直接操作元素的JS方式退居幕後。在框架把控的範圍,依照框架設計,由框架自動處理。以Vue
來說,不在直接決定是否真加類別(className
),而透過綁定變數進行單向或雙向溝通。
<style>
.red{
color:red;
}
</style>
<div id="app">
<h1 v-bind:class="{red:isRed}">Hello, World</h1>
</div>
<script>
var app = new Vue({
el: "#app",
data:{
isRed: true,
}
})
</script>
透過app.isRed=false
,修改isRed
變數,會自動將className
中的red
移除,而無須操作DOM。(實際上更像是部份重新渲染)
既然jQuery
和前端框架在根本的設計上有所不同,兩者要相比有些困難。不過jQuery
還有一個我認為的真正挑戰者 - 新的瀏覽器原生API。
jQuery與瀏覽器原生API - jQuery的真正挑戰者
相比起前端框架,我認為jQuery
真的的挑戰者,是日新月異的瀏覽器API標準。從這些新的API也可以看出jQuery
的影響力,未來可能會有更多瀏覽器API可以使用,那麼上面提到的痛點可能就會消失。舉幾個已經有的例子:
querySelector && querySelectorAll
querySelector
和querySelectorAll
同樣可以透過CSS選擇器方式取得元素:
document.querySelector("#my-id");
// 幾乎等價
$("#my-id");
////////////////////////
document.querySelectorAll("#my-id li");
// 幾乎等價
$("#my-id li");
值得一題的是document.querySelectorAll
取回的元素是一個Array
,他可以使用Array.prototype.forEach
去遍歷元素,上面要添加class
的例子,在配合等等會說到的classList
變得更為簡單。
className && classList
原本操作className
有夠麻煩
//document.querySelector("#my-id").classList.add("red")
var elm = document.getElementById("my-id");
var class_list = elm.className;
class_list = class_list.split();
class_list.push("red");
elm.className = class_list.join(" ");
但後來有了classList
。
document.querySelector("#my-id").classList.add("red")
此外,classList
還有以下這些方法:
add()
remove()
toggle()
replace()
contains()
Ajax && fetch
上面看過jQuery.ajax
的例子:
$.ajax({
url: "https://fiddle.jshell.net/favicon.png",
beforeSend: function( xhr ) {
xhr.overrideMimeType( "text/plain; charset=x-user-defined" );
}
})
.done(function( data ) {
if ( console && console.log ) {
console.log( "Sample of data:", data.slice( 0, 100 ) );
}
});
這下使用fetch
似乎也差不多了。
// an example from https://developer.mozilla.org/zh-TW/docs/Web/API/Fetch_API/Using_Fetch
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
data && dataset
2020-04-25 更新
<div id="my-id2"
data-name="Bob"
data-age="25">
</div>
使用jQuery
可以這樣取得擁有data-
前綴的屬性:
console.log($("#my-id2").data("name")); // => "Bob"
console.log($("#my-id2").data("age")); // => "25"
現在可以使用 dataset API:
console.log(document.querySelector("#my-id2").dataset.name); // => "Bob"
console.log(document.querySelector("#my-id2").dataset.age); // => "25"
jQuery的地位與影響
就像瀏覽器大戰促進了瀏覽器的發展,jQuery
的熱門程度,也很大程度影響新的瀏覽器API,他在瀏覽器發展歷史上已經留下一個不可忽略的軌跡。時至今日,隨著使用人數的增多與技術的發展,原生標準的瀏覽器API追趕著jQuery
。如果你已經擁抱了新的技術,jQuery
這份滿漢全席似乎就變得多餘,你可以去尋找其他小的函式庫,吃自助餐。但如果你需要兼容舊的瀏覽器,那jQuery
仍然有可能是你的選擇之一。
回到標題 我們還需要JavaScript函式庫 嗎?
我的回答會是:是的,只是jQuery
的價值不在那麼高。
前端三大框架亦是 JavaScript函式庫 ,使用了與過往截然不同的設計方式。但儘管如此,框架仍有不足之處,適時地引入plugin或是與框架無關的函式庫無疑會對開發上有所幫助。
jQuery的未來
世紀大分手 - Bootstrap 5 不再使用jQuery
另一個流行的套件 – Bootstrap
,是一個能夠快速建立頁面布局的系統。他與jQuery
一樣影響著瀏覽器的發展(影響了一些CSS3)。在Bootstrap 4
以前,都必須先引入jQuery
才可以使用。但近日Bootstrap 5
將表示會移除這個依賴。
jQuery 4.0
那麼jQuery
會就此漠弱嗎?在我撰寫本文當下,jQuery
的軟體倉庫仍在1個月前有所更新,並有新版本jQuery 4
的進度。jQuery 4.0
仍在開發。
技術隨需求發展。新的階段會有新的需求,jQuery 3
已經證明了他的價值,jQuery 4
會不會再改變一次瀏覽器世界?就算不是jQuery
,現在或許也有個小專案正在萌芽,會像jQuery
一樣影響著未來瀏覽器的發展。
