HTML5筆記:跨域通訊、多線程、本地存儲和多圖片上傳技術


  最近做項目在前端我使用了很多新技術,這些技術有bootstrap、angularjs,不過最讓我興奮的還是使用了HTML5的技術,今天我想總結一些HTML5的技術,好記性不如爛筆頭,寫寫文章可以很好的整理思路,寫到博客里還能做個備忘。

  1) 跨域通訊

  現在做企業項目,前端很不自然的會大量使用iframe標簽,我以前在文章里提到iframe是一個效率極其低下的標簽,但是如果項目沒有什么性能的苛求,使用iframe還是非常的方便的。

  使用iframe經常碰到父子窗體通訊的問題,我們看看下面的代碼:

  父頁面代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>父窗體</title>
</head>
<body>
    <span id="superSpan">父窗體</span>&nbsp;&nbsp;<button onclick="pTest()">點擊</button>
    <iframe src="inner.html" width="300"></iframe>
</body>
</html>
<script type="text/javascript">
    var superStr = "父窗體:hello iframe";
    function pTest(){
        var s = window.frames[0].window.subStr;
        alert(s);
    }
</script>

  子窗體頁面代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子窗體</title>
</head>
<body>
    <span id="subSpan">子窗體</span>&nbsp;&nbsp;<button onclick="sTest()">點擊</button>
</body>
</html>
<script type="text/javascript">
    var subStr = "子窗體:OK,Good!";
    function sTest(){
        var s = parent.superStr;
        alert(s);
    }
</script>

  由上面例子我們可以知道父子窗體可以進行信息的交流,不過這個交流局限性很高,它只能是做到javascript變量和方法的相互交流,如果我們想在父頁面操作子頁面的DOM結構或者子頁面想操作父頁面的DOM結構,這都是不行的(不過這點在我即將要說到的技術也是沒法做到的),另外還有一個非常重要的一點那就是這些操作必須是同域下的。

  今天我介紹下HTML5里實現父子窗體通訊的解決方案,它不僅可以在同域下相互發送信息,在不同域名下也是可以相互發送信息的。

  同域名下的例子:

  父窗體:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>HTML5通訊API</title>
</head>
<body>
    <h1>通訊示例,相同域名下</h1>
    <iframe width="500" src="http://localhost:63342/socketprj/sub.html" onload="test()"></iframe>
    <div id="showcontent"></div>
</body>
</html>
<script type="text/javascript">
    window.addEventListener("message",function(evt){
        document.getElementById("showcontent").innerHTML = evt.data;
    },false);

    function test(){
        var frm = window.frames[0];
        frm.postMessage("你好,我是父頁面訪問地址是http://localhost:63342/socketprj/main.html","http://localhost:63342/socketprj/sub.html");
    }
</script>

  子窗體:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>子頁面</title>
</head>
<body>
子頁面
</body>
</html>
<script type="text/javascript">
    window.addEventListener("message",function(evt){
        console.log(evt);
        document.body.innerHTML = "父頁面過來的數據:" + evt.data;
        evt.source.postMessage("子頁面回傳過來的信息地址是" + this.location + ",父頁面的地址是" + evt.origin,evt.origin);
    },false);
</script>

  這種跨域通訊方式其實就是一個事件,這個事件就是message事件,它是window對象下的一個事件,接收信息就是給window對象綁定message事件,event對象的data屬性可以獲取發送過來的信息,發送信息則是使用postMessage方法了。

  如果是跨域,子窗體的代碼不變同上,父窗體代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>HTML5通訊API</title>
</head>
<body>
    <h1>通訊示例,不相同域名下</h1>
    <iframe width="500" src="http://localhost:8080/sub.html" onload="test()"></iframe>
    <div id="showcontent"></div>
</body>
</html>
<script type="text/javascript">
    window.addEventListener("message",function(evt){
        document.getElementById("showcontent").innerHTML = evt.data;
    },false);

    function test(){
        var frm = window.frames[0];
        frm.postMessage("你好,我是父頁面訪問地址是http://localhost:63342/socketprj/main.html","http://localhost:8080/sub.html");
    }
</script>

  2) 瀏覽器的多線程技術:web worker

  這里我們先看一個例子吧,這個例子是沒有使用多線程技術做一個超長javascript運算,代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>對比測試的參照頁面worker</title>
</head>
<body>
    <h1>對比測試的參照頁面:javascript執行時間過長會導致瀏覽器終止javascript執行</h1>
    請輸入:<input type="text" id="ipt"/>&nbsp;&nbsp;<button onclick="test()">計算</button>
</body>
</html>
<script type="text/javascript">
    function test(){
        var num = parseInt(document.getElementById("ipt").value,10);
        var res = 0;
        for (var i = 0;i < num;i++){
            res += 1;
        }
        alert(res);
    }
</script>

  我們在頁面里輸入999999999999,等一段時間,瀏覽器會彈出一個提示框,如下圖所示:

 

  瀏覽器會提示我們去終止javascript執行,這是為啥了?

  瀏覽器內部其實包含兩個執行引擎,一個是渲染引擎,這個引擎負責頁面的展示,一個是javascript引擎,它負責javascript執行,但是瀏覽器在實際執行的方式是以單線程的方式執行渲染操作和javascript操作,也就是說頁面一回只能執行一個操作要么渲染頁面要么就是執行javascript代碼,因此當javascript執行時候就會阻塞渲染的執行,假如javascript執行時間過長頁面加載就會被阻塞,這時候我們就會感覺頁面不可用了,為了避免javascript過長執行導致頁面無法使用,瀏覽器在檢測到javascript執行到一個極限次數時候就會彈出以上提示框。

  關於瀏覽器能不能提供多線程的解決方案有人曾經咨詢過javascript之父,這位大師很干脆的說,這是不可能的,他提出的理由是多線程操作過於復雜,那怕是最有經驗的程序員也很難控制好多線程技術,引入它只會增加學習成本和開發風險。

  不過話說回來,傳統的瀏覽器單線程改成多線程執行難度還是很大的,因為javascript是有權利修改頁面的展示,如果引入多線程,搞不好程序員就很難正確控制頁面的展示了。

  谷歌的工程師為了讓瀏覽器有更好的用戶體驗,在HTML5沒有出現之前做出了一個解決方案,那就是Gear,Gear其實就是web worker的前身,web worker相當於Gear的升級版,下面我們就來看看web worker的使用吧,代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>worker單線程,無嵌套</title>
