Why No Refresh
Web 2.0 的一個主要概念,就是將瀏覽器視為一個應用程式(也就是 Web Application),讓 User 感覺不到網頁究竟跟一般的視窗應用程式有什麼差異。要達到這樣的目標,就需要用到大量的 DHTML 技巧,如拖曳、動畫效果等,以及本次要介紹的不換頁技術。
傳統的網頁中,不管做任何事,都必須重新整理網頁一次,譬如新增一筆資料、換頁、查詢、修改
。這樣的做法會有以下的缺點:- 浪費頻寬:整個網頁必須要重新載入,如頁首、頁尾等不必要的資訊也必須由 Server 端傳輸。使想如果整個網頁如果傳輸前跟傳輸後僅有三個字的不同、就浪費了 99% 的頻寬。
- 伺服器負荷高:由於整頁重新載入,伺服器端所消耗、運算的資源較多。
- 使用者焦點遺失:例如刪除一筆資料、送出後就沒有辦法鎖定在目前的位置。
- 使用者等待時間長:在頁面未出來前無法做任何事,空白一片。
以視窗應用程式的觀點來看,做任何事都必須重新整理勢必是一件很不合理的事吧。所以當整個潮流都移向「網路應用程式」的當下,不重新整理的技術,變得越來越重要,也是一個不可不會的基本功夫。今天要介紹的主要有下列幾種:
- Window Pop Up
- window.open()
- window.showModalDialog()
- Frame
- Frameset
- Iframe
- Cookies
- Image Replacement
- 204 Piggyback
- External Javascript
- XMLHttp
Window Pop Up:利用跳出視窗更新網頁
在跳出視窗尚不會被攔截的時代,常有許多網站會利用這樣的方式來做不換頁的更新。而現在主流的瀏覽器 IE 、Firefox 預設已經會攔截跳出視窗,用這種方式來更新已經少之又少了。
window.open()
我們可以利用跳出的視窗去取得伺服器端的資料,再把取得的資料寫回原本的視窗。這是一種蠻直覺的做法,剛剛提到「封鎖快顯視窗」的緣故,若這個跳出視窗的動作不是由使用者所驅動,那麼十之八九會被擋掉,功能就會因此而失效了。
輸入帳號取得使用者的 Email (ASP Code) | 自動取得伺服器上的時間(被視窗封鎖的失敗範例)window.showModalDialog()
由於視窗內建的 window.alert(), window.prompt(), winfow.confirm() 外觀都是一成不變的,基於這個問題,微軟就發展出了 window.showModalDialog。showModalDialog 的中文名稱就是「對話視窗」,跟 alert(), prompt(), confirm(), 一樣,使用者必須關閉此視窗、或按下某個 button 才可以繼續下一步,也可以稱為「同步化作業」(必須等待處理完畢、不能在等待的時間作其他事情)。這是一個蠻好使用的方式,但很可惜的是 FireFox 完全不支援、而且在 IE 如果不是使用者所驅動、也一樣會有封鎖視窗的問題在。
什麼是 showModalDialog | 查詢使用者的 Email (ASP Code)Frame:利用框架更新網頁
這也是一種傳統的做法,但是到目前都還是歷久不衰。
Frameset
我們可以用 Frame Set 的方式將網頁一切為二,一個 Viewable Frame 是使用者所檢視的網頁、一個是看不到(寬度設為 0)的 Hidden Frame。假設網友在其所檢視的網頁按下了一個連結,這個連結的目標(target)其實是指向到 Hidden Frame 的,在 Hidden Frame 讀取此網頁完畢之後,就可以把資料輸出到 Viewable Frame 中的一個 div 供使用者觀看。
<!-- 設第二個 Frame 顯示高度為零 -->
<frameset cols="100%,*">
<frame src="view.html" name="view"></frame>
<frame src="hidden.html" name="hidden"></frame>
</frameset>
教學:載入文件到目前的網頁中 |
完成
其實可以把這種隱藏的 Frame 想成是一種 Buffer 的觀念,等 Buffer 區讀完之後才會放到正式頁面上
優點:這種方法在比較舊的瀏覽器如 Netscape 4 也可以使用、資料傳輸量不限
缺點:無法做搜尋引擎最佳化(SEO)、無法存取跨網域的資料
註:會有上一頁的歷史紀錄,但無法歸納為優點或缺點,端看開發人員的使用角度。像 AJAX 無法有上一頁下一頁的歷史紀錄,對很多以 Usability 為考量的網站就是一種致命傷。
IFrame
跟 Frameset 的原理相同,只是我們不需要再包裝一層,比較容易實做。可以放在現有網頁的任何地方,或者是動態產生再加以利用。
<html>
<head>
<title>Example</title>
<style>
iframe {display:none;}
</style>
</head>
<body>
<h1>Title</h1>
<p>Content</p>
<div id="view">Show Area</div>
<iframe src="about:blank" name="buffer"></iframe>
</body>
</html>
Tab Framework
優缺點與 Frame 一樣,但 SEO 較好。由於 Iframe 是比 Frame 新一些的技術,所以剛剛提到的 NN4 就沒辦法使用 iframe 來做了
Cookies
這種技術是利用 Cookies 不管在 Client 端或 Server 端都可以被存取的特性,我們可以在在頁面上想辦法製造一些與 Server 端的微量變動,讓 Server 接到改變後的 Client 端的請求。那麼,我們該怎麼製造出不整頁重新整理的微量變動呢?有下列兩種方法:
Image Replacement
<!-- 欲送出的變數值 -->
請輸入使用者帳號:<input id="txt" type="text" value="JosephJ"/>
<!-- 回傳的訊息會顯示在此 -->
<p id="msg">在您輸入的過程就會幫您檢查此帳號是否存在唷...</p>
<!-- 被用來發出 Request 的圖片 -->
<img id="img" alt="hidden image"/>
圖片<img/>本身就具有可以利用 js 做動態更替載入的特性。在這邊我們不是要顯示圖片,而是利用這一個特性將我們帶有參數的網址送出、將 src 設為此帶有參數的網址,那麼自然就會對 Server 做出 GET 的 HTTP Request(想當然爾,圖片就是破圖)。
至於資料的傳回,我們就不再利用圖片了!而是在負責的 Server 端網頁(如 PHP 或 ASP),將所需的資料寫入至 Cookie 中。
最後一步,我們再利用 Javascript 來取得這更新的 Cookies 顯示在網頁上。如此一來,整個網頁不需要重新整理就可以抓到資料了!
範例:增測使用者帳號是否存在 ( Server 端程式碼 ) | 範例改進:每打一個字就做一次增測圖片替換的優點:不影響 SEO。
圖片替換的缺點:Cookies 不能用的時候就失效了、只能傳送少量的資訊(Cookies 最多只有 4KB 的容量)、無法存取遠端資訊、若未來對 img 做出安全性限制(僅可使用圖片格式),屆時就無法利用此方法取得資訊。
204 Piggyback
其實這是使用 HTTP 的狀態 (如 5XX 是伺服器錯誤)。利用這種技巧,連一個假的圖片都省掉了,除了 Js 的處理外,你可以用一般的方式連結、或送出表單到某一特定的網頁(Server-side Language)。這個特定的網頁有一個很重要的設定:就是必須將網頁的 Header 設為 HTTP/1.1 204 No Content(可參考:Status Code Definitions)
PHP 的設定法:
<?php header('HTTP/1.1 204 No Content'); ?>
ASP 的設定法:
<% Response.Status = "204 No Content" %>
204 No Content 代表了網頁收到了 Request,但是不做任何的回應。所以當這樣設定了之後,瀏覽器的確會有送出的動作,但是你可以發現所在的網頁將是會靜止不動的。這樣一來,我們「製造 Request 但不重新整理網頁」的目標就達成了。這個目標的網頁,如上面的圖片替代方法,一樣會把所需的回應寫到 Cookies 中。開發者再一次,又可以在 Client 端利用 Js 取得由 Server 端所變動的 Cookies
範例:以使用者帳號取得其資訊 | Server 端程式碼 | Amazon 的評比 | K+ 會用到的 Module優點:不影響 SEO、製作方法與開法一般網頁相似、比圖片置換的方法更為直覺、讓不更新網頁的上傳得以達成(另開新視窗也可達成)。
缺點:同 Image Replacement。
External Javascript
簡單來說,這個技巧就是利用網頁允許使用外部 Javascript 的特性。而,外部 Javascript 的 src 也跟圖片一般,可以動態改變,所以一樣可以達到不 Refresh 整個網頁就發出 HTTP Request 的目標。Even Better,在上述的方法中,沒有一個是可以跨網域的!但是引用外部 Javascript 有不限於本地端的特性(我們時常會連結到其他人 Server 上的 js),所以這個方法是可以對非本地端的網頁發出 HTTP Request 的。我們可以把 Js 當作是一個資料來源。
<html>
<head>
<title>Example</title>
<script src="http://www.benesse.com.tw/tool/city.asp?city=台北市"></script>
<script>
... 在這裡處理上面那隻 script src 的參數值 ...
... 例如將台北市改為台中市 ...
</script>
</head>
<body>
... 網頁內容 ...
</body>
</html>
如同原始碼,我寫了一個以縣市取得相關鄉鎮市區的 External Javascript(按此觀看),你可以從原始檔中發現我們的 js 其實是連到 http://www.benesse.com.tw/tool/address.asp 這個 ASP 網頁,為什麼是 ASP 網頁呢?就是因為希望 js 的內容可以因應帶入的參數有所不同、傳回的東西也就會不相同。您可以將此網頁的原始碼複製貼上到任何地方,你會發現、在有網際網路的情況下、都是可以正常使用的!
範例二:delicious 也有提供這樣的 Feed, 我做了一些改進,你可以自選使用者及觀看筆數(按此觀看)。其實只要格式是 JSON 就可以拿來當 External Javascript
範例三:其實在 Yahoo!Kimo 也有用到 External Javascript 的技術喔,就是 Overture 的 Linkspot 廣告,是為了要能夠放在別的網站,如 MSN、蘋果日報、東森新聞報等網站,在別人的網站只要放一段我們的原始碼,就可以用我們的服務、達到「隨插即用」的效果(按此觀看)
範例四:最近剛好有機會要做 Overture 的 eCM 廣告,把上面的 Linkspot 給淘汰掉 :D (按此觀看)、(我自己做好玩的測試樣式的版本)
優點:可存取跨網欲的資料
缺點:使用他人 Js 有安全性疑慮(按此觀看)、必須仰賴別人的伺服器作業、未來安全性升高有可能禁止遠端的 Js 存取。
XMLHttp
看了以上的各種技術,除了 Remote Scripting 外,其他的技巧似乎都像是一種「Hack」(非正規的做法),有可能未來某一天都被瀏覽器所禁止掉。不過這樣的瓶頸,隨著 XMLHttp 的誕生有了更好的解決之道。
XMLHttp 首先由 Microsoft 實作,是一種可以單純由 Javascript 對後端發出 Http Request、並且接著取得回傳結果的技術。藉由這種方式,開發者就不需要再藉著隱藏的 Frame 、Image、Cookies 或開新視窗來傳遞資料了、讓技術回歸正當的做法。附帶一提的是,這是個老掉牙的技術,直到最近才因為行銷人員將之重新包裝成「AJAX」才大紅特紅。
IE 7 以前, XMLHttp 都還是用 ActiveX 來做
var oRequest = new ActiveXObject("Microsoft.XMLHTTP");
但是在 FireFox 就直接有 window.XMLHttpRequest 這個物件了~
var oRequest = new XMLHttpRequest();
基本的呼叫函式可以這樣寫:
//全域物件
var http_request = false;
function makeRequest(url) {
if (window.XMLHttpRequest) { // Mozilla [11], Safari,...
http_request = new XMLHttpRequest();
}
else if (window.ActiveXObject) { // IE
http_request = new ActiveXObject("Microsoft.XMLHTTP");
}
// 指定後續處理的函式 (Callback Function)
http_request.onreadystatechange = alertContents;
http_request.open('GET', url, true);
http_request.send(null);
}
alertContent 函式
function alertContents() {
if (http_request.readyState == 4) {
if (http_request.status == 200) {
alert(http_request.responseText);
}
else {
alert('There was a problem with the request.');
}
}
}
使用上面兩個函式就可以輕鬆地使用 XMLHttp 來取得資料,以下的範例是我的兩個作品:
討論區,利用 AJAX 達成不換頁、讀取內容 | AJAX DataGrid (創意來源)Problem - Cross Domain
XMLHttp 雖然好用,但是有一個缺憾,跟 Frame 或 WindowsPopup 的技術一樣、它不能取得自身網域外的資料。這點我們必須要配合後端的技術來解決。可以參考 Yahoo! Developer 的這篇文章:HOWTO: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls
藉由這個 proxy.php,我們就可以存取遠端的資料,這樣一來,我們就可以利用 Flickr, Upcoming, Delicious 等服務來架設我們的個人網站,而不用自己建個資料庫,是不是令人很興奮呢?
利用 Yahoo 的 API 來做自己網頁的搜尋引擎 |練習區
以下的區塊是給您練習用的