前端JQuery應用實戰筆記 2 - AJAX 應用 (上)

AJAX 簡介

AJAX(Asynchronous JavaScript and XML)
可與伺服器進行非同步更新,透過瀏覽器應用程式便能快速、即時更動介面及內容,不需要重新讀取整個網頁,讓程式更快回應使用者的操作。

主要目的在於提高網頁互動性、速度、可用性。
之前傅統網頁中按下送出按鈕後,都必須要等待伺服器回應後才能繼續操作網頁,使用AJAX方式送出網頁後仍可以操作畫面,具有更佳良好使用者體驗,不需要更新整個網頁,只更新需要部分即可。

AJAX 動態載入

以往網頁中如有相同頁首頁尾,以前多半都會使用複製貼上。中間如有異動,就必須很累人的全部網頁重新複製貼上一次。
現在可以透過AJAX動態載入,把頁首頁尾內容動態載入進來,就可以維護一份檔案即可,再也不需要複製貼上了,既省時又省力。


ex.1 頁首頁尾-各別獨立

外部載入頁首及頁尾網頁。
ex.1 練習

index.html

1
2
3
4
5
6
7
<div class="page">
<div class="header"></div> <!-- 用來載入 header.html -->
<div class="content">
<span>我是 content 內容</span>
</div>
<div class="footer"></div> <!-- 用來載入 footer.html -->
</div>

header.html

1
<span>我是AJAX載入的 header 內容</span>

footer.html

1
<span>我是AJAX載入的 footer 內容</span>

all.js

1
2
3
4
$(function () {
$(".header").load("header.html");
$(".footer").load("footer.html");
});

使用 load 方法可以動態載入HTML檔案,之後有修改也只要改一隻檔案就好,
不用想以前使用複製貼上這種非常費時費力方式來維護了。


ex.2 頁首頁尾-共用相同

外部載入一個共用網頁,把要載入的內容都放進去,可減少跟伺服器請求檔案數量,加快網頁存取效率。
ex.2 練習

index.html

1
2
3
4
5
6
7
<div class="page">
<div class="header"></div> <!-- 用來載入 common.html 裡頭的 header -->
<div class="content">
<span>我是 content 內容</span>
</div>
<div class="footer"></div> <!-- 用來載入 common.html 裡頭的 footer -->
</div>

common.html

1
2
3
4
5
6
7
8
9
10
11
<div class="header">
<div>
<span>我是AJAX載入共用檔案的 header 內容</span>
</div>
</div>

<div class="footer">
<div>
<span>我是AJAX載入共用檔案的 footer 內容</span>
</div>
</div>

all.js

1
2
3
4
$(function () {
$(".header").load("common.html .header>div");
$(".footer").load("common.html .footer>div");
});

使用 load 方法 ( 檔案路徑 + 空白 + 選取器 ) 來載入頁面。

可以減少跟伺服器請求檔案的數量,且使用瀏覽器快取,由於瀏覧器為了加快網頁存取效率,會將檔案進行快取動作。但也可能在伺服器上檔案更新後,重新整理瀏覧器還是舊的內容,這時就要清除瀏覽器快取。
在 Chrome 可用快速鍵 Ctrl + Shift + Delete 清除快取。


ex.3 選單-載入選單

使用外部載入選單,並判斷已點選哪個選單。
ex.3 練習

index.html

1
2
3
4
<div class="menu"></div>  <!-- 用來載入 menu.html -->
<div class="content">
<span>我是首頁</span>
</div>

menu.html

1
2
3
<a href="index.html">首頁</a>
<a href="page1.html">第一頁</a>
<a href="page2.html">第二頁</a>

page1.html/page2.html

1
2
3
4
5
6
7
8
9
10
<!-- page1 -->
<div class="menu"></div>
<div class="content">
<span>我是第一頁</span>
</div>
<!-- page2 -->
<div class="menu"></div>
<div class="content">
<span>我是第二頁</span>
</div>

all.js

1
2
3
4
5
6
7
8
9
$(function () {
$(".menu").load("menu.html", function () { // 動態載入menu.html
//替目前頁面選項加上選取後效果
var url = location.href; // 宣告url變數 = 目前瀏覽器網址
var href = url.substr(url.lastIndexOf("/") + 1); // 宣告href變數 = 擷取 url 字元
$("a[href='" + (href || "index.html") + "']").addClass("selected");
//a元素判斷擷取的字元是否有效,無效就選是首頁的a元素,再套上CSS效果
});
});
  • location.href 取得目前瀏覽器網址
  • substr 與 lastIndexOf 方法取得字串,參考筆記
  • 使用短路邏輯判斷

短路邏輯 (short-circuit evaluation)
|| 當左邊結果為 tuthy 時則回傳左邊,當左邊結果為 falsy 時則回傳右邊,
&& 當左邊結果為 falsy 時則回傳左邊,當左邊結果為 truthy 時則回傅右邊,
(可轉換成 true 的值稱 truthy,可轉換成 false 的值稱 falsy。)


ex.4 選單-載入內容

用一個類似目錄頁,再利用選單來點選時,載入各對應的頁面內容。
ex.4 練習

index.html

1
2
3
4
5
6
7
<div class="menu">
<a href="page0.html">首頁</a>
<a href="page1.html">第一頁</a>
<a href="page2.html">第二頁</a>
<a href="page3.html">第三頁</a>
</div>
<div class="content"></div> //用來載入各別檔案內容

page0.html/page1.html/page2.html/page3.html

1
2
3
4
5
6
7
8
9
10
11
12
<!-- page0 -->
<h1>我是首頁</h1>
<span>我是首頁的內容</span>
<!-- page1 -->
<h1>我是第一頁標題</h1>
<span>我是第一頁的內容</span>
<!-- page2 -->
<h1>我是第二頁</h1>
<span>我是第二頁的內容</span>
<!-- page3 -->
<h1>我是第三頁標題</h1>
<span>我是第三頁的內容</span>

all.js

1
2
3
4
5
6
7
$(function () {
$(".menu>a").click(function (e) {
$(".menu>a.selected").removeClass();
$(".content").load($(this).addClass("selected").attr("href"));
e.preventDefault();
}).first().click();
});
  • attr 方法取得選取器中的網址,參考筆記
  • this 表示目前選取器中被click的那個 DOM 物件。
  • $(this) 可以將 DOM 物件轉換成 jQuery 物件。
  • e.preventDefault 方法可以停止超連結預設動作(包含表單提交)。
  • e.stopPropagation 方法可以停止事件往上層傳遞(事件冒泡參考筆記)。
  • first 方法從選取器中篩選出第一個選取器。
  • click 方法若不帶入 function 則表示會立即觸發 click 事件。

ex.5 選單-具有獨立網址

ajax 每次取資料時頁面更新後瀏覽器並不產生歷史記錄,後退和前進按鈕失去應用的效用。點取任一選單的內容也不會被記錄,所以每次載入都會從首頁顯示,如果想要直接用連結網址,這時可以結合hash來產生獨立網址使用。
ex.5 練習

index.html / page0.html / page1.html / page2.html / page3.html 同 ex.4
all.js

1
2
3
4
5
6
7
8
$(function() {
$(".menu>a").click(function(e) {
$(".menu>a.selected").removeClass();
$(".content").load($(this).addClass("selected").attr("href"));
location.hash = $(this).attr("href");
e.preventDefault();
}).filter("[href='" + (location.hash.substr(1) || $(".menu>a").attr("href")) + "']").click();
});

※ 觀念 : this 在不同的位置所指向的東西也不同,在 jQuery 中 this 會指向引發事件那個 DOM 物件 :

1
2
3
4
$(".box").click(function(){
this //被按到的那一個 DOM ( 原生物件無法直接用 JQuery 操作 )
$(this) //將 DOM 轉換成 JQuery 物件
});
在一般 function 中 this 會指向 window :
1
2
3
4
function run() {
this //window
}
run();
在建構函式中 this 會指向新的獨立的物件 :
1
2
3
4
function RUN() {
this //new Object
}
new RUN();
總結 this :
  1. 在 jQuery 是指向 DOM 物件。
  2. 函式方面,看是在哪邊被執行,全域的話通常都指向 window,物件底下的話都指向當下的物件。
  3. 在建構函式中執行 new 的話都會是全新的物件。

ex.6 選單-可使用上下頁按鈕歷史紀錄

紀錄點過那些歷史頁面,可使用上下頁按鈕回去。
ex.6 練習

index.html / page0.html / page1.html / page2.html / page3.html 同 ex.4
all.js

1
2
3
4
5
6
7
8
9
10
11
12
13
$(function() {
$(".menu>a").click(function(e) {
$(".menu>a.selected").removeClass();
$(".content").load($(this).addClass("selected").attr("href"));
location.hash = $(this).attr("href");
e.preventDefault();
});
// 增加 on 事件
$(window).on("hashchange", function() {
// 這段程式碼從上面搬下來,主要是當 hashchange 被改變時,點擊頁面
$(".menu>a").filter("[href='" + (location.hash.substr(1) || $(".menu>a").attr("href")) + "']").click();
}).trigger("hashchange");
});
  • 如果不是 jQuery 內建事件,可以用 on 來綁定事件,參考jQuery常用事件資料
  • 使用 on 方法可以監聽 hashchange 事件,當 hash 有變動就會觸發事件。
  • trigger 方法可以強迫觸發任何事件 (一進到畫面就馬上執行)。
  • hashchange 只有在 window 才會有。

ex.7 圖片-載入動畫

紀錄點過那些歷史頁面,可使用上下頁按鈕回去。
ex.7 練習

index.html

1
2
3
4
5
6
7
8
9
10
11
12
<div class="box">
<img src="images/pic1.jpg">
<img src="images/pic2.jpg">
<img src="images/pic3.jpg">
<img src="images/pic4.jpg">
<img src="images/pic5.jpg">
<img src="images/pic6.jpg">
<img src="images/pic7.jpg">
<img src="images/pic8.jpg">
<img src="images/pic9.jpg">
</div>
<div class="loading"></div>

all.js

1
2
3
$(window).load(function () {
$(".loading").fadeOut();
});

要看載入效果,可以按F12開啟開發人員工具,調整較慢的網路連線速度試試。

$(document).ready 事件是當畫面 HTML 載入完畢後就觸發 ( 但不包含圖片下載完成 )。
$(window).load 事件是必須等待全部物件 ( 包含所有圖片 ) 下載完成後才會髑發。
$(document).ready 會比 $(window).load 更早觸發,所以可以視情況要用哪一個。
$(window).load 事件不需要放在 $(document).ready 事件裡面。


ex.8 圖片-載入進度條

加入進度條,分別計算有幾張圖片佔總數多少百分比,累計後在四捨五入整數帶入進度條。
ex.8 練習

index.html

1
2
3
4
5
6
7
<!-- 增加計算百分比進度條 -->
<div class="loading">
<div class="progress progress-striped active">
<div class="txt">Loading...</div>
<div class="bar"></div>
</div>
</div>

all.js

1
2
3
4
5
6
7
8
9
10
// 增加計算百分比進度條
$(function() {
var progress = 0;
$("img").load(function() {
progress += 100 / $("img").length; //先除以張數看占多少百分比,完成後再去累加
var percent = Math.round(progress) + "%"; //將小數點轉成整數
$(".txt").text(percent); //產生百分比數字
$(".bar").width(percent); //設定百分比寬度
});
});
  • $("img").load 方法當每一張圖片下載完成就會觸發事件 ( html 裡有幾張 img 就觸發幾次 )。
  • 每一張讀取完就去 += ( 累加 ) 每張圖片的百分比。
  • Math.round 方法可以將小數四捨五入成整數。