因為搞了一整個早上,所以決定來好好整理一下這次的心得。

先來個前情提要好了。
我需要寫一個監控交易列表的網頁,內容就是一整排的交易明細,一段時間後會自動更新。
因為列表可能很長,櫃台在看某一筆資料的時候一定會捲動捲軸,
那如果在此時更新,通常Scrollbar會回到網頁Top的位置,這樣顯得很不方便。

所以我的需求是:自動更新的網頁,而且更新後Scrollbar會維持在更新前的位置。
這個目標在以前寫的版本已經有成功做到, 之前寫的網頁是一整個頁面,沒有框架。



要用Javascript refresh網頁有很多寫法,最常見的大概是:
window.location.reload(); 以及
window.location.href=self.location.href; 之類的。

而我當時試了許多方法,意外發現 window.history.go(int page) 可以達到我的目標。
history如字面意義是存放網頁的瀏覽紀錄。 變數page如果給1,就會有下一頁的效果;
同理給-1,就會回到上一頁。而要在本頁更新,則是傳0。
有趣的是它似乎把之前使用者瀏覽的最後位置也記住了,
所以不會有像用其他方法一樣Scrollbar又回到頁頂的問題。

所以之前的問題就這樣解決了。
不過現在重新寫過,要把介面改掉,切了四個框架。



現在我只要左上方的frame會更新就好,那要怎麼辦呢?
想說簡單,把window用frame取代掉就好啦!

window.top.frames[frame_name].location.reload();

這樣就可以只更新那個頁面了。
好,既然reload()可行,那麼history.go(0)應該也可以如法炮製吧?

window.top.frames[frame_name].history.go(0);

結果神奇的事情發生了:四個頁面全部一起Refresh了。
這不是很沒道理嗎?我有指定frame了呀!
不信邪的我又改了許多指定frame的方式:

parent.frame_name.history.go(0);
window.top.frame_name.history.go(0);
....

結果通通都沒用:四個頁面永遠會一起更新。
這樣不行啊!其他頁面還在做交易的時候隨便更新不就完蛋了?
我還一度以為history.go()對frame的執行有問題,所以另外開檔案測試了一下。
結果發現history.go(1)和history.go(-1)的運行都很正常:不會影響到別的frame。
單單只有傳0的時候會全部的frame一起動作...

心血來潮換了瀏覽器測,發現IE竟然Work得相當好!
這是什麼鬼設定我真的不明白了。

事情到此本來可以告一段落,因為店裡的Browser本來就是IE。
可是我還是希望能找到IE和FF都適用的方案,所以又花了些時間找方法。

這時候就是Google大賽了,以下是值得參考的幾項連結:
How to get an anchor after page being reloaded?
Maintain scrollbar position on postback
Auto-refresh dashboard/project grid
Maintaing Page Scroll Position

不過有很多方法都是從別的frame去控制另一個frame,
需要使用者的手動submit form之類的動作。
雖然理論上同一個頁面也可以用body onLoad的方法做到同樣的事情, 但是我老是試不成功。
本來想採用最後一條連結的方式,可是好像只有一開始試成功過,後來就不行了。
目前我還搞不清楚理由。好像接收不到onunload之後傳出去的訊息。
就算我把FF主控台說的錯誤訊息 => forms no properties 改掉,
把forms[0] 改成 form的名稱還是沒有辦法。

所以現在就先用Cookie的方式了(第三條連結下方,Michael Nacey的作法),
雖然我覺得用Cookie並不是個好作法,但是暫時就這樣做吧。
如果有人還發現了什麼好點子,請告訴我~

另外還要注意一點就是 body.onScroll() 和 scrollTop 在DTD版本不同的適用性。
現在的版本宣告已經不支援 body.onScroll() 了,所以要從JS裡面 Call window.scroll()。
至於取得頁面的scrollTop屬性,視宣告與IE版本不同有兩種寫法:
document.documentElement.scrollTop ( IE6, DTD 4.01 ) 或者是
document.body.scrollTop ( IE5, DTD 3.2 )

老實說,各家Browser在規格上的不一,真的是很煩!
下面附上Michael Nacey的JS code,有興趣的可以參考一下。
因為四個頁面的Cookie要分開存,所以我加了頁面的檔名到Cookie名稱前面。






function setPosCookies (){
var scrollX, scrollY;

// 儲存Scrollbar的位置 (x, y)
if (document.all){
if (!document.documentElement.scrollLeft)
scrollX = document.body.scrollLeft;
else
scrollX = document.documentElement.scrollLeft;
if (!document.documentElement.scrollTop)
scrollY = document.body.scrollTop;
else
scrollY = document.documentElement.scrollTop;
}else{
scrollX = window.pageXOffset;
scrollY = window.pageYOffset;
}

// 設定 Cookie, 名稱為頁面 http://yyyy/XXXX.php => 取XXXX用
var url = document.location.href;
var x_name = url.substring(url.lastIndexOf('/')+1, url.lastIndexOf('.')) + "scrollX";
var y_name = url.substring(url.lastIndexOf('/')+1, url.lastIndexOf('.')) + "scrollY";
setCookie(x_name, scrollX);
setCookie(y_name, scrollY);
}

function setCookie(c_name,value,expiredays){
// 不指定expire date, 則離開browser, cookie即失效
var exdate = new Date();
exdate.setDate(exdate.getDate()+expiredays);
document.cookie = c_name+ "=" +escape(value)+
((expiredays==null) ? "" : ";expires="+exdate.toGMTString());
}

function getCookie(c_name){
if (document.cookie.length>0){
c_start=document.cookie.indexOf(c_name + "=");
if (c_start!=-1){
c_start=c_start + c_name.length+1;
c_end=document.cookie.indexOf(";",c_start);
if (c_end==-1) { c_end=document.cookie.length;}
return unescape(document.cookie.substring(c_start,c_end));
}
}
return "";
}

function checkCookie(){
// 取得 Cookie => (x, y)座標
var url = document.location.href;
var x_name = url.substring(url.lastIndexOf('/')+1, url.lastIndexOf('.')) + "scrollX";
var y_name = url.substring(url.lastIndexOf('/')+1, url.lastIndexOf('.')) + "scrollY";
var x = getCookie(x_name);
var y = getCookie(y_name);
if (y == null || y == "") { y = 0;}
if (x == null || x == "") { x = 0;}
window.scrollTo(0, y)
}

window.onload = checkCookie;
window.onscroll = setPosCookies;
window.onkeypress = setPosCookies;
window.onclick = setPosCookies;

創作者介紹

天晴天雨,星映月。

Starshine 發表在 痞客邦 PIXNET 留言(3) 人氣()


留言列表 (3)

發表留言
  • 瑋珊
  • 寫得很詳盡呢,謝謝。
  • 哪裡,謝謝你的回應。: )

    Starshine 於 2007/08/30 20:16 回覆

  • bruse
  • 感恩!

    您的程式碼解決在下的問題,非常感謝!
  • 不客氣,謝謝你的回應 : )

    Starshine 於 2008/04/06 11:54 回覆

  • AKOU
  • 各位好

    我的資料是資料庫拉出來會垂直排列由上往下…

    如果要設定修改的話我預設是彈出視窗,設定完成則進去我的close頁面
    (連結是寫javasc#ipt:;)

    寫法如下

    window.opener.location.reload();
    window.close();

    這樣的確可以在設定完成後,就關閉設定視窗並且將主頁面重新整理

    但是遇到的問題就是,如果使用者在第五筆(也就是捲軸拉到中間了)

    這樣重整就會讓畫面捲軸又回去第一筆…使用者又要拉到中間

    所以我搜尋資料找到這個寫法
    window.opener.location.reload();
    window.opener.history.go(0);
    window.close();

    可是好像沒用@@…效果還是跟最初的寫法一樣

    請問要如何重整母視窗並且捲軸位置不變之後子視窗自己關閉呢…?

    謝謝
找更多相關文章與討論