</head>
<body>
    <h1>worker單線程,無嵌套</h1>
    請輸入:<input type="text" id="ipt"/>&nbsp;&nbsp;<button onclick="test()">計算</button>
</body>
</html>
<script type="text/javascript">
    var worker = new Worker("js/worker.js");
    worker.onmessage = function(evt){
        alert(evt.data);
    }

    function test(){
        var num = parseInt(document.getElementById("ipt").value,10);
        worker.postMessage(num);
    }
</script>

  woker.js的代碼如下:

onmessage = function(evt){
    var num = evt.data;
    var res = 0;
    for (var i = 0;i < num;i++){
        res += 1;
       // console.log(res);
    }
    postMessage(res);
}

  使用worker技術,我們要把多線程的代碼寫在一個單獨的js文件里面,同時定義一個onmessage方法,這個相當於一個事件的回調函數,回調函數的參數event里的data屬性用來接收數據,postMessage方法傳輸數據,這個做法和前面的message相似。本例子只是演示了一個單線程的例子,我們還可以使用線程嵌套線程,這個我就不細說了,有興趣的朋友可以嘗試一下。

  3) 本地存儲

  HTML5的web storage技術有兩個一個是sessionstorage和localstorage,sessionstorage顧名思義就是只在會話有效,localstorage則是長時間有效,我在項目里做demo程序時候,就使用localstorage做本地存儲,相當於一個小型數據庫,web storage技術很簡單,我就給一個簡單例子,代碼如下:

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>本地存儲-存儲數據</title>
</head>
<body>
    <h1>本地存儲-存儲數據</h1>
</body>
</html>
<script type="text/javascript">
    localStorage.setItem("mess","Hello Message!");
    localStorage.setItem("obj",{id:"111",name:"xtq"});
</script>

 

  在chrome瀏覽器里我們可以在控制台里Resource的local Storage找到存儲的數據,我們可以發現obj最終存儲的是[object,object],這就說明web storage只能存儲字符串,如果我們想存儲javascript對象就的將其序列化變成字符串進行存儲。

  4) 多文件上傳

  文件上傳使用的標簽就是:

<input type="file" multiple id="fileIpt" size="120"/>

  在html4里,這個標簽只能上傳一個文件,現在我們只要在標簽里加入multiple屬性就可以實現多文件上傳。在html4里ajax是沒有辦法做上傳文件操作,因此我們如果想實現ajax文件上傳就不得不使用hack技術,模擬文件上傳,這個我曾在博客里分享過我寫的模擬多文件上傳的demo,當時也是沒法子要保證瀏覽器兼容性,不得不hack一把了。

  在html5里我們對文件上傳的控制力變得更強了,今天只展示一個簡單文件上傳操作的API,今后我會寫一個復雜的多文件上傳的demo和大家一起分享下,我們先看下面這個例子:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>多文件上傳</title>
</head>
<body>
    <input type="file" multiple id="fileIpt" size="120"/><br/>
    <button onclick="test()">點擊測試</button>
</body>
</html>
<script type="text/javascript">
    function test(){
        var f = document.getElementById("fileIpt");
        var sFileList = "";
        for (var i = 0;i < f.files.length;i++){
            var item = f.files[i];
            sFileList += "文件名稱:" + item.name + "\n修改時間:" + item.lastModifiedDate + "\n文件大小:" + item.size + "\n文件類型:" + item.type + "\n=================\n";
        }
        alert(sFileList);
    }
</script>

  在我做一個圖片上傳項目的時候,曾經有個想法就是想在圖片客戶端這里,也就是在文件傳輸到服務器之前給文件一個預覽功能,當時我沒時間仔細查閱資料,因此自己還是按照HTML4里掌握的知識認為瀏覽器在客戶端是無法操作文件數據的,因此很難實現這個想法。最近看書發現原來HTML5已經可以做到這一點了,我寫了一個例子和大家分享下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>圖片本地顯示</title>
</head>
<body>
    <input type="file" multiple id="fileIpt" size="120"/><br/>
    <button onclick="test()">顯示圖片</button>
    <div id="result"></div>
</body>
</html>
<script type="text/javascript">
    function test(){
        var files = document.getElementById("fileIpt").files;
        for (var i = 0;i < files.length;i++){
            var f = files[i];
            if (f.type.indexOf("image") != -1){
                var reader = new FileReader();
                reader.readAsDataURL(f);
                reader.onload = function(evt){
                   var resDiv =  document.getElementById("result");
                    var oImg = document.createElement("img");
                    oImg.setAttribute("src",this.result);
                    oImg.setAttribute("width",300);
                    oImg.setAttribute("height",300);
                    resDiv.appendChild(oImg);
                }

            }
        }
    }
</script>

  好了,今天文章就寫到這里,對於多文件上傳我之后一定抽時間寫個完整的例子出來,自己上次做項目對這塊做的很是過癮,而今天還發現了可以在客戶端預覽圖片,因此這塊很值得寫個好demo了。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM