zoukankan      html  css  js  c++  java
  • 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 + "
    修改时间:" + item.lastModifiedDate + "
    文件大小:" + item.size + "
    文件类型:" + item.type + "
    =================
    ";
            }
            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了。

  • 相关阅读:
    智器SmartQ T7实体店试用体验
    BI笔记之SSAS库Process的几种方案
    PowerTip of the Day from powershell.com上周汇总(八)
    PowerTip of the Day2010071420100716 summary
    PowerTip of the Day from powershell.com上周汇总(十)
    PowerTip of the Day from powershell.com上周汇总(六)
    重新整理Cellset转Datatable
    自动加密web.config配置节批处理
    与DotNet数据对象结合的自定义数据对象设计 (二) 数据集合与DataTable
    在VS2003中以ClassLibrary工程的方式管理Web工程.
  • 原文地址:https://www.cnblogs.com/sharpxiajun/p/5554530.html
Copyright © 2011-2022 走看看