1. 程式人生 > >頁面間大量資料引數傳遞

頁面間大量資料引數傳遞

前言

我們在開發專案中經常會遇到一種問題,就是在前端頁面跳轉時傳遞某些引數,通常我們是通過路由傳遞的,但是如果資料量很多的情況下,會造成路由非常的長,如果在大的話甚至會超出位址列URL的最大限度,這就狗帶了.最近手頭上一個專案的前端剛好遇到這個問題,該專案前端用的是vue2.x.不是什麼大問題,但是之前沒有認真想過解決辦法,於是將解決思路記錄下來了.

位址列URL最大限度

首先我查了不同瀏覽器位址列URL的最大限度.

雖然HTTP協議的RFC規範並沒有詳細規定URL的最大字元長度限制,但實際上,在瀏覽器或者伺服器中總會存在限制的。這裡所說的字元是指ASCII字元。HTTP RFC2616協議沒有規定URL的最大長度,規定伺服器如果不能處理太長的URL,就得返回414狀態碼(Request-URI Too Long)。

微軟 Internet Explorer:微軟幫助網站上說IE7之前(包括IE7)的瀏覽器,對URL的最大長度限制是2,083個字元。Firefox:對於Firefox1.5.x,位址列能顯示的URL最大長度是65,536個字元,但實際上有效的URL最大長度不少於100,000個字元。對於Firefox 3.0.5,mozilla官方論壇上有人測試其URL長度限制為65,000個字元。也有人說Firefox可以支援URL高達2Gbyte的長度(參考),在data URL中可以運用到這樣大資料量的URL。dataURL是一種URL本身包含了實際資料的URL,比如一個圖片、一個HTML網頁或者全部的資料、程式碼等等。僅有Firefox支援dataURL。Safari:

Safari最少支援80,000個字元長度的URL。Opera:Opera官方網站上說,Opera並沒有強制限制URL的長度。網友測試Opera 9支援最少190,000個字都長度的URL,並且Opera9的位址列可以顯示、編輯、複製和貼上完整的URL串。

綜上,又在網上找了一個附表:

IE

URL最大限制是2083個位元組,Path長度最大是2048位元組(Get請求)。

Firefox

65536

Safari

80000以上

Opera

190000位元組以上

Chrome

8182位元組

Apache Server

8192位元組

IIS

16384位元組

Perl HTTP::Daemon

至少8000位元組

我的思路

思路一

我的第一個想法就是通過快取進行解決----cookie/localStorage/sessionStorage.通過在伺服器或客戶端進行資料快取以供頁面進行讀取.但是在後續的思考中我想到首先cookie快取量很小,同時session/cookie對與網站所有頁面是透明的,我只是想實現指定頁面間進行引數傳遞,其他頁面應該不知情,考慮到保密性,我放棄了這個想法.

思路二

我的第二個思路還是通過快取來實現,但是是通過application cache(共享本地快取),具體的介紹就不在這裡說了.但是我考慮到application cache具有快取時間,而我想要的是在頁面跳轉後快取的引數資料被銷燬,也就是類似快閃記憶體的機制.同時application cache快取頁面需要的資源,那麼其他頁面所需要的資源也同時被快取下來,這樣做得不償失.

思路三

通過js的全域性變數.這個沒什麼介紹的,將引數儲存在全域性變數中,那麼在頁面宣告週期內所有頁面都可以使用.但是還是那個問題,在使用全域性變數的時候,其他頁面也能夠獲得.所以pass.

思路四

我找到利用原生很不錯的方法,那就是通過模態視窗來實現頁面間的引數傳遞.以下是對showModalDialog(模態視窗)的簡單介紹:

基本介紹:

          showModalDialog()         (IE 4+ 支援)
          showModelessDialog()      (IE 5+ 支援)
          window.showModalDialog()                  方法用來建立一個顯示HTML內容的模態對話方塊。
          window.showModelessDialog()             方法用來建立一個顯示HTML內容的非模態對話方塊。
使用方法:
          vReturnValue = window.showModalDialog(sURL [, vArguments] [,sFeatures])
          vReturnValue = window.showModelessDialog(sURL [, vArguments] [,sFeatures])
引數說明:
         sURL          --  必選引數,型別:字串。用來指定對話方塊要顯示的文件的URL。
         vArguments    -- 可選引數,型別:變體。用來向對話方塊傳遞引數。傳遞的引數型別不限,包括陣列等。對話方塊通過 

                          window.dialogArguments來取得傳遞進來的引數。
         sFeatures     -- 可選引數,型別:字串。用來描述對話方塊的外觀等資訊,可以使用以下的一個或幾個,用分號“;”隔開。
sFeatures的引數選擇:
1.    dialogHeight:    對話方塊高度,不小於100px
2.    dialogWidth:    對話方塊寬度。
3.    dialogLeft:     離螢幕左的距離。
4.    dialogTop:     離螢幕上的距離。
5.    center:          { yes | no | 1 | 0 } :              是否居中,預設yes,但仍可以指定高度和寬度。
6.    help:             {yes | no | 1 | 0 }:                是否顯示幫助按鈕,預設yes。
7.    resizable:       {yes | no | 1 | 0 } [IE5+]:     是否可被改變大小。預設no。
8.    status:          {yes | no | 1 | 0 } [IE5+]:      是否顯示狀態列。預設為yes[ Modeless]或no[Modal]。
9.    scroll:            { yes | no | 1 | 0 | on | off }:是否顯示滾動條。預設為yes。

...
使用showModalDialog進行引數傳遞:

通過vArguments來進行傳遞的。型別不限制,對於字串型別,最大為4096個字元。也可以傳遞物件,如下:

test.html:

var obj=new Object();
obj.name="qiubinchao";
obj.tel="12345678"; 
window.showModalDialog('./testb.html',obj,"dialogWidth:500px;dialogHeight:550px"); 
window.location.href="./testb.html"; 
testb.html:

var obj = window.dialogArguments
console.log(window.dialogArguments);
一個問題:在chrome37後,showModalDialog被chrome禁了,這就很尷尬了,但是有解決的辦法:
test.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    
    <script>
        show();
        function AddNew() {
            if(!window.showModalDialog) {
                window.showModalDialog=function(url,name,option){
                    if(window.hasOpenWindow){
                        window.newWindow.focus();
                    }
                    var re = new RegExp(";", "g");  
                    var option  = option.replace(re, '","'); //把option轉為json字串
                    var re2 = new RegExp(":", "g");
                    option = '{"'+option.replace(re2, '":"')+'"}';
                    option = JSON.parse(option);
                    var openOption = 'width='+parseInt(option.dialogWidth)+',height='+parseInt(option.dialogHeight)+',left='+(window.screen.width-parseInt(option.dialogWidth))/2+',top='+(window.screen.height-30-parseInt(option.dialogHeight))/2;
                    window.hasOpenWindow = true;
                    window.newWindow = window.open(url,name,openOption);
                }
            }

        }

        function show() {
            var obj=new Object();
            obj.name="qiubinchao";
            obj.tel="12345678"; 

            AddNew();
            window.showModalDialog('./testb.html',obj,"dialogWidth:500px;dialogHeight:550px"); 

            window.location.href="./testb.html"; 
        }
    </script>
</body>
</html>
一些其他問題:
  • 怎樣才讓在showModalDialog和showModelessDialog的超連線不彈出新視窗?

在被開啟的網頁里加上:

<base target="_self">
就可以了。這句話一般是放在<head>之間的。
  • 怎樣才重新整理showModalDialog和showModelessDialog裡的內容?

在showModalDialog和showModelessDialog裡是不能按F5重新整理的,又不能彈出選單。這個只能依靠javascript了,以下是相關程式碼:

<body onkeydown="if (event.keyCode==116){reload.click()}">
<a id="reload" href="filename.htm" style="display:none">reload...</a>
將filename.htm替換成網頁的名字然後將它放到你開啟的網頁裡,按F5就可以重新整理了,注意,這個要配合<base target="_self">使用,不然你按下F5會彈出新視窗的。
  • 如何用javascript關掉showModalDialog(或showModelessDialog)開啟的視窗。
<input type="button" value="關閉" onclick="window.close()">

也要配合<base target="_self">,不然會開啟一個新的IE視窗,然後再關掉的。

  • Math.random與showModalDialog。

當你設定的彈出網頁固定時(如上面的"modal.htm"頁面),ie很可能到臨時檔案區,下載上次產生的該頁面(openPage.html),而沒有重新載入,對於動態載入的頁面來說,這樣往往產生誤會,如沒有及時更新資料,也就更不利於開發者測試。所以,你可以採用如下方式:      

var strPage = “/medal.htm?random="+Math.random();

這樣每次產生的strPage是不一樣的.

但是最後我還是放棄了,因為首先我用的是vue框架,寫原生太不優雅;其次如上所示,使用模態視窗的侷限性太大.

思路五

俗話說:解鈴還須繫鈴人

在一籌莫展之際,我想到了vue-router中的params.上程式碼:

傳參: 
this.$router.push({name:'/send/sendHome', params: {setStr: this.multipleSelection}});

接收引數:
let setArray = this.$route.params.setStr;
vue-router中無論是params/query(路由物件屬性)都支援引數傳遞,但是我的毛病又犯了,這兩個有什麼區別呢?

query傳遞引數:

傳參: 
this.$router.push({
        path:'/xxx'
        query:{
          id:id
        }
      })

接收引數:
this.$route.query.id

注意:無論是params還是query進行引數傳遞,傳參是this.$router,接收引數是this.$route,一定要細心.

區別:

1.當使用query進行引數傳遞時,引數會跟在路徑後面.我們可以在位址列看到後面跟的引數,而params不會在位址列顯示.直白的說query相當於get請求,而params相當於post請求.

2.params傳參,push裡面只能是 name:'xxxx',不能是path:'/xxx',因為params只能用name來引入路由,如果這裡寫成了path,接收引數頁面會是undefined.

果然...自己挖的坑還要自己填...