黃忠成

風雪之閣- i live,so i writing
文章數 - 133, 回應數 - 125, 引用數 - 0


關於我:



黃忠成

  • 資深.NET 技術顧問
  • Run! PC 雜誌專欄作者
  • 程序員雜誌文章作者
  • PC Magazine 雜誌專欄作者
  • MSDN 專欄作者
  • MSDN 特約專屬講師
  • Microsoft .NET專屬講師
  • 台灣微軟特約技術顧問
  • 台灣微軟最有價值專家


  • 批評,指教,鼓勵, 請 寫信給我
    轉載文章請使用連結模式,
    請勿整篇Copy! 謝謝!


    我所提供的教育訓練:

    Windows Forms
    ASP.NET 2.0
    如有課程需要,請與我聯絡!

  • 我的著作:

  • 文章標籤

    全部標籤

    每月文章

    文章分類

    [IE8]Internet Explorer 8 中的JavaScript (2)

     

    Internet Explorer 8 中的JavaScript (2)
     
    /黃忠成
     
     
    本文主題涵蓋
     
    1.       XDR-Cross Domain Request
    2.       DOM Storage
    3.       Online/Offline Detecting API
    4.      AJAX Navigation
     
     
     
    XDR-Cross Domain Request
     
        所有人都知道,AJAX技術所依賴的XMLHttpRequest不能跨網域執行,這是受限於瀏覽器安全模型所致,以往要跨越此界限的方式有兩種,
    一是透過瀏覽器的安全設定允許,二是使用JavaScript Hacking技巧,也就是JSONP的手法運行。
     IE 8提供了另一種方式,那就是改用XDomainRequest物件,程式9是這樣一個例子。
     
    程式9
    XDRRequest.aspx
    <%@ Page Language="C#" AutoEventWireup="true" CodeFile="XDRRequest.aspx.cs" Inherits="XDRRequest" %>
     
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
          <script language="javascript" type="text/javascript">
              var xdr;
              function loadd() {
                  alert(xdr.reponseText);
              }
              function aclick() {
                  xdr =new XDomainRequest();
                  xdr.onload = function() { alert("success: " + xdr.responseText); }
                  xdr.onerror = error;
                  xdr.open("GET", "http://localhost:20339/HTMLInspect/XDRPage.aspx?msg=c");
                  xdr.send("tt");
              }
              function error() {
                  alert("XDR failed");
              }
          </script>
          <a href="#" onclick="aclick();">Test Link</a>
        </div>
        </form>
    </body>
    </html>
     
    XDomainRequest用法與XMLHttpRequest相同,不同的是他可以跨網域執行,前題是要求的頁面必須包含一個特定的Header,如程式10
     
    程式10
    XDRPage.aspx
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
     
    public partial class XDRPage : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {       
            if (Request.QueryString["msg"] != null)
            {
                Response.Clear();
                Response.AppendHeader("Access-Control-Allow-Origin", "http://localhost:20339");
                Response.Write("i am cross-domain response");
                Response.Flush();
                Response.End();           
            }
        }
    }
    以本例來說,當啟動XDomainRequest的網域不是http://localhost:20339的話,那麼即會丟出圖15的錯誤訊息。
    15
    反之則成功跨網域。
    16
    17是此流程示意圖。
    17
     
     
    DOM Storage
     
     HTML 5 中規範了DOM Storage規格,DOM Storage指的是瀏覽器提供一塊儲存空間供網頁使用,目的與Cookies類似,都是讓網頁用來儲存暫時性資料,
    不過與Cookies不同,DOM Storage的容量較大(Cookies只有4KB),目前IE 8所支援的DOM Storage有兩類,一是Session Storage,儲存於此的資料會在瀏覽器
    的該Tab(頁籤)關閉時被清空,空間限定為10 MB,只有該Tab內的網頁能存取到session Storage內資料。另一種是Local Storage,儲存於此的資料會一直存在,
    直到使用者透過【刪除歷程記錄】為止,Local Storage內的資料可被所有Tab內網頁存取,空間限定為10 MB。程式11是使用session Storage的例子。
     
    程式11
    UseDOMStorage.htm
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script language="javascript" type="text/javascript">
            function putSession(value) {
                sessionStorage["mystate"] = value;
            }
     
            function loadSession() {
                return sessionStorage["mystate"];
            }
        </script>
    </head>
    <body>
       <input type="button" value="put state" onclick="putSession(document.getElementById('txtState').value)" />
       <input type="button" value="get state" onclick="document.getElementById('txtState').value = loadSession()" />  
       <input type="text" id="txtState" maxlength="10" />
    </body>
    </html>
     
     
    使用DOM Storage的方式很簡單,以sessionStorage來說,只要以sessionStorage[<key>] = value方式即可將值存入,反之
    則是以sessionStorage[<key>]將值取出。程式12是使用Local Storage的例子。
     
    程式12
    UseGlobalStorage.htm
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
        <script language="javascript" type="text/javascript">
            function putSession(value) {
                localStorage["mystate"] = value;
            }
     
            function loadSession() {
                return localStorage["mystate"];
            }
        </script>
    </head>
    <body>
       <input type="button" value="put state" onclick="putSession(document.getElementById('txtState').value)" />
       <input type="button" value="get state" onclick="document.getElementById('txtState').value = loadSession()" />  
       <input type="text" id="txtState" maxlength="10" />
    </body>
    </html>
     
     
    Online/Offline Detecting API
     
       IE 8是少數完整呈現navigator.onLine屬性的瀏覽器,此屬性可用來偵測瀏覽器是否處於網路已連線狀態,在IE 7前,這個屬性僅能反應
    使用者點選檔案選單中離線瀏覽與否的狀態,在IE 8,這個屬性已經可以正確反應網路連線狀態,因此在IE 8中,我們可以透過navigator.onLine
    屬性來判斷目前是離線或是連線狀態,更甚之,IE 8還提供了online及offline事件,分別在瀏覽器於線上及離線切換時觸發(包含網路斷線及重新連線、
    或是由檔案選單中選取離線工作)。
     
    程式13
    DetectingOnOffline.htm
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     
    <html>
    <head>
     <script language="javascript" type="text/javascript">
     
        function updateStatus() {
            if (navigator.onLine) {
                document.getElementById("state").innerHTML = "Online";
            }
            else {
                document.getElementById("state").innerHTML = "Offline";
            }
            document.body.ononline = OnLine;
            document.body.onoffline = OffLine;
        }
     
        function OnLine() {
            document.getElementById("state").innerHTML = "Online";
        }
     
        function OffLine() {
            document.getElementById("state").innerHTML = "Offline";
        }  
       
     </script>
    </head>
    <body onload="updateStatus();">
     <p id="state"></p>
    </body>
    </html>
     
     
    AJAX  Navigation
     
         AJAX技術的熱門程度,遠超過當初提出人的想像,也因為其太熱門,一些問題也慢慢的浮現,最常見的就是Back(上一頁)按紐無法運作,基本上,
    瀏覽器的上一頁按紐是依據URL來產生的,但在AJAX技術下,URL是不會有變動的,所以自然上一頁按紐也無法運作了。 
     解決此問題的辦法有很多,多半是運用hash技巧,IE 8是少數將此功能內建的瀏覽器,IE 8在遭遇AJAX存取時,會在URL上插入一小段Tag,藉此
    讓上一頁可以正常運作,雖說如此,大部份的程式碼還是要設計師自己寫,程式14是使用此技巧的例子。
     
    程式14
    JQueryNavigator.htm
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
     
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title></title>
       
        <script language="javascript" type="text/javascript" src="jquery-1.3.2.min.js"></script>
        <script language="javascript" type="text/javascript">
            var currentAction = -1;
            var sysAction = false;
     
            function OnHashChanged() {
                if (sysAction) {
                    sysAction = false;
                    return;               
                }
                var hashAction = Number(document.location.hash.substr(7));
                this.goToPage(hashAction);           
            }
     
            function goToPage(hashAction) {
                $.get("AjaxService.aspx?actionID=Action" +
                       hashAction.toString(),HandleBackCallback);
            }
     
            function DoAction() {
                sysAction = true;
                $.get("AjaxService.aspx", HandleCallback);
            }
     
            function HandleBackCallback(data, textStatus) {
                document.title = data;
                $("#content").get(0).innerHTML = data;
            }
     
            function HandleCallback(data) {
                currentAction++;
                document.title = data;
                document.location.hash = "Action" + currentAction.toString();           
                $("#content").get(0).innerHTML = data;
            }
     
          
        </script>   
    </head>
    <body onload="document.body.onhashchange = OnHashChanged;">
        <div id="content"></div>
        <input type="button" value="call action" onclick="DoAction()" />   
    </body>
    </html>
    AJAXService.aspx
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
     
    public partial class AjaxService : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {       
            Response.Expires = -1;
            if (Request.QueryString["actionID"] != null)
            {
                Dictionary<string, string> sessionStorage =
                     Session["Actions"] as Dictionary<string, string>;
                if (sessionStorage != null)
                {
                    Response.Write(sessionStorage[Request.QueryString["actionID"]]);
                    Response.Flush();
                    Response.End();
                    return;
                }
                else
                {
                    return;
                }
            }
            else
            {
                Dictionary<string, string> sessionStorage =
                         Session["Actions"] as Dictionary<string, string>;
                string data = DateTime.Now.ToString();
                if (sessionStorage == null)
                {
                    sessionStorage = new Dictionary<string, string>();
                    Session["Actions"] = sessionStorage;
                    sessionStorage.Add("Action0", data);
                }
                else
                    sessionStorage.Add("Action" + sessionStorage.Count.ToString(), data);
                Response.Write(data);
                Response.Flush();
                Response.End();
            }
        }
    }
    18是執行畫面。
    18
    這個例子有點複雜,讓我拆解開來談,首先是AjaxService.aspx的程式碼,這裡會為每個AJAX Request建立一個Action記錄,這些記錄存放在一個
    Dictionary Collections中,這個Collection中每個元素代表一個Action,以Action<Request序號>Key,值則是當時AJAX Request時的回傳值。
     
       當JQueryNavigator.htm中以get來啟動一個AJAX Request成功後,HandleCallback會被呼叫,此處產生一個Action序號(currentAction),並將其以Action<Action序號>
    設定給document.location.hash,然後設定document.title後結束。HandleCallback的一連串動作會引發IE 8記錄歷程的動作,其會以document.title為歷程項目的標題,
    以document.location.hash為點選該歷程記錄時的值,當使用者點選上一頁或是某個歷程項目時,document.body.onhashchange事件會被觸發,而我們所設定的
    OnHashChanged函式就會被呼叫,此時的document.location.hash值正是當初IE 8所記錄的,於此我們再以get函式將Action<序號>做為URL附加參數傳入,
    最後AjaxService.aspx中以Action<序號>來取出當初預儲的值回傳。
     
     整個流程順下來,你會發現IE 8扮演的角色是在記錄歷程記錄時將hash視為是URL的一部份一起記錄下來,但hash值的產生及管理是由我們用JavaScript處理的,
    後端也必須預先記錄每個Request,因為當使用者企圖回到某個歷程記錄時,IE 8會觸發onhashchange,而我們需要在此處重新回到後端來取得先前取過的值。
     另一種更精巧的設計方式,還可以利用DOM Storage的特性,將這些值預先儲存在客戶端,這樣就不用得常常回後端取得先前已取過的值了。
     

    本文範例下載

     


    posted on 2009/4/10 00:00 | 1 人收藏 1 人推薦 我要推薦 | 閱讀數 : 3153 | 文章分類 [ IE ] 訂閱

    Feedback

    目前沒有回應.

    回應

    標題
    姓名
    電子郵件 (將不會被顯示)
    個人網頁
    內容 
      登入後使用進階評論  
    Please add 7 and 5 and type the answer here:

    Powered by: