2020年12月5日 星期六

[C# ASP.NET]利用JavaScript偵測畫面寬度並且去觸發POSTBACK回傳來達到畫面上的調整

     目前正在用C# WebForm Chart控制項來畫統計圖表,但是如果要利用此來做RWD頁面就會有問題,因為Chart是在Server端處理完後再輸出,所以Client端最後其實得到的是<img>圖檔。沒辦法針對手機旋轉而去變化,而單純去伸縮img高寬只會讓解析度跑掉。至此我需要的是能夠偵測Client端的寬度變化並且回傳到Server端,好讓Chart能夠讀取新的寬度後再重新輸出。

     因為C#沒辦法正確抓到Client端的寬度及變化,所以利用JavaScript來協助處理,然後為了觸發POSTBACK並將寬度數值傳回Server端,這邊先在畫面放上下面這兩個控制項。
<asp:HiddenField ID="HidnW" runat="server" />
<asp:Button ID="btnReProChart" runat="server" style="display:none"/> 

1.首先在第一次載入頁面時,紀錄螢幕寬度並寫到HidnW。然後藉由btnProChart這隱藏按鈕來觸發POSTBACK來做初次調整
    
//抓取HidnW
let HW = document.getElementById("HidnW");
if (HW.value == "")
{   
    //紀錄頁面寬度
    HW.value = document.body.offsetWidth;
    __doPostBack ('btnReProChart','');
}

如此一來會在初次載入時寫入寬度值到HidnW,並POSTBACK回Server端。

2.再來就是要在Client端寬度變化時也觸發POSTBACK

//寬度變化時
window.onresize = function(){
    //避免過度回傳,只有原本寬度和現在寬度變化量有一定差距時再變化
    if (Math.abs(HW.value-document.body.offsetWidth) >50)
    {
        //這邊在網址加上hash值(第三段再說明原因)
        history.replaceState({}, "Jump", window.location.toString() + "#Jump");
           
        HW.value = document.body.offsetWidth;
        __doPostBack ('btnReProChart','');
    }
}

順便一提,如果用手機Chrome APP來瀏覽網頁時,畫面上下滑動也會觸發window.onresize。因為頁面滑動的同時網址列也會跟著顯示或隱藏,導致畫面的高度(window.innerHeight)也隨之變動而去觸發window.onresize事件。

3.因為程式的原理是畫面寬度變化超過50就PostBack回傳到Server端,如此一來同一頁面將會留下複數的history紀錄。雖然可以多放一個LinkButton來導回正確的上一頁,但如果是在手機上操作大部分都會利用返回鍵(Chrome)或是左右滑動(Safari)來返回上頁。所以勢必得想辦法讓重複history紀錄刪除或是跳過。
    
     而上一段在URL加上#Jump就派上用場了,但是因為Chrome和Safari瀏覽器的差別,所以這部份分成兩種寫法處理。因為Chrome回到上一頁會重新執行頁面的JavaScript,所以比較方便處理,只要以下程式碼寫在文本裡面就可以。

//跳頁
if (location.hash.indexOf('Jump') != -1) window.history.back();
    
     而Safari回上頁的情況下,並不會重新執行頁面的JavaScript,所以要寫在popstate事件裡才會執行。MDN上的解釋:https://developer.mozilla.org/zh-TW/docs/Web/API/Window.onpopstate
    
window.addEventListener('popstate', function (event) {
    if (location.hash.indexOf('Jump') != -1) window.history.back();
})

4.在處理完上一頁後,最後得要再次確認目前寬度和上頁Chart輸出寬度是否吻合,所以要在PageShow事件裡(為了配合Safari上一頁Cache不會執行頁面JavaScript)做最後確認。
    
window.addEventListener('pageshow', function (event) {
    //一樣檢測寬度變化量
    if (Math.abs(HW.value-document.body.offsetWidth) > 50)
    {
        HW.value = document.body.offsetWidth;
        __doPostBack ('btnReProChart','');
    }
})

到此就大致上完成了。

結語:事實上這並不是一個好方法,畢竟需要POSTBACK到Server端處理,如果今天不斷的旋轉螢幕就得一直POSTBACK而造成Server不必要的Workload。但是要讓Chart不斷產生出配合螢幕寬度變化的圖檔,就只能將資料不斷送回Server處理。除非今天不使用Chart控制項,而是其他可在Client端處理的統計圖,或者直接不讓統計圖隨者螢幕旋轉而去變化,而只在第一次載入時才去判斷,這樣也可以減少很多Workload。不過這案子主要僅供內部使用,所以不會有大量的連線人數,這點算是不幸中的大幸。


沒有留言:

張貼留言