What is JQuery?
JQuery 是 Javascript 的 libarary,可以讓 js 變得更直覺,更好寫。簡單來說,他可以讓工程師很方便的控制網頁裡面的元件,做出特定的動作,如:點擊按鈕後跳出視窗。
要產生行為,主要有三個要素:
- selector
目標元件 (element) 的選擇器,如:$(‘.info-button’) 可以選擇 class 為 info-button 的 element,$(‘li a’) 則可以選擇清單裡面的連結,也可使用逗號隔開,一次選取多個項目:$(‘.info-button, .nav-button, tab-button’)。'$' 就是代表 JQuery 的識別記號,讓 JQuery 能解析指令。 - event
觸發動作的時機,如:點擊(click),捲動(scroll),滑鼠移過(hover)。
常用的 events 列表:
http://www.w3schools.com/jquery/jquery_events.asp
$('.btn').click(function() {
// do something
});
- function
執行的動作內容,如:跳出視窗,捲到頁面最上方,下拉選單等等。就和數學的 f(x) = x+1 一樣,function 有個小括弧可以承接變數,大括弧則包含了要做的事情:
function plusTwo(x) {
return x + 2;
}
var result = plusTwo(4); // result -> 6function setHeight($element, hei) {
$element.height(hei); // 呼叫 Jquery 提供的 height() function, 來設定高度
console.log('setHeight successs'); // 輸出成功訊息
}
setHeight($('.btn'), 20); // btn 會被設為高度 20px
- click event 裡面的 function 不用命名,因為不會有其他地方使用到他。
- 上面範例中,setHeight()的變數 $element, hei 可以自由命名,這裡 $element 命名故意加上錢字號 $ 是用來識別變數需要傳入 JQuery element $(‘…’),才能正確運作。
Code Demo
以下用五種 Code 寫法,實作”點擊按鈕後展開選單”的功能。雙左斜線//代表註解,在斜線後面的內容是不會被執行的,可以拿來寫筆記,或是暫時不執行該程式區塊。在底下 Demo 中,可以自行編輯 JS 區塊,取消不同 example() 的註解來切換要執行的 example code (不過結果其實相同)。大家可以比較看看同樣的功能,不同的寫法,可以造成如何的天壤之別:
example1
function example1() {
// 在點擊按鈕的時候,執行 function() :
$('.btn').click(function() {
// 切換選單狀態 (toggleClass), 若選單打開, 則關閉; 若選單關閉, 則打開
$('.dropdown-menu').toggleClass('is-open');
});
}
toggleClass 可以切換選單開/合的狀態。這個寫法,只有點擊按鈕時能開合選單。但一般使用者的習慣,是希望點擊頁面的其他地方,選單也能合起來。這時可加入條件,在進行點擊時判斷 event* 的目標為何:
example2
function example2() {
// 在點擊頁面 (body) 的時候,執行 function(),並且用變數 e 來存放 event 內容
$('body').click(function(e) {
// 如果點擊的對象是按鈕, 則切換選單狀態
if( $('.btn').is(e.target) ) {
$('.dropdown-menu').toggleClass('is-open');
} else {
// 如果點擊的對象不是按鈕, 則關閉選單
$('.dropdown-menu').removeClass('is-open');
}
});
}
- event:當按鈕被點擊,JQuery 會回傳點擊事件 (click event) 的資訊,包含被點擊的項目 event.target 、點擊的位置 event.offsetX、event.offsetY 等等。每種 JQuery event 會回傳不同的資訊,可以用來做很多的用途。
- 上面範例中,在 body 頁面點擊到任何元件時,用了變數 e 來接收點擊事件的資訊,其中 $(‘.btn’).is(e.target) 可以判斷點擊目標是否是按鈕,
常用的 JQuery css method:
http://www.w3schools.com/jquery/jquery_ref_html.asp
但這個範例在點擊空白頁面處、點擊選單時,選單都會收起來。我們希望點擊選單時,選單應該要保持打開,這樣該如何做呢?這是小考題,大家可以先想一想,答案在下方。
function example3() { ...? }
上面的 example3 大家是否有想出來呢?
這裡先給大家兩個複雜的範例 (這是真實案例,說出來都是淚……底下兩個範例還是簡化過的版本):
example3Complex
function example3Complex() {
$('body').click(function(e) { // 若點擊的地方不是 btn / dropdown-menu, 則關閉
if ( !$('.btn, .dropdown-menu').is(e.target) ){
$('.dropdown-menu').removeClass('is-open');
}
// 若點擊 btn / dropdown-menu, 分兩種情況
else {
// 如果選單打開, 而且點擊 btn, 則關閉
if( $('.dropdown-menu').hasClass('is-open')
&& $('.btn').is(e.target) ){
$('.dropdown-menu').removeClass('is-open');
} else {
// (點擊 dropdown-menu) 保持打開
$('.dropdown-menu').addClass('is-open');
}
} });
}
有沒有覺得眼花撩亂,好難懂阿阿阿!!!
經過編修之後
function example3ComplexEdit() {
$('body').click(function(e) { // 若選單不是打開, 而且點擊的地方在 btn, 則打開選單
if( !$('.dropdown-menu').hasClass('is-open')
&& $('.btn').is(e.target) ) {
$('.dropdown-menu').addClass('is-open');
}
// 若選單打開, 當點擊的地方不是選單時, 則關閉選單
else if ($('.dropdown-menu').hasClass('is-open')
&& !$('.dropdown-menu').is(e.target)){
$('.dropdown-menu').removeClass('is-open');
} });
};
唉,好了一點,但還是有點複雜QQ
當要做的行為越來越複雜,硬寫絕對不是好的作法。要怎麼聰明的寫 Code呢?
Thinking UI
規劃介面行為,從畫圖開始。可以把點擊畫面個區塊會發生的事件畫出來,再抽象化成一行行的 Code 指令,這樣比較容易想像、寫出簡單好讀的 Code。
Draw all states
List all states
- 點擊按鈕,會 toggleClass
- 點擊選單,無作用
- 點擊按鈕選單之外,選單會收起
可以寫成
- if (是按鈕) { 則 toggleClass }
- else if (是選單) { 沒有反應就只是選單 }
- else { 不是按鈕也不是選單,那就收起選單 }
Do Re Mi So ~~ 簡潔的程式碼就出爐了:
function example3() {
$('body').click(function (e) {
if( $('.btn').is(e.target) ) {
$('.dropdown-menu').toggleClass('is-open');
} else if( $('.dropdown-menu').is(e.target) ) {
// do nothing
} else {
$('.dropdown-menu').removeClass('is-open');
}
});
}
可以和前面的範例比較,雖然執行的事情差不多,都是控制選單要開還是關,但最主要的差別是觸發事件的條件要怎麼寫才好讀、好懂,且邏輯不容易出錯。魔鬼總是常在細節裡,有時候條件沒訂好,常常會漏掉一些 special case,導致頁面元件沒有如預期般的運行。
Simple JS Style Guide
“ 好的 Coding Style,讓工程師上天堂 ,下略 “
能夠寫出基本的 JQuery 行為後,再來就是要寫好的 JS Style,好的可以讓 Code 更容易閱讀,讓下一個工程師更好維護!這部分不是針對 JQuery 作介紹,而是針對寫 Code 、使用 function 時要注意的通用事項。
Variables
盡量使用區域變數,定義全域變數很容易被誤改。
// bad way
var counter = 0;
function plus1() {
counter = counter + 1;
}
function reset() {
counter = 0;
}
var count0 = counter, count2 = counter;
plus1();
reset(); // 一旦呼叫 reset(), 之前的 counter 就會不見了
count0 = counter; // reset 完, count0 == 0
plus1();
counter2 = counter; // 原本預期 plus1() 呼叫兩次要得到 counter2 == 2, 但中間被清空過所以 counter2 變成只剩 1// good way
function plus1(recentCount) {
return recentCount+ 1;
}
function reset() {
return 0;
}(function() { // 主程式區段
var count0, count2; // 只有在主程式中可以修改這兩個變數
count2 = plus1(count2);
count0 = reset();
count2 = plus1(count2);
});
Naming
- 小寫駝峰 helloWorld
一般 function / 變數命名都是小寫開頭,如:
var name / function initialize()
但如果單字有兩個以上,則第二個字首要大寫,就像駱駝的駝峰。
如:var firstName / function initializeBtn()
這裡需注意 function 命名,動詞擺前方,或是用觸發的時機命名
如:initializeBtn() / getData() / setStyle()
onWindowResize() / onMenuScroll() - 大寫底線 HELLO_WORLD
只有定義”常數” (不可更動的數字),才會用大寫底線。
如:MAX_WINDOW_WIDTH = 480; - dash分隔 hello-world
通常只用於 class selector:btn-primary
— 其他較少用的種類 —
- 大寫駝峰 HelloWorld
可用於特殊物件定義 (JS 物件導向寫法)
var UserInfo = function() {...} - 小寫底線 hello_word
可用於變數命名(較不常用),或是特殊標記:var last_name / var _name_
詳細的 JS Style Document :http://usejsdoc.org/
Function Structure
js 文件中,常看到很多直接把 code 塞在同一個 function ,這樣對 Coding 和維護專案的工程師,都是很不健康的一件事。
為了讓 Coding 整潔好讀,盡量把性質相同的程式碼擺在一起,需要找錯誤或修改內容時,就能快速找到需要修正的段落,而不會在茫茫程式海中一行行尋找。
// bad way
$(document).ready(function(){
$('.btn').click(...);
$('.nav').click(...);
$('body').scroll(...);
$(window).resize(function(
...
));
});// good way
function initializePage() {
$('.btn').click(...);
$('.nav').click(...);
$('body').scroll(function() {
onBodyScroll();
});
}
function onBodyScroll() {
// many things todo
}
function onWindowResize() {
// many things todo
}$(document).ready(function(){
initializePage();
$(window).resize(function(
onWindowResize();
));
});
這個例子中,把原本塞在 $(document).ready 裡面的內容都向外移動,只要有許多事情要做,就要獨立開一支 function 來執行,確保 function() 不會過於龐大。像是假設 body 捲動時要做很多事情,就不要全部塞入 initializePage(),而應該新開一支 onBodyScroll() 來控管,讓專案在便複雜之後, Coding 能保持好讀,不會太大包。
結語
JQuery 對新手入門是很棒的工具,相對好操作、好套用。雖然他也有許多缺點,像是結構鬆散,常常變成一堆散亂的元件,不好管理,但若想踏入工程師的世界,這應該是最入門款、最有親和力的。歡迎大家一起來寫 Code !
“ 只要有心,人人都可以是工程師 “
碎碎念:原本只是想寫個開合選單的範例,到底怎麼可以變成這麼長的一篇文章,一邊寫一邊覺得這個好像要提一下,那個好像必須講,結果越寫越多。菜鳥工程師第一篇的技術文章,從基礎開始,希望大家會覺得有幫助 :)
Q&A
- JS 有時候放在 head 前面,有時候放在 body 裡是為何?
<head> 是在頁面載入時一開始執行的區段,JS sources 可以放在裡面,但有時底下的 html 元件還沒載入時如果先執行 JS,就會來不及被 JS 初始化 (像是 JS 設定 btn 的點擊動作,萬一此時 btn 還沒出現,就會吃不到設定),導致元件動作出錯。
一般較好的作法,<head> 裡面放 css sources ,<body> 最後面放 JS sources ,則執行順序:CSS載入-> html 元件載入 -> 最後才是 JS。
有客製化的 css / js 也要放在外掛下方,代表再另外附加上去的功能。
<html> <head>
<-- css 外掛們 -->
<link href="bootstrap.min.css" rel="stylesheet">
<link href="vital-ui-kit.min.css" rel="stylesheet">
<-- css 客製化 -->
<link href="basic.css" rel="stylesheet">
</head> <body>
<-- 很多的頁面元件們 -->
<div class="btn"></div> <-- js 外掛們 -->
<script type="text/javascript" src="bootstrap.min.js"></script>
<script type="text/javascript" src="vital-ui-kit.min.js"></script>
<-- js 客製化 -->
<script type="text/javascript" src="main.js"></script>
</body></html>
- kendo ui 的 jQuery 好像是 1.9.1,目前好像有更新的,若未來要換新的,會影響到其他的 JS 套件嗎?
專案的外掛有相依性,為了維持套件彼此之間不會衝突,我們不能更換到最新的版本,以免 kendo 會 GG。但如果未來 kendo 更新了,可以使用更高版本的 JQuery ,才能將版本升上去。
以目前的專案情況來說,JQuery 的功能已經夠用,所以不用擔心沒有升級會導致專案跑不動的情況~