您的位置:奥门新浦京网址 > Wed前段 > 数据交互与本地存储,浅谈javascript函数节流

数据交互与本地存储,浅谈javascript函数节流

发布时间:2020-01-03 06:40编辑:Wed前段浏览(122)

    浅谈javascript函数节流

    2016/03/14 · JavaScript · 函数

    原文出处: 涂根华   

    什么是函数节流?

         函数节流简单的来说就是不想让该函数在很短的时间内连续被调用,比如我们最常见的是窗口缩放的时候,经常会执行一些其他的操作函数,比如发一个ajax请求等等事情,那么这时候窗口缩放的时候,有可能连续发多个请求,这并不是我们想要的,或者是说我们常见的鼠标移入移出tab切换效果,有时候连续且移动的很快的时候,会有闪烁的效果,这时候我们就可以使用函数节流来操作。大家都知道,DOM的操作会很消耗或影响性能的,如果是说在窗口缩放的时候,为元素绑定大量的dom操作的话,会引发大量的连续计算,比如在IE下,过多的DOM操作会影响浏览器性能,甚至严重的情况下,会引起浏览器崩溃的发生。这个时候我们就可以使用函数节流来优化代码了~

    函数节流的基本原理:

         使用一个定时器,先延时该函数的执行,比如使用setTomeout()这个函数延迟一段时间后执行函数,如果在该时间段内还触发了其他事件,我们可以使用清除方法 clearTimeout()来清除该定时器,再setTimeout()一个新的定时器延迟一会儿执行。

    我们先来看一个简单的window.resize的demo例子,比如我先定义一个全局变量count=0;当我触发一次window.resize的时候,该全局变量count++; 我们来看看在控制台中打印出count的效果;JS代码如下:

    var count = 0; window.onresize = function(){ count++; console.log(count); }

    1
    2
    3
    4
    5
    var count = 0;
    window.onresize = function(){
        count++;
        console.log(count);
    }

    执行截图效果如下:

    图片 1

    如上resize的代码,简单的缩放一次就打印出多次,这并不是我们想要的效果,这是简单的测试,那如果我们换成ajax请求的话,那么就会缩放一次窗口会连续触发多次ajax请求,下面我们试着使用函数节流的操作试试一下;

    函数节流的第一种方案封装如下:

    function throttleFunc(method,context){ clearTimeout(method.tId); method.tId = setTimeout(function(){ method.call(context); },100); }

    1
    2
    3
    4
    5
    6
    function throttleFunc(method,context){
         clearTimeout(method.tId);
         method.tId = setTimeout(function(){
             method.call(context);
         },100);
    }

    我们再来封装一下窗口缩放的demo

    var count = 0; function myFunc() { count++; console.log(count); } window.onresize = function(){ throttleFunc(myFunc); } function throttleFunc(method,context){ clearTimeout(method.tId); method.tId = setTimeout(function(){ method.call(context); },100); }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    var count = 0;
    function myFunc() {
       count++;
       console.log(count);
    }
    window.onresize = function(){
        throttleFunc(myFunc);
    }
    function throttleFunc(method,context){
         clearTimeout(method.tId);
         method.tId = setTimeout(function(){
             method.call(context);
         },100);
    }

    如上代码,我们再来看看效果,窗口缩放和放大效果会看到,只执行了一次;打印了一次。

    上面的代码使用一个定时器每隔100毫秒执行一次;

    我们也可以使用闭包的方法对上面的函数进行再封装一下;

    函数节流的第二种封装方法如下:

    function throttle(fn, delay){ var timer = null; return function(){ var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function(){ fn.apply(context, args); }, delay); }; };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function throttle(fn, delay){
         var timer = null;
         return function(){
             var context = this,
                 args = arguments;
             clearTimeout(timer);
             timer = setTimeout(function(){
                 fn.apply(context, args);
             }, delay);
         };
    };

    上面第二种方案是使用闭包的方式形成一个私有的作用域来存放定时器timer,第二种方案的timer是通过传参数的形式引入的。

    调用demo代码如下:

    var count = 0; function myFunc() { count++; console.log(count); } var func = throttle(myFunc,100); window.onresize = function(){ func(); } function throttle(fn, delay){ var timer = null; return function(){ var context = this, args = arguments; clearTimeout(timer); timer = setTimeout(function(){ fn.apply(context, args); }, delay); }; };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    var count = 0;
    function myFunc() {
        count++;
        console.log(count);
    }
    var func = throttle(myFunc,100);
    window.onresize = function(){
       func();
    }        
    function throttle(fn, delay){
         var timer = null;
         return function(){
             var context = this,
                 args = arguments;
             clearTimeout(timer);
             timer = setTimeout(function(){
                 fn.apply(context, args);
             }, delay);
         };
    };

    函数节流的基本思想是:就是想让一个函数不要执行的太频繁,减少一些过快的来节流函数,比如当我们改变窗口缩放的时候,浏览器的间隔有可能是16ms,这是浏览器自带的时间间隔,我们无法改变,而我们通过节流的方式可以试着改变一下这个间隔,尽量稍微延长下这个调用时间,因此我们可以封装如下函数:

    函数节流的第三种封装方法

    function throttle3(fn,delay,runDelay){ var timer = null; var t_start; return function(){ var context = this, args = arguments, t_cur = new Date(); timer & clearTimeout(timer); if(!t_start) { t_start = t_cur; } if(t_cur - t_start >= runDelay) { fn.apply(context,args); t_start = t_cur; }else { timer = setTimeout(function(){ fn.apply(context,args); },delay); } } }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    function throttle3(fn,delay,runDelay){
          var timer = null;
          var t_start;
          return function(){
             var context = this,
                 args = arguments,
                 t_cur = new Date();
             timer & clearTimeout(timer);
             if(!t_start) {
                 t_start = t_cur;
             }
             if(t_cur - t_start >= runDelay) {
                  fn.apply(context,args);
                  t_start = t_cur;
             }else {
                  timer = setTimeout(function(){
                      fn.apply(context,args);
                   },delay);
             }
        }
    }

    调用demo如下:

    var count = 0; function myFunc() { count++; console.log(count); } var func = throttle3(myFunc,50,100); window.onresize = function(){ func();} function throttle3(fn,delay,runDelay){ var timer = null; var t_start; return function(){ var context = this, args = arguments, t_cur = new Date(); timer & clearTimeout(timer); if(!t_start) { t_start = t_cur; } if(t_cur - t_start >= runDelay) { fn.apply(context,args); t_start = t_cur; }else { timer = setTimeout(function(){ fn.apply(context,args); },delay); } } }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    var count = 0;
    function myFunc() {
       count++;
       console.log(count);
    }
    var func = throttle3(myFunc,50,100);
    window.onresize = function(){
       func();}
    function throttle3(fn,delay,runDelay){
          var timer = null;
          var t_start;
          return function(){
              var context = this,
                  args = arguments,
                  t_cur = new Date();
              timer & clearTimeout(timer);
              if(!t_start) {
                  t_start = t_cur;
              }
              if(t_cur - t_start >= runDelay) {
                    fn.apply(context,args);
                    t_start = t_cur;
              }else {
                    timer = setTimeout(function(){
                         fn.apply(context,args);
                    },delay);
              }
          }
    }

    上面的第三个函数是封装后的函数,有三个参数,我们可以自己设置触发事件的时间间隔,则意味着,如上代码50ms连续调用函数,后一个调用会把前一个调用的等待处理掉,但每隔100ms会至少执行一次,具体使用哪一种方式只要看自己的权衡,但是我个人觉得第二种封装函数的方式够我们使用的,当然据说第三种方式性能更好~

    1 赞 3 收藏 评论

    图片 2

    5. 渐进增强(progressive enhancement)

    在构建前端结构的时候,应始终将渐进增强作为你的指导原则。首先设计并且构建核心体验,随后再完善那些为高性能浏览器设计的高级特性的相关体验,创建弹性体验。如果你的网页可以在使用低速网络、老旧显示器的很慢的电脑上运行飞快,那么在光纤高配电脑上它只会运行的更快。

    数据交互与本地存储

    2016/01/17 · HTML5, JavaScript · 1 评论 · 存储

    原文出处: 涂根华   

    一:Iframe父页面与子页面之间的调用

    专业词语解释如下:

        Iframe:iframe元素是文档中的文档。

        window对象: 浏览器会在其打开一个HTML文档时创建一个对应的window对象。但是,如果一个文档定义了一个或者多个框架

    (即:包含一个或者多个frame或者iframe标签),浏览器就会为原始文档创建一个window对象,再为每个iframe创建额外的window对象,这些额外的window对象是原始窗口的子窗口。

    contentWindow: 是指指定的iframe或者iframe所在的window对象。

       1. 父页面与子页面之间的调用。

    现在我们可以慢慢做demo来分别讲解下,假如有iframe父页面为 iframe1.html, 父页面上有2个子页面 分别为iframe2.html 和 iframe3.html。

    父页面iframe1.html代码如下:

    XHTML

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="jquery1.7.js"></script> </head> <body> <iframe src="" id = "iframe3"></iframe> <iframe src="" id = "iframe2"></iframe> <div class="iframe1">父页面</div> <script> function test2() { console.log(1); } </script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
        <script src="jquery1.7.js"></script>
    </head>
    <body>
        <iframe src="http://localhost/iframe/iframe3.html" id = "iframe3"></iframe>
        <iframe src="http://localhost/iframe/iframe2.html" id = "iframe2"></iframe>
        <div class="iframe1">父页面</div>
       <script>
        function test2() {
            console.log(1);
        }
       </script>
    </body>
    </html>

    子页面iframe2.html代码如下:

    XHTML

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="jquery1.7.js"></script> </head> <body> <div id="test">aaa</div> <div class="iframe2">子页面</div> <script> function b() { console.log("我是子页面"); } function iframe3Page() { console.log("iframe3页面调用iframe2页面"); } </script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <title>Document</title>
      <script src="jquery1.7.js"></script>
    </head>
    <body>
        <div id="test">aaa</div>
        <div class="iframe2">子页面</div>
           <script>
               function b() {
               console.log("我是子页面");
           }
           function iframe3Page() {
               console.log("iframe3页面调用iframe2页面");
           }
          </script>
    </body>
    </html>

    1.  子页面iframe2.html调用父页面 iframe1.html的元素如下代码:

        console.log($(‘.iframe1’,parent.document));

    2.  子页面iframe2.html调用父页面iframe1.html的函数如下代码:

        parent.test2();

    注意:父页面iframe1.html页面 中test2方法不能放在$(function(){}), 放在里面就调用不到。

    3. 子页面iframe2.html调用自身的iframe(假如父页面有很多iframe,获取自身iframe不通过id或者name属性).

        1.首先我们可以在父页面上写一个函数 用来获取页面所有的iframe,之后进行遍历,进行判断当前的window对象是否相同。如下代码:

    JavaScript

    function getFrame(f){ var frames = document.getElementsByTagName("iframe"); for(i=0;i){ if(frames[i].contentWindow == f){ return(frames[i]) } } }

    1
    2
    3
    4
    5
    6
    7
    8
    function getFrame(f){
        var frames = document.getElementsByTagName("iframe");
        for(i=0;i){
             if(frames[i].contentWindow == f){
                  return(frames[i])
              }
          }
      }

        2. 在子页面iframe2.html中如下调用父页面的方法 getFrame.

    JavaScript

    /* 获取自身的iframe */ var aa = parent.getFrame(this); console.log(aa); $(aa).attr("flag",true);

    1
    2
    3
    4
    /* 获取自身的iframe */
    var aa = parent.getFrame(this);
    console.log(aa);
    $(aa).attr("flag",true);

    给iframe2设置属性 flag: true, 如下截图:

    图片 3

    4. 父页面iframe1.html调用子页面 iframe2.html的元素及函数.

    如下调用有误的:

    console.log(document.getElementById(“iframe2”).contentWindow.b());

    因为iframe2.html 有可能未加载完成,所以要等iframe2加载完成后再进行调用,

    所以我们需要 iframe2.onload = function(){}; 这样再进行调用。为了兼容IE,我们可以如下封装一个方法:

    JavaScript

    function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback & callback(); }); }else { iframe.onload = function(){ callback & callback(); } } } // 调用方式如下: // 父页面调用子页面iframe2的方法 var iframe2 = document.getElementById("iframe2"); iframeIsLoad(iframe2,function(){ iframe2.contentWindow.b(); // 打印出 我是子页面 // 父页面获取子页面iframe2的元素 var iframeDom = $(".iframe2",iframe2.contentWindow.document); console.log(iframeDom); });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    function iframeIsLoad(iframe,callback){
        if(iframe.attachEvent) {  
             iframe.attachEvent('onload',function(){
                 callback & callback();
             });
     
        }else {
             iframe.onload = function(){
                  callback & callback();
             }
        }
    }
    // 调用方式如下:
    // 父页面调用子页面iframe2的方法
    var iframe2 = document.getElementById("iframe2");
    iframeIsLoad(iframe2,function(){
        iframe2.contentWindow.b(); // 打印出 我是子页面  
        // 父页面获取子页面iframe2的元素
        var iframeDom = $(".iframe2",iframe2.contentWindow.document);
        console.log(iframeDom);
     
    });

    二:理解JSONP跨域技术的基本原理

    Javascript是一种在web开发中经常使用的前端动态脚本技术,在javascript中,有一个很重要的安全限制,被称为”same-Origin-Policy”同源策略,这一策略对于javascript代码能够访问的页面内容作了很重要的限制,即javascript只能访问与包含它的文档在同协议,同域名,同端口的脚本进行交互;

    JSONP的基本原理是:利用在页面中创建节点的方法向不同域提交http请求的方法称为JSONP。

    JSONP的具体实现方法如下:

    首先我们为了演示跨域,我们在host文件夹下绑定如下2个域名如下:

       127.0.0.1  abc.example1.com

       127.0.0.1  def.example2.com

    其中在abc.example1.com域名下有一个a.html页面;访问页面路径如下:

       

    1. 我们在域名下abc.example1.com下的a.html页面引入一个域名为def.example2.com下的a.js文件;如下:

      然后在a.js代码变为如下:

    JavaScript

       function jsonp(){         alert(1)    }   jsonp();

    1
    2
    3
    4
       function jsonp(){
            alert(1)
       }
      jsonp();

    最后我们在域名下abc.example1.com下的a.html页面运行下可以看到弹出对话框 “1”;我们可以看到引入不同域名下的js文件也能跨域执行;

    2. 如果我在域名为def.example2.com下的a.js文件能否调用a.html的方法名呢?我们继续来演示这个demo;我们在abc.example1.com下的a.html引入文件如下:

    JavaScript

    function jsonp(){     alert(1) }

    1
    2
    3
    4
    5
    function jsonp(){
     
        alert(1)
     
    }

    其中域名为def.example2.com下的a.js内容为:jsonp(); 我们继续来运行下页面,可以看到,还是可以弹出对话框 1;

    3.  如果我在外面的调用方法能否传递一个参数呢?我们继续和第二点一样,只是方法里面多了一个参数传进去即可:如下代码:

    def.example2.com下的a.js内容为:jsonp(“我是来测试的”);abc.example1.com下的a.html文件内容为:

    JavaScript

     function jsonp(html){        alert(html)   }

    1
    2
    3
     function jsonp(html){
           alert(html)
      }

    我们运行下页面a.html,也可以看到弹出了对话框 “我是来测试的”文案;所以,我们就可以通过这种方法来给页面中传入外站的数据;可以实现JSONP的跨域数据;

    理解JSONP执行过程如下:

        首先在客户端注册一个callback(比如jsonpcallback),然后把callback名字(比如叫jsonp123456)传给服务器端,服务器端得到callback名字后,需要用jsonp123456(),把将要输出的json内容包括起来,此时,服务器生成的json数据才能被客户端正确接收;然后以javascript语法的方式,生成一个function,function的名字就是传递回来的参数jsonp123456.然后就可以在客户端直接运行调用jsonp123456这个函数了;

    演示代码如下:

    在域名下abc.example1.com下的a.html页面代码如下:

    动态创建script标签,给script动态设置src值为域名def.example2.com,这样就实现在不同的域名下了;

    如下代码:

    JavaScript

    <script> function jsonp123456(data){ alert(data.name); // tugenhua alert(data.age); // 28 alert(data.single); // yes } var eleScript= document.createElement("script"); eleScript.type = "text/javascript"; eleScript.src = ""; document.getElementsByTagName("HEAD")[0].appendChild(eleScript); </script> //在def.example2.com域名下的a.js代码如下: jsonp123456({"name":'tugenhua','age':'28','single':'yes'});

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <script>
        function jsonp123456(data){
            alert(data.name); // tugenhua
            alert(data.age);  // 28
            alert(data.single); // yes
        }
        var eleScript= document.createElement("script");
        eleScript.type = "text/javascript";
        eleScript.src = "http://def.example2.com/iframe/a.js?jsonpcallback=jsonp123456";
        document.getElementsByTagName("HEAD")[0].appendChild(eleScript);
    </script>
    //在def.example2.com域名下的a.js代码如下:
    jsonp123456({"name":'tugenhua','age':'28','single':'yes'});

    分析: 在a.html下给服务器端发送请求,并且给服务器端传递参数 jsonpcallback=jsonp123456;服务器端拿到jsonpcallback这个参数后;需要用jsonp123456(),把将要输出的json内容包括起来,此时,服务器生成的json数据才能被客户端正确接收;然后以javascript语法的方式,生成一个function,function的名字就是传递回来的参数jsonp123456.然后就可以在客户端直接运行调用jsonp123456这个函数了;

    如上演示的代码; 之后分别弹出data.name;data.age;及data.single;

    JSONP的优点:

    它不像XMLHttpRequest对象实现ajax请求受到同源策略的限制,它在所有的浏览器都支持,

    比如古老的IE6也支持,并且在请求完成后可以通过callback的方式传回结果;

    JSONP的缺点:

    1. 只支持get请求,不支持post请求,它只支持http跨域的请求情况,

    不能解决不同域的两个页面之间如何进行javascript调用的问题; 

    1. 由于它是get请求,传递的参数都拼在url后面,因此数据安全性不高;

    三:iframe之间通信问题

    1. iframe通信 分为:同域通信 和 跨域通信。所谓同域通信是指   下的a.html页面嵌套 iframe 比如: 的B.html页面,这两个页面数据进行通信,比如我想在父页面A.html 调用子页面当中的函数 我们很容易想到或者google下 ;document.getElementById(‘iframeA’).contentWindow.b(); 这种方法,其中b 是子页面B.html中的一个函数。但是这样调用下有个问题我纠结了很久,就是既然在火狐下报这样的错误, 如下图所示:

    图片 4

    b不是个函数 但是我在子页面明明定义了这么一个函数,那么为什么会报这样的错误呢?经过仔细分析及google,发现有这么一个问题需要理解,当iframe没有加载完成后 我就去执行这个js会报这样的错误,所以就试着在火狐下 用iframe.onload 这个函数 进行测试,果然没有报错,是正确的 所以就确定是这个问题。所以就想写个兼容IE和火狐 google写个函数 来确定iframe已经加载完成!,其实给个回调函数来调用我们上面的方法。

    综合上面的思路 A.html 就可以写个这样的代码:

    JavaScript

    <iframe src="" id="iframeA" name="iframeA"></iframe> <div id="topName">topNddddddddddddddddame</div> <script> function A(){ alert("A"); } var iframe = document.getElementById('iframeA'); iframeIsLoad(iframe,function(){ var obj = document.getElementById('iframeA').contentWindow; obj.b(); }); function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback && callback(); }); }else { iframe.onload = function(){ callback && callback(); } } } </script> B.html 代码如下: var b = function(){ alert("B"); };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    <iframe src="http://localhost/demo/iframe/iframeB.html" id="iframeA" name="iframeA"></iframe>
    <div id="topName">topNddddddddddddddddame</div>
    <script>
        function A(){
            alert("A");
        }
        var iframe = document.getElementById('iframeA');
        iframeIsLoad(iframe,function(){
            var obj = document.getElementById('iframeA').contentWindow;
            obj.b();
        });
         function iframeIsLoad(iframe,callback){
            if(iframe.attachEvent) {
                iframe.attachEvent('onload',function(){
                    callback && callback();
                });
            }else {
                iframe.onload = function(){
                    callback && callback();
                }
            }
         }
    </script>
    B.html 代码如下:
    var b = function(){
        alert("B");
    };

    2.子页面调用父页面的函数很简单,只要这样搞下就ok了,window.parent.A();

    3. 子页面取父页面元素的值: window.parent.document.getElementById(“topName”).innerHTML等方法。

    二: iframe跨域通信。

    iframe跨域访问一般分为2种情况,第一种是同主域,不同子域的跨域。 第二种是:不同主域跨域。

    一、 是同主域下面,不同子域之间的跨域;可以通过document.domain 来设置相同的主域来解决。

    假如现在我有个域 abc.example.com 下有个页面叫abc.html, 页面上嵌套了一个iframe 如下:

    XHTML

    <iframe src="" id="iframe2" style="display:none;"></iframe>,

    1
    <iframe src="http://def.example.com/demo/def.html"  id="iframe2" style="display:none;"></iframe>,

    我想在abc域下的页面abc.html 访问 def域下的def.html  我们都知道由于安全性 游览器的同源策略的限制,js不能操作页面不同域下 不同协议下 不同端口的页面,所以就要解决跨域访问了,假如父页面abc.html 页面有个js函数:

     function test(){console.log(1);};

     我想在子页面调用这个函数 还是按照上面的同域方式调用 parent.test();这样,通过在火狐下看 已经跨域了 解决的办法是 在各个js函数顶部 加一句 document.domain = ‘example.com’,就可以解决了。

     abc.html代码如下:

    XHTML

    <iframe src="" id="iframe2" style="display:none;"></iframe> // 跨域 子页调用父页的 函数 (假设是下面test函数) document.domain = 'example.com'; function test(){console.log(1);};

    1
    2
    3
    4
    <iframe src="http://def.example.com/demo/def.html"  id="iframe2" style="display:none;"></iframe>
      // 跨域 子页调用父页的 函数 (假设是下面test函数)
      document.domain = 'example.com';
      function test(){console.log(1);};

    def.html代码如下:

    JavaScript

    /* * 子页调用父页的方法 */ document.domain = 'example.com'; //window.top.test(); window.parent.test();

    1
    2
    3
    4
    5
    6
    /*
    * 子页调用父页的方法
    */
    document.domain = 'example.com';
    //window.top.test();
    window.parent.test();

    还是这两个页面 我想父页调用子页 如下方法:

    a.html代码如下:

    JavaScript

    /* * 跨域 父页想调用子页的的函数 */ document.domain = 'example.com'; var iframe = document.getElementById('iframe2'); iframeIsLoad(iframe,function(){ var obj = iframe.contentWindow; obj.child(); }); function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback & callback(); }); }else { iframe.onload = function(){ callback & callback(); } } }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /*
    * 跨域 父页想调用子页的的函数
    */
    document.domain = 'example.com';
    var iframe = document.getElementById('iframe2');
    iframeIsLoad(iframe,function(){
        var obj = iframe.contentWindow;
             obj.child();
    });
    function iframeIsLoad(iframe,callback){
            if(iframe.attachEvent) {
                iframe.attachEvent('onload',function(){
                    callback & callback();
                });
            }else {
                iframe.onload = function(){
                    callback & callback();
                }
            }
    }

    假如现在def.html页面有个child函数 代码如下:

    JavaScript

    document.domain = 'example.com'; function child(){console.log('我是子页');}

    1
    2
    document.domain = 'example.com';
    function child(){console.log('我是子页');}

    就可以跨域调用了 不管是子页面调用父页面 还是父页面调用子页面。一切ok!

    三:是不同主域跨域;

    虽然google有几种方法关于不同主域上的跨域问题 有通过location.hash方法或者window.name方法或者html5及flash等等,

    但是我觉得下面iframe这种方法值得学习下,如下图所示:

    图片 5

    域a.com的页面request.html(即

    思路:要实现a.com域下的request.html页面请求域b.com下的process.php,可以将请求参数通过url传给response.html,由response.html向process.php发起真正的ajax请求(response.html与process.php都属于域b.com),然后将返回的结果通过url传给proxy.html,最后由于proxy.html和request.html是在同个域下,所以可以在proxy.html利用window.top 将结果返回在request.html完成真正的跨域。

    ok, 先看看页面结构

    a.com域下有:

     request.html  proxy.html

    1
    2
     request.html
     proxy.html

    b.com域下有:

    response.html Process.php

    1
    2
    3
    response.html
     
    Process.php

    先来看看request.html页面如下:

    XHTML

    <!DOCTYPE HTML> <html> <head> <title> New Document </title> </head> <body> <p id="result">这里将会填上响应的结果</p> <a id="sendBtn" href="javascript:void(0)">点击,发送跨域请求</a> <iframe id="serverIf" style="display:none"></iframe> <script> document.getElementById('sendBtn').onclick = function() { var url = '', fn = 'GetPerson', //这是定义在response.html的方法 reqdata = '{"id" : 24}', //这是请求的参数 callback = "CallBack"; //这是请求全过程完成后执行的回调函数,执行最后的动作 CrossRequest(url, fn, reqdata, callback); //发送请求 } function CrossRequest(url,fn,reqdata,callback) { var server = document.getElementById('serverIf'); server.src = url + '?fn=' +encodeURIComponent(fn) + "&data=" +encodeURIComponent(reqdata) + "&callback="+encodeURIComponent(callback); } //回调函数 function CallBack(data) { var str = "My name is " + data.name + ". I am a " + data.sex + ". I am " + data.age + " years old."; document.getElementById("result").innerHTML = str; } </script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    <!DOCTYPE HTML>
    <html>
    <head>
      <title> New Document </title>
    </head>
    <body>
        <p id="result">这里将会填上响应的结果</p>
        <a id="sendBtn" href="javascript:void(0)">点击,发送跨域请求</a>
        <iframe id="serverIf" style="display:none"></iframe>
     
        <script>
            document.getElementById('sendBtn').onclick = function() {
                var url = 'http://b.com/demo/ajax/ajaxproxy/reponse.html',
                    fn = 'GetPerson',          //这是定义在response.html的方法
                    reqdata = '{"id" : 24}',   //这是请求的参数
                    callback = "CallBack";     //这是请求全过程完成后执行的回调函数,执行最后的动作
     
                CrossRequest(url, fn, reqdata, callback);  //发送请求
            }
     
            function CrossRequest(url,fn,reqdata,callback) {
                var server = document.getElementById('serverIf');
                server.src = url + '?fn=' +encodeURIComponent(fn) + "&data=" +encodeURIComponent(reqdata) + "&callback="+encodeURIComponent(callback);
            }
            //回调函数
            function CallBack(data) {
                var str = "My name is " + data.name + ". I am a " + data.sex + ". I am " + data.age + " years old.";
                 document.getElementById("result").innerHTML = str;
            }
        </script>
    </body>
    </html>

    这个页面其实就是要告诉response.html:我要让你执行你定义好的方法GetPerson,并且要用我给你的参数'{“id” : 24}’。

    response.html纯粹是负责将CallBack这个方法名传递给下一位仁兄proxy.html,而proxy.html拿到了CallBack这个方法名就可以执行了,

    因为proxy.html和request.html是同域的。

    response.html代码如下:

    XHTML

    <!DOCTYPE HTML> <html> <head> <title> New Document </title> </head> <body> <iframe id="proxy"></iframe> <script> // 通用方法 ajax请求 function _request (reqdata,url,callback) { var xmlhttp; if(window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); }else { xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } xmlhttp.onreadystatechange = function(){ if(xmlhttp.readyState == 4 && xmlhttp.status == 200) { var data = xmlhttp.responseText; callback(data); } } xmlhttp.open('POST',url); xmlhttp.setRequestHeader("Content-Type", "application/json; charset=utf-8"); xmlhttp.send(reqdata); } // 通用方法 获取url参数 function _getQuery(key) { var query = location.href.split('?')[1], value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]); return value; } //向process.php发送ajax请求 function GetPerson(reqdata,callback) { var url = ''; var fn = function(data) { var proxy = document.getElementById('proxy'); proxy.src = "" + encodeURIComponent(data) + "&callback=" + encodeURIComponent(callback); }; _request(reqdata, url, fn); } (function(){ var fn = _getQuery('fn'), reqdata = _getQuery("data"), callback = _getQuery("callback"); eval(fn + "('" + reqdata +"', '" + callback + "')"); })(); </script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    <!DOCTYPE HTML>
    <html>
    <head>
      <title> New Document </title>
    </head>
    <body>
         <iframe id="proxy"></iframe>
        <script>
            // 通用方法 ajax请求
            function _request (reqdata,url,callback) {
                var xmlhttp;
                if(window.XMLHttpRequest) {
                    xmlhttp = new XMLHttpRequest();
                }else {
                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
                }
     
                xmlhttp.onreadystatechange = function(){
                    if(xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                        var data = xmlhttp.responseText;
                        callback(data);
                    }
                }
                xmlhttp.open('POST',url);
                xmlhttp.setRequestHeader("Content-Type", "application/json; charset=utf-8");
                xmlhttp.send(reqdata);
            }
     
            // 通用方法 获取url参数
            function _getQuery(key) {
                var query = location.href.split('?')[1],
                    value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]);
                return value;
            }
     
            //向process.php发送ajax请求
            function GetPerson(reqdata,callback) {
                var url = 'http://b.com/demo/ajax/ajaxproxy/process.php';
                var fn = function(data) {
                    var proxy = document.getElementById('proxy');
                    proxy.src = "http://a.com/demo/ajax/ajaxproxy/Proxy.html?data=" + encodeURIComponent(data) + "&callback=" + encodeURIComponent(callback);
                };
                _request(reqdata, url, fn);
            }
     
            (function(){
                var fn = _getQuery('fn'),
                    reqdata = _getQuery("data"),
                    callback = _getQuery("callback");
               eval(fn + "('" + reqdata +"', '" + callback + "')");
            })();
        </script>
    </body>
    </html>

    这里其实就是接收来自request.html的请求得到请求参数和方法后向服务器process.php发出真正的ajax请求,然后将从服务器返回的数据以及从request.html传过来的回调函数名传递给proxy.html。 

    接下来看看php代码如下,其实就是想返回一个json数据:

    PHP

    <?php $data = json_decode(file_get_contents("php://input")); header("Content-Type: application/json; charset=utf-8"); echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}'); ?>

    1
    2
    3
    4
    5
    <?php
        $data = json_decode(file_get_contents("php://input"));
        header("Content-Type: application/json; charset=utf-8");
        echo ('{"id" : ' . $data->id . ', "age" : 24, "sex" : "boy", "name" : "huangxueming"}');
    ?>

    最后就是proxy.html代码:

    XHTML

    <!DOCTYPE HTML> <html> <head> <title> New Document </title> </head> <body> <script> function _getUrl(key) {//通用方法,获取URL参数 var query = location.href.split("?")[1], value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]); return value; } (function() { var callback = _getUrl("callback"), data = _getUrl("data"); eval("window.top." + decodeURIComponent(callback) + "(" + decodeURIComponent(data) + ")"); })(); </script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <!DOCTYPE HTML>
    <html>
    <head>
      <title> New Document </title>
    </head>
    <body>
        <script>
             function _getUrl(key) {//通用方法,获取URL参数
                           var query = location.href.split("?")[1],
                    value = decodeURIComponent(query.split(key + "=")[1].split("&")[0]);
                        return value;
                   }
             (function() {
                 var callback = _getUrl("callback"),
                     data = _getUrl("data");
                 eval("window.top." + decodeURIComponent(callback) + "(" + decodeURIComponent(data) + ")");
             })();
        </script>
    </body>
    </html>

    这里也是最后一步了,proxy终于拿到了request.html透过response.html传过来的回调函数名以及从response.html直接传过来的响应数据,

    利用window.top执行request.html里定义的回调函数。

    四:iframe高度自适应的问题。

      iframe高度自适应分为2种,一种是同域下自适应  另外一种是跨域下自适应,下面我们来看看同域下iframe高度自适应的问题。

       1. 同域下iframe高度自适应的问题:

         思路:获取被嵌套iframe元素,通过JavaScript取得被嵌套页面最终高度,然后在主页面进行设置来实现。

         假如我们demo有iframe1.html和iframe2.html 下面贴上iframe1.html代码如下:

    XHTML

    <!DOCTYPE HTML> <html> <head> <title> New Document </title> <style> *{margin:0;padding:0;} </style> </head> <body> <iframe src="" style="width:100%;border:1px solid #333;" frameborder="0" id="iframe"></iframe> <script> window.onload = function() { var iframeid = document.getElementById('iframe'); if(iframeid && !window.opera) { if(iframeid.contentDocument && iframeid.contentDocument.body.offsetHeight) { iframeid.height = iframeid.contentDocument.body.offsetHeight; }else if(iframeid.Document && iframeid.Document.body.scrollHeight){ iframeid.height = iframeid.Document.body.scrollHeight; } } } </script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <!DOCTYPE HTML>
    <html>
    <head>
      <title> New Document </title>
      <style>
        *{margin:0;padding:0;}
      </style>
    </head>
     
    <body>
        <iframe src="http://a.com/demo/ajax/iframeheight/iframe2.html" style="width:100%;border:1px solid #333;" frameborder="0" id="iframe"></iframe>
     
        <script>
            window.onload = function() {
                var iframeid = document.getElementById('iframe');
                if(iframeid && !window.opera) {
                    if(iframeid.contentDocument && iframeid.contentDocument.body.offsetHeight) {
                        iframeid.height = iframeid.contentDocument.body.offsetHeight;
                    }else if(iframeid.Document && iframeid.Document.body.scrollHeight){
                        iframeid.height = iframeid.Document.body.scrollHeight;
                    }
                }
            }
        </script>
    </body>
    </html>

    iframe2.html代码如下:

    XHTML

    <!DOCTYPE HTML> <html> <head> <title> New Document </title> <style> *{margin:0;padding:0;} </style> </head> <body> <div style="height:500px;"></div> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <!DOCTYPE HTML>
    <html>
    <head>
      <title> New Document </title>
      <style>
        *{margin:0;padding:0;}
      </style>
    </head>
     
    <body>
        <div style="height:500px;"></div>
    </body>
    </html>

    就可以动态设置iframe1页面的高度为iframe2的高度了。

    2. 跨域下iframe高度自适应的问题。

    首先我们知道iframe跨域我们是不能用上面js方式来控制了,所以我们只能用个中间键,我们可以在a.com域下iframe1.html页面嵌套一个b.com域下的iframe2.html页面,然后我在iframe2.html页面嵌套个和iframe1.html相同域的iframe3.html页面了,这样的话 iframe1.html和iframe3.html就可以无障碍的进行通信了,因为页面iframe2.html嵌套iframe3.html,所以iframe2.html可以改写iframe3.html的href值。

     iframe1中的内容:

     iframe1.html内容主要接受iframe3.html页面传过来的内容并且去完成相应的操作。iframe1.html代码如下:

    XHTML

    <iframe src="" style="width:400px;height:200px;" id="iframe"></iframe> <script> var ifr_el = document.getElementById("iframe"); function getIfrData(data){ ifr_el.style.height = data+"px"; } </script>

    1
    2
    3
    4
    5
    6
    7
    <iframe src="http://b.com/demo/ajax/iframeheight/iframe2.html" style="width:400px;height:200px;" id="iframe"></iframe>
    <script>
       var ifr_el = document.getElementById("iframe");
       function getIfrData(data){
        ifr_el.style.height = data+"px";
       }
    </script>

    iframe2.html中的内容:

    iframe2.html内容是怎么把值传给iframe3.html页面,刚才说了是将值传递到iframe3.html页面的href中,所以只要修改iframe的src就可以,因为不用刷新C页面,所以可以用过hash的方式传递给iframe3.html页面.iframe2.html代码如下:

    JavaScript

    <!DOCTYPE HTML> <html> <head> <title> New Document </title> <style> *{margin:0;padding:0;} </style> </head> <body> <iframe id="iframe" src="" width="0" height="230px"></iframe> <script> var oldHeight = 0, ifr_el = document.getElementById("iframe"); t && clearInterval(t); var t = setInterval(function(){ var height = document.body.scrollHeight; if(oldHeight != height) { oldHeight = height; ifr_el.src += '#' +oldHeight; } },200); </script> </body> </html>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <!DOCTYPE HTML>
    <html>
    <head>
      <title> New Document </title>
      <style>
        *{margin:0;padding:0;}
      </style>
    </head>
    <body>
        <iframe id="iframe" src="http://a.com/demo/ajax/iframeheight/iframe3.html" width="0" height="230px"></iframe>
        <script>
            var oldHeight = 0,
                  ifr_el = document.getElementById("iframe");
     
            t && clearInterval(t);
            var t = setInterval(function(){
                var height = document.body.scrollHeight;
                if(oldHeight != height) {
                    oldHeight = height;
                    ifr_el.src += '#' +oldHeight;
                }
            },200);
        </script>
    </body>
    </html>

    可以看到 默认情况下 iframe1.html 页面我给iframe2.html的高度是200像素, 但是在iframe2.html我给iframe3.html高度是230像素,那么正常情况下是有滚动条的,那么现在我是想在iframe2.html获取滚动条的高度,把高度传给通过iframe3.html的src里面去,然后在iframe3.html页面里获取这个高度值 传给iframe1.html(因为iframe1.html和iframe3.html是同域的),所以iframe1.html能取到这个高度值,再设置下本身的高度就是这个值就ok了。iframe3.html页面的唯一功能就是接收iframe2.html页面通过href传进来的值并且传递给iframe1.html页面,可到iframe2.html页面传来的值可以通过一个定时器不停去查看location.href是 否被改变,但是这样感觉效率很低,还有个方式就是在新的浏览器中通过onhashchange事件 (IE8+,Chrome5.0+,Firefox3.6+,Safari5.0+,Opera10.6+)来监听href的改变。

    iframe3.html代码如下:

    JavaScript

    <script> var oldHeight = 0; t && clearInterval(t); var t = setInterval(function(){ var height = location.href.split('#')[1]; if(height && height != oldHeight) { oldHeight = height; if(window.parent.parent.getIfrData) { window.parent.parent.getIfrData(oldHeight); } } },200); </script>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <script>
        var oldHeight = 0;
        t && clearInterval(t);
        var t = setInterval(function(){
            var height = location.href.split('#')[1];
            if(height && height != oldHeight) {
                oldHeight = height;
                if(window.parent.parent.getIfrData) {
                    window.parent.parent.getIfrData(oldHeight);
                }
            }
        },200);
    </script>

    这样就可以解决通过跨域实现iframe自适应高度的问题了。

    五:本地存储cookie,sessionStorage, localStorage比较及使用

    一:Cookie

    1. 什么是cookie?

         Cookie是在客户端用于存储会话信息的,用户请求页面在web服务器与浏览器之间传递。每当同一台计算机通过浏览器请求某个页面时,就会发送这个 cookie。

     2. cookie的限制?

         1. Cookie的数据大小限制只能为4kb数据,如果数据长度超过4kb数据,超过后的数据将返回空字符串。

         2. Cookie是以文件形式存储在客户端计算机中,查看和修改cookie很方便,但是安全性方面不好,因此重要的数据不要使用cookie来存储。

         3. Cookie是有 有效期概念的,如果想要cookie存储多长时间,可以设置cookie的时间,一般的情况下,cookie的生命周期是在游览器关闭的时候失效。

         4. Cookie是有域的概念的,在不同的域下,cookie不能互相使用,cookie对于那个域是有效的,所有向该域发送的请求中都会包含这个cookie 的信息的,

        这个值可以包含子域(subdomain 如www.zuixiandao.cn) ,也可以不包含它(如.zuixiandao.cn, 对于所有的zuixiandao.cn的所有子域都有效). 

        如果没有明确的指定,那么这个域会被认作来自设置cookie的那个域。

         5. Cookie路径的概念:对于指定域中的那个路径,应该向服务器发送cookie,比如我们可以指定cookie只有从

         6. Cookie失效时间的概念:表示cookie何时应该被删除,默认情况下,浏览器会话结束时即将删除所有的cookie,不过也可以自己设置

     删除时间的。这个值是个GMT格式的日期(Wdy DD-Mon-YYYY HH:MM:SS GMT),用于指定应该删除cookie的准确时间,因此,

     cookie可在浏览器关闭后依然保存在用户的机器上(同一个浏览器,不同的浏览器不能保存),如果设置的日期是过期的日期,那么cookie立刻删掉。

          7. Cookie安全标志 指定后,cookie只有在使用SSL连接的时候才发送到服务器。比如:cookie信息只能发送给, 

      而

    二: javascript中的cookie

     1. Javascript中的cookie是 一系列由分号隔开的名-值对,如下面的淘宝的cookie,如下:

    document.cookie = “isg=E5AA5F2CEE8AA93BB351D1601F7B218E; thw=cn; _med=dw:1920&dh:1080&pw:1920&ph:1080&ist:0; v=0; t=1292efa78d867ff6275e6c5cb971bed7”;

         2. 设置cookie的超时。

             expires;   // 设置cookie的过期的时间

             以下设置 cookie 在 365天后超时;

             var date = new Date();

             date.setTime(date.getTime()+365*24*3600*1000);

             document.cookie = ‘key:value;expires =’ + date.toGMTString();

    下面是设置cookie, 删除cookie,及 获取cookie的封装代码如下:

    JavaScript

    // 获取所有的cookies function getCookies() { var allCookies = document.cookie; return decodeURIComponent(allCookies); } // 获取指定的cookie function getOneCookie(name) { var allCookies = document.cookie.split(";"); for(var i = 0, ilen = allCookies.length; i < ilen; i++) { var temp = allCookies[i].split("="); if($.trim(decodeURIComponent(temp[0])) == name) { return decodeURIComponent(temp[1]); } } return -1; } // 添加cookie 有效期是一年 function addCookie(name,value,expires,path,domain,secure) { var curCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value); if(expires instanceof Date) { curCookie += ';expires =' + expires.toGMTString(); }else { var date = new Date(); date.setTime(date.getTime()+365*24*3600*1000); curCookie += ';expires =' + date.toGMTString(); } if(path) { curCookie += "; path=" + path; } if(domain) { curCookie += "; domain=" +domain; } if(secure) { curCookie += "; secure"; } document.cookie = curCookie; } // 删除cookie function removeCookie(name,path,domain,secure) { addCookie(name,"",new Date(0),path,domain,secure); }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    // 获取所有的cookies
    function getCookies() {
        var allCookies = document.cookie;
        return decodeURIComponent(allCookies);
    }
    // 获取指定的cookie
    function getOneCookie(name) {
        var allCookies = document.cookie.split(";");
        for(var i = 0, ilen = allCookies.length; i < ilen; i++) {
            var temp = allCookies[i].split("=");
            if($.trim(decodeURIComponent(temp[0])) == name) {
                return decodeURIComponent(temp[1]);
             }
        }
        return -1;
    }
    // 添加cookie 有效期是一年
    function addCookie(name,value,expires,path,domain,secure) {
        var curCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
        if(expires instanceof Date) {
            curCookie += ';expires =' + expires.toGMTString();
        }else {
            var date = new Date();                
            date.setTime(date.getTime()+365*24*3600*1000);
            curCookie += ';expires =' + date.toGMTString();
        }
        if(path) {
            curCookie += "; path=" + path;
        }
        if(domain) {
            curCookie += "; domain=" +domain;
        }
        if(secure) {
            curCookie += "; secure";
        }
        document.cookie = curCookie;
    }
    // 删除cookie
    function removeCookie(name,path,domain,secure) {
         addCookie(name,"",new Date(0),path,domain,secure);
    }

    下面我们来做一个小需求,比如一个登陆页面,有 有户名,密码,记住密码,及显示cookie和删除cookie按钮。当我点击记住密码的时候,那么当我第重启开页面时候,只要输入用户名,密码会自动填充,当然我们也可以点击删除cookie按钮进行删除,如下代码:

    HTML代码:

    XHTML

    <h2>cookie介绍</h2> <p> <label>用户名:</label> <input type="text" class="userName" id="userName"/> </p> <p> <label>密码:</label> <input type="password" id="password"> </p> <p> <label>记住密码:</label> <input type="checkbox" id="remember"/> </p> <input value="删除" type="button" id="delCookie"> <input type="button" value="显示cookie" id="showpassword">

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    <h2>cookie介绍</h2>
    <p>
         <label>用户名:</label>
         <input type="text" class="userName" id="userName"/>
    </p>
    <p>
         <label>密码:</label>
         <input type="password" id="password">
    </p>
    <p>
         <label>记住密码:</label>
         <input type="checkbox" id="remember"/>
    </p>
    <input value="删除" type="button" id="delCookie">  
    <input type="button" value="显示cookie" id="showpassword">

    JS代码如下:

    JavaScript

    <script> // 获取所有的cookies function getCookies() { var allCookies = document.cookie; return allCookies; } // 获取指定的cookie function getOneCookie(name) { var allCookies = document.cookie.split(";"); for(var i = 0, ilen = allCookies.length; i < ilen; i++) { var temp = allCookies[i].split("="); if(temp[0] == decodeURIComponent(name)) { return decodeURIComponent(temp[1]); } } return -1; } // 添加cookie 有效期是一年 function addCookie(name,value,expires,path,domain,secure) { var curCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value); if(expires instanceof Date) { curCookie += ';expires =' + expires.toGMTString(); }else { var date = new Date(); date.setTime(date.getTime()+365*24*3600*1000); curCookie += ';expires =' + date.toGMTString(); } if(path) { curCookie += "; path=" + path; } if(domain) { curCookie += "; domain=" +domain; } if(secure) { curCookie += "; secure"; } document.cookie = curCookie; } // 删除cookie function removeCookie(name,path,domain,secure) { addCookie(name,"",new Date(0),path,domain,secure); } $("#userName").unbind('blur').bind('blur',function(){ var val = $(this).val(); if(val) { var curCookie = getOneCookie(val); if(curCookie != -1) { $("#password").val(curCookie); } } }); // 记住密码 $("#remember").unbind('click').bind('click',function(){ if(document.getElementById("remember").checked) { if($("#userName").val() && $("#password").val()) { addCookie($("#userName").val(),$("#password").val()); alert("Saved!"); } } }); // 删除cookie $("#delCookie").unbind('click').bind('click',function() { if($("#userName").val()) { removeCookie($("#userName").val()); alert(getCookies()); }else { alert("用户名为空"); } }); // 显示cookie $("#showpassword").unbind('click').bind('click',function(){ if($("#userName").val()) { var curCookie = getOneCookie($("#userName").val()); if(curCookie != -1) { alert(curCookie); }else { alert("没有cookie"); } }else { alert("没有cookie"); } }); </script>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    <script>
            // 获取所有的cookies
            function getCookies() {
                var allCookies = document.cookie;
                return allCookies;
            }
            // 获取指定的cookie
            function getOneCookie(name) {
                var allCookies = document.cookie.split(";");
                for(var i = 0, ilen = allCookies.length; i < ilen; i++) {
                    var temp = allCookies[i].split("=");
                    if(temp[0] == decodeURIComponent(name)) {
                        return decodeURIComponent(temp[1]);
                    }
                }
                return -1;
            }
            // 添加cookie 有效期是一年
            function addCookie(name,value,expires,path,domain,secure) {
                var curCookie = encodeURIComponent(name) + '=' + encodeURIComponent(value);
                if(expires instanceof Date) {
                    curCookie += ';expires =' + expires.toGMTString();
                }else {
                    var date = new Date();
                    date.setTime(date.getTime()+365*24*3600*1000);
                    curCookie += ';expires =' + date.toGMTString();
                }
                if(path) {
                    curCookie += "; path=" + path;
                }
                if(domain) {
                    curCookie += "; domain=" +domain;
                }
                if(secure) {
                    curCookie += "; secure";
                }
                document.cookie = curCookie;
            }
            // 删除cookie
            function removeCookie(name,path,domain,secure) {
                addCookie(name,"",new Date(0),path,domain,secure);
            }
     
            $("#userName").unbind('blur').bind('blur',function(){
                  var val = $(this).val();
                  if(val) {
                     var curCookie = getOneCookie(val);
                     if(curCookie != -1) {
                        $("#password").val(curCookie);
                     }
                  }
            });
            // 记住密码
            $("#remember").unbind('click').bind('click',function(){
                if(document.getElementById("remember").checked) {
                    if($("#userName").val() && $("#password").val()) {
                        addCookie($("#userName").val(),$("#password").val());  
                        alert("Saved!");
                    }
     
                }
            });
            // 删除cookie
            $("#delCookie").unbind('click').bind('click',function() {
                if($("#userName").val()) {
                    removeCookie($("#userName").val());
                    alert(getCookies());
                }else {
                    alert("用户名为空");
                }
            });
     
            // 显示cookie
            $("#showpassword").unbind('click').bind('click',function(){
                if($("#userName").val()) {
                    var curCookie = getOneCookie($("#userName").val());
                    if(curCookie != -1) {
                        alert(curCookie);
                    }else {
                        alert("没有cookie");
                    }
     
                }else {
                    alert("没有cookie");
                }
            });
    </script>

    Cookie的实例demo如下:

    cookie

    三:IE用户数据;

    在IE5.0中,微软通过一个自定义行为引入了持久化用户数据的概念,用户数据允许每个文档最多128kb的数据,每个域名最多1MB的数据,

    要使用持久化数据,首先必须如下所示,使用css在某个元素上指定userData行为:

     

    IE用户数据

     

    针对IE有如下使用方法:

    1. getAttribute(“key”) 获取指定的属性值。

    2. load(object) 从 userData 存储区载入存储的对象数据。

    3. removeAttribute(“key”) 移除对象的指定属性。

    4. save(object) 将对象数据存储到一个 userData 存储区。

    5. setAttribute(“key”,”value”) 设置指定的属性值。

    我们继续做一个demo来演示下在IE浏览器下的存储的demo。

    HTML代码如下:

    XHTML

    <div style="behavior:url(#default#userData)" id="dataStore">IE用户数据</div> <input value="IE下保存数据" type="button" id="IESave"> <input type="button" value="IE下获取数据" id="IEGet"> <input type="button" value="IE下删除数据" id="IERemove">

    1
    2
    3
    4
    <div style="behavior:url(#default#userData)" id="dataStore">IE用户数据</div>
    <input value="IE下保存数据" type="button" id="IESave">
    <input type="button" value="IE下获取数据" id="IEGet">
    <input type="button" value="IE下删除数据" id="IERemove">

    JS代码如下:

    JavaScript

    var dataStore = document.getElementById("dataStore"); $("#IESave").click(function(e){ dataStore.setAttribute("name","tugenhua"); dataStore.setAttribute("book",'111111'); dataStore.save("bookInfo"); }); // IE下获取数据 $("#IEGet").click(function(){ dataStore.load("bookInfo"); alert(dataStore.getAttribute("name")); alert(dataStore.getAttribute("book")); }); // IE下删除数据 $("#IERemove").click(function(){ dataStore.removeAttribute("name"); dataStore.removeAttribute("book"); dataStore.save("bookInfo"); });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    var dataStore = document.getElementById("dataStore");
    $("#IESave").click(function(e){
        dataStore.setAttribute("name","tugenhua");
        dataStore.setAttribute("book",'111111');
        dataStore.save("bookInfo");
    });
    // IE下获取数据
    $("#IEGet").click(function(){
        dataStore.load("bookInfo");
        alert(dataStore.getAttribute("name"));
        alert(dataStore.getAttribute("book"));
    });
     
    // IE下删除数据
    $("#IERemove").click(function(){
        dataStore.removeAttribute("name");
        dataStore.removeAttribute("book");
        dataStore.save("bookInfo");
    });

    IE浏览器下的demo如下:

    使用IE浏览器下查看效果 请点击我!!

    四:sessionStorage 和 localStorage 

    Html5新增了两个本地存储数据,分别是sessionStorage 和 localStorage.

    浏览器支持程度如下:

    图片 6

    注意:IE8 及 以上都支持 web storage。

       sessionStorage: 将数据保存在session对象中,所谓session,指用户浏览某个网站时,从进入网站到浏览器关闭的这段时间,也就是用户浏览这个网站所花费的时间。

           生命周期:指只在当前的窗口有效,打开一个新的同源窗口,或者说重启浏览器都失效。

           数据大小:可以保存5MB甚至更多。

       localStorage: 将数据保存在客户端本地的硬件设备(通常是指硬盘,但也可以是其他硬件设备),即使浏览器被关闭了,该数据依然存在,下次打开浏览器访问网站时仍然可以继续使用。但是,数据保存是按不同的浏览器分别进行的,也就是说,如果打开别的浏览器,是读取不到在这个浏览器中保存的数据的。

         生命周期:数据一直保存在硬盘中。持久性保存(但是不同的浏览器保存的数据,是不能通用的)。

         数据大小:可以保存5MB甚至更多的数据。

        1. cookie 与 sessionStorage 及 localStorage的区别;   

            共同点:都是在客户端存储数据,且是同源的。

        区别:

    存储大小不一样;cookie存储数据最大只能为4kb,而sessionStorage与localStorage可以保存5MB甚至更多数据。

      Cookie数据始终在同源的http请求中携带,即cookie在浏览器与服务器之间来回传递,而sessionStorage与localStorage不会自动发给服务端,仅在本地保存。

    数据有效期不同;sessionStorage仅在当前浏览器窗口未关闭之前有效(同源的新窗口不生效),localStorage仅在当前的浏览器下永久生效(不同的浏览器不能共享数据),不管关闭了 重新打开的 还是生效的。Cookie只在设置的cookie过期时间之前一直有效,即使窗口或者浏览器关闭,或者打开新的同源窗口。

    作用域不同;sessionStorage不在不同的浏览器窗口中共享,即是同一个页面,localStorage在所有的同源窗口中都是共享的(只在相同的浏览器下),cookie在所有的同源窗口都是共享的(仅在同一个浏览器中)。

          SessionStorage与LocalStorage他们都拥有相同的方法;

          1. setItem存储value

             用法:.setItem( key, value),代码如下:

             localStorage.setItem(key,value):将value存储到key字段

          2. getItem获取value

              用法:.getItem(key) 代码如下:

              localStorage.getItem(key):获取指定key本地存储的值

          3. removeItem删除key

              用法:.removeItem(key),代码如下:

              localStorage.removeItem(key):删除指定key本地存储的值

          4. clear清除所有的key/value

              用法:.clear(),代码如下:

              localStorage.clear();  清除所有的数据(firefox除外)

          它将删除所有同源的本地存储的localStorage数据

          而对于Session Storage,它只清空当前会话存储的数据。

          sessionStorage也有上面一样的方法;

    下面我们来使用sessionStorage及 localStorage 来练习下,来做个demo。如下:

    HTML代码如下:

    XHTML

    <h1>web Storage实列</h1> <p id="msg"></p> <input type="text" id="input" /> <input type="button" value="保存数据" id="saveData"/> <input type="button" value="读取数据" id="readData"/> <input type="button" value="删除数据" id="removeData"/> <input type="button" value="清除所有的数据" id="clearData"/>

    1
    2
    3
    4
    5
    6
    7
    <h1>web Storage实列</h1>
    <p id="msg"></p>
    <input type="text" id="input" />
    <input type="button" value="保存数据" id="saveData"/>
    <input type="button" value="读取数据" id="readData"/>
    <input type="button" value="删除数据" id="removeData"/>
    <input type="button" value="清除所有的数据" id="clearData"/>

    页面上一个input输入框,当我点击 保存数据 按钮后 分别使用sessionStorage和localStorage 把值保存起来,当我点击 读取数据 按钮后 读取数据,分别在不同的浏览器或者新的同源窗口 或者关闭浏览器窗口 重新打开新窗口,来分别看看之间的区别,区别上面已经总结了,下面我们来看看JS代码如下:

    JavaScript

    <script> // sessionStorage demo $("#saveData").unbind('click').bind('click',function(){ var inputVal = $("#input").val(); sessionStorage.setItem("message",inputVal); //localStorage.setItem("message",inputVal); }); $("#readData").unbind("click").bind('click',function(){ var msg = sessionStorage.getItem("message"); //var msg = localStorage.getItem("message"); $("#msg").html(msg); }); $("#removeData").unbind('click').bind('click',function(){ sessionStorage.removeItem("message"); //localStorage.removeItem("message"); }); $("#clearData").unbind('click').bind('click',function(){ sessionStorage.clear(); //localStorage.clear(); }); </script>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <script>
            // sessionStorage demo
            $("#saveData").unbind('click').bind('click',function(){
                var inputVal = $("#input").val();
                sessionStorage.setItem("message",inputVal);
                //localStorage.setItem("message",inputVal);
            });
            $("#readData").unbind("click").bind('click',function(){
                var msg = sessionStorage.getItem("message");
                //var msg = localStorage.getItem("message");
                $("#msg").html(msg);
            });
            $("#removeData").unbind('click').bind('click',function(){
                sessionStorage.removeItem("message");
                //localStorage.removeItem("message");
            });
            $("#clearData").unbind('click').bind('click',function(){
                sessionStorage.clear();
                //localStorage.clear();
            });
    </script>

    如上的代码,我们现在继续来看看效果如下:使用

    sessionStorage效果请点击:

    使用localStorage效果请点击:

    我们还可以做一点复杂的应用,比如如下一个表格有一些字段,比如姓名,email,tel,及备注字段,我们先保存到本地去,然后根据姓名这个字段进行搜索就可以搜索到数据到,我们可以称为这是简单的本地数据库,如下代码:

    XHTML

    <table> <tr> <td>姓名:</td> <td> <input type="text" id="name"/> </td> </tr> <tr> <td>EMALL:</td> <td> <input type="text" id="email"/> </td> </tr> <tr> <td>电话号码:</td> <td> <input type="text" id="tel"/> </td> </tr> <tr> <td>备注:</td> <td> <input type="text" id="memo"/> </td> </tr> <tr> <td>保存</td> <td> <input type="button" id="save" value="保存"/> </td> </tr> </table> <p> 检索:<input type="text" id="file"/> <input type="button" id="find" value="检索"/> </p> <p id="msg"></p>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <table>
        <tr>
            <td>姓名:</td>
            <td>
                <input type="text" id="name"/>
            </td>
        </tr>
        <tr>
            <td>EMALL:</td>
            <td>
                <input type="text" id="email"/>
            </td>
        </tr>
        <tr>
            <td>电话号码:</td>
            <td>
                <input type="text" id="tel"/>
            </td>
        </tr>
        <tr>
            <td>备注:</td>
            <td>
                <input type="text" id="memo"/>
            </td>
        </tr>
        <tr>
            <td>保存</td>
            <td>
               <input type="button" id="save" value="保存"/>
            </td>
        </tr>
    </table>
    <p>
         检索:<input type="text" id="file"/>
         <input type="button" id="find" value="检索"/>
    </p>
    <p id="msg"></p>

    JS代码如下:

    JavaScript

    // 保存数据 $("#save").unbind('click').bind('click',function(){ var data = new Object; data.name = $("#name").val(); data.email = $("#email").val(); data.tel = $("#tel").val(); data.memo = $("#memo").val(); var str = JSON.stringify(data); localStorage.setItem(data.name,str); alert("数据已经保存"); }); // 检索数据 $("#find").unbind('click').bind('click',function(){ var find = $("#file").val(); var str = localStorage.getItem(find); var data = JSON.parse(str); var result = "姓名:" + data.name + "</br>"; result += "Email: " + data.email + "</br>"; result += "tel:" + data.tel + "</br>"; result += "备注:" + data.memo + "</br>"; $("#msg").html(result); });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //  保存数据
    $("#save").unbind('click').bind('click',function(){
         var data = new Object;
         data.name = $("#name").val();
         data.email = $("#email").val();
         data.tel = $("#tel").val();
         data.memo = $("#memo").val();
         var str = JSON.stringify(data);
         localStorage.setItem(data.name,str);
         alert("数据已经保存");
    });
     
    // 检索数据
    $("#find").unbind('click').bind('click',function(){
          var find = $("#file").val();
          var str = localStorage.getItem(find);
          var data = JSON.parse(str);
          var result = "姓名:" + data.name + "</br>";
              result += "Email: " + data.email + "</br>";
              result += "tel:" + data.tel + "</br>";
              result += "备注:" + data.memo + "</br>";
          $("#msg").html(result);
      });

    demo如下效果:

    请点击查看:

    六:window.name 实现跨域数据传输。

    Window.name 中的name值在不同的页面(甚至不同的域名)加载后依旧存在,并且数据量可以达到2MB。

    Window.name 数据传输的基本原理:

    同域下:Name在浏览器环境中是一个全局/window对象的属性,且当在ifrmae中加载页面时,name的属性值依旧保持不变。

    比如我们在同域下abc.example.com下 有2个页面 app.html 和 data.html

     App.html页面代码嵌套一个iframe data.html页面,代码如下:

    XHTML

    <iframe src="" id="iframe"/>

    1
    <iframe src="http://abc.example.com/demo/tugenhua0707/storage/data.html" id="iframe"/>

    其中data.html 页面 使用一个window.name = “111”;来保存数据。

       现在我们接下来在app.html页面 如何来调用同域下的data.html下的window.name的数据,首先我们先要获取到这个iframe,然后判断iframe是否加载完,加载完后就获取这个iframe中的window.name, 

    App.html JS的代码如下:

    JavaScript

    function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback & callback(); }); }else { iframe.onload = function(){ callback & callback(); } } } var iframe = document.getElementById("iframe"); // 同域下 iframeIsLoad(iframe,function(){ var data = iframe.contentWindow.name; alert(data); });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function iframeIsLoad(iframe,callback){
        if(iframe.attachEvent) {
             iframe.attachEvent('onload',function(){
              callback & callback();
             });
        }else {
            iframe.onload = function(){
             callback & callback();
            }
        }
    }
    var iframe = document.getElementById("iframe");
    // 同域下
    iframeIsLoad(iframe,function(){
        var data = iframe.contentWindow.name;
            alert(data);
    });

    2. 跨域下:

       现在我们使用hosts文件来绑定2个IP 来演示下跨域的情况,在hosts文件绑定如下:

       127.0.0.1  abc.example.com  和 127.0.0.1 def.example.com

       我们现在在 abc.example.com 新建一个app.html页面 里面还是嵌套一个 def.example.com域下的 data.html页面,代码如下:

       App.html代码如下:

    XHTML

    <iframe src="" id="iframe"/>

    1
    <iframe src="http://def.example.com/demo/tugenhua0707/storage/data.html" id="iframe"/>

    如果我们还是和上面的方式取数据的话 明显报错跨域了,现在我们是使用window.name解决跨域下数据的传输,那么我们可以使用一个同域abc.example.com下的代理页面proxy.html来做处理,通过在def.example.com域下的data.html页面加载一个与abc.example.com同域下的proxy.html页面, 将该目标页面设置iframe的name属性,因为app.html 与 proxy.html是在同一个域下,所以我们可以获取到。

    在app.html页面 JS代码如下:

    JavaScript

    function iframeIsLoad(iframe,callback){ if(iframe.attachEvent) { iframe.attachEvent('onload',function(){ callback & callback(); }); }else { iframe.onload = function(){ callback & callback(); } } } var iframe = document.getElementById("iframe"); var state = 0; // 跨域下 iframeIsLoad(iframe,function(){ if (state === 1) { var data = iframe.contentWindow.name; // 读取数据 alert(data); //弹出111 } else if (state === 0) { state = 1; iframe.contentWindow.location = ""; // 设置的代理文件 } });

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function iframeIsLoad(iframe,callback){
        if(iframe.attachEvent) {
            iframe.attachEvent('onload',function(){
                 callback & callback();
            });
        }else {
            iframe.onload = function(){
                 callback & callback();
             }
         }
    }      
    var iframe = document.getElementById("iframe");
    var state = 0;
    // 跨域下
    iframeIsLoad(iframe,function(){
       if (state === 1) {
            var data = iframe.contentWindow.name;    // 读取数据
            alert(data);    //弹出111
       } else if (state === 0) {
            state = 1;
            iframe.contentWindow.location = "http://abc.example.com/demo/tugenhua0707/storage/proxy.html";    // 设置的代理文件
       }  
    });

    当然如上:我们如果name数据已经拿到了的话,以后不需要的话,我们可以销毁掉,清空等操作。

    七:使用HTML5中postMessage 实现ajax中的POST跨域问题

    浏览器支持程度:IE8+,firefox4+,chrome8+  opera10+

         1. 首先,要想接收从其他的窗口发过来的消息,就必须对窗口对象的message事件进行监听,如下代码:

              window.addEventListener(“message”, function(){},false);

         2. 其次,需要使用window对象的postMessage方法向其他窗口发送消息,该方法定义如下所示:

             otherWindow.postMessage(message, targetOrigin);

    该方法使用2个参数,第一个参数为所发送的消息文本,但也可以是任何javascript对象,第二个参数是接收消息的对象窗口的url地址

    (比如:http:127.0.0.1:8080/) , 但是我们也可以在url地址字符串中使用通配符”*”, 指定全部的域下,但是我们还是建议使用特定的域名下,

    otherWindow为要发送窗口对象的引用。

    Demo演示:

         假如现在我在hosts文件下 ,绑定2 个域名如下:

         127.0.0.1       abc.example.com

         127.0.0.1        longen.example.com

    现在假如在abc.example.com域下有一个abc.html页面,在longen.example.com域下有def.html页面,现在我是希望这2个不同域名下的页面

    能互相通信,abc.html代码如下:

    XHTML

    <form> <p> <label for="message" style="color:red;font-size:24px;">给iframe子窗口发一个信息:</label> <input type="text" name="message" value="send" id="message" /> <input type="submit" value="submit" id="submit"/> </p> </form> <h4>目标iframe传来的信息:</h4> <p id="test">暂无信息</p> <iframe id="iframe" src="" style="display:none"></iframe>

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <form>  
          <p>  
            <label for="message" style="color:red;font-size:24px;">给iframe子窗口发一个信息:</label>  
            <input type="text" name="message" value="send" id="message" />  
            <input type="submit" value="submit" id="submit"/>  
          </p>  
    </form>  
    <h4>目标iframe传来的信息:</h4>  
    <p id="test">暂无信息</p>  
    <iframe id="iframe" src="http://longen.example.com/webSocket/def.html" style="display:none"></iframe>

    JS代码如下:

    JavaScript

    var win = document.getElementById("iframe").contentWindow; document.getElementById("submit").onclick = function(e){ e.preventDefault(); win.postMessage(document.getElementById("message").value,""); } window.addEventListener("message",function(e){ e.preventDefault(); document.getElementById("test").innerHTML = "从" + e.origin + "那里传过来的消息:n" + e.data; },false);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var win = document.getElementById("iframe").contentWindow;    
    document.getElementById("submit").onclick = function(e){
        e.preventDefault();
        win.postMessage(document.getElementById("message").value,"http://longen.example.com");
    }  
     
    window.addEventListener("message",function(e){
         e.preventDefault();
         document.getElementById("test").innerHTML = "从" + e.origin + "那里传过来的消息:n" + e.data;
    },false);

    Def.html代码如下:

    HTML代码:

    XHTML

    <form> <p> <label for="message">给父窗口abc.html发个信息:</label> <input type="text" name="message" value="send" id="message" /> <input type="submit" /> </p> </form> <p id="test2">暂无信息。</p>

    1
    2
    3
    4
    5
    6
    7
    8
    <form>  
          <p>  
            <label for="message">给父窗口abc.html发个信息:</label>  
            <input type="text" name="message" value="send" id="message" />  
            <input type="submit" />  
          </p>  
    </form>  
    <p id="test2">暂无信息。</p>

    JS代码如下:

    JavaScript

    var parentwin = window.parent; window.addEventListener("message",function(e){ document.getElementById("test2").innerHTML = "从父窗口传来的域" +e.origin + ",和内容数据:" + e.data; parentwin.postMessage('HI!你给我发了"'+e.data+'"。',""); },false);

    1
    2
    3
    4
    5
    var parentwin = window.parent;
    window.addEventListener("message",function(e){
           document.getElementById("test2").innerHTML = "从父窗口传来的域" +e.origin + ",和内容数据:" + e.data;  
           parentwin.postMessage('HI!你给我发了"'+e.data+'"。',"http://abc.example.com");
    },false);

    当我点击abc.html页面后,可以看到效果如下,从def.html返回内容了。如下:

    图片 7

    我们需要知道如下几条信息:

    1. 通过对window对象的message事件进行监听,可以接收消息。

    2. 通过访问message事件的origin属性,可以获取消息的发送源。

    3. 通过访问message事件的data属性,可以取得消息内容。

    4. 使用postMessage方法发送消息。

    5. 通过访问message事件的source属性,可以获取消息发送源的窗口对象(准确的说,应该是窗口的代理对象)。

    有了上面的基本知识点,我们可以延伸为实现ajax POST跨域的问题。

    2. 使用postMessage 知识点解决 ajax中POST跨域问题。

     原理:原理也很简单,假如我们的域名abc.example.com下的abc.html页面需要发ajax请求(跨域,域名为longen.example.com)下,那么我们还是先跨页面文档的形式,和上面一样,我们可以现在longen.example.com下 建立一个页面,比如叫def.html. 那么我们现在还是在 abc.html 页面嵌入一个隐藏域iframe src路径指向longen.example.com域下def,html页面。过程还是和跨文档类似,

     只是现在在def.html页面中 在window.onmessage 事件内写ajax请求即可,如下代码:

    abc.example.com下的abc.html页面如下:

    html代码和上面一样,下面是JS代码:

    JavaScript

    var win = document.getElementById("iframe").contentWindow; document.getElementById("submit").onclick = function(e){ e.preventDefault(); win.postMessage(document.getElementById("message").value,""); } window.addEventListener("message",function(e){ e.preventDefault(); alert(typeof e.data) var json = JSON.parse(e.data); console.log(json); alert(json.url) },false);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var win = document.getElementById("iframe").contentWindow;      
    document.getElementById("submit").onclick = function(e){
          e.preventDefault();
          win.postMessage(document.getElementById("message").value,"http://longen.example.com/");
    }    
    window.addEventListener("message",function(e){
        e.preventDefault();
        alert(typeof e.data)
        var json = JSON.parse(e.data);
         console.log(json);
        alert(json.url)
    },false);

    def.html代码如下:

    JS代码如下:

    JavaScript

    //获取跨域数据 window.onmessage = function(e){ $.ajax({ url: '', type:'POST', dataType:'text', //data: {msg:e.data}, success: function(res) { var parentwin = window.parent; parentwin.postMessage(res," } }); };

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //获取跨域数据  
    window.onmessage = function(e){  
         $.ajax({
              url: 'http://longen.example.com/webSocket/test.php',
              type:'POST',
              dataType:'text',
              //data: {msg:e.data},
              success: function(res) {
                   var parentwin = window.parent;  
                   parentwin.postMessage(res,"http://abc.example.com");//跨域发送数据  
              }
          });
    };

    test.php代码如下:

    PHP

    <?php $data=array( url =>1, name =>'2', 'xx-xx'=>"xx" ); echo json_encode($data); ?>

    1
    2
    3
    4
    5
    6
    7
    8
    <?php
        $data=array(  
         url =>1,
          name =>'2',
          'xx-xx'=>"xx"
    );
    echo json_encode($data);
    ?>

    如上实现方式 就可以实现ajax post跨域了。

    1 赞 8 收藏 1 评论

    图片 8

    27. 你是否开始使用IPv6?

    因为我们已经没什么IPv4的地址可用了,而且移动网络大都开始使用IPv6(美国已经有50%的入口采用IPv6),将你的DNS升级到IPv6为以后作打算是个不错的选择。要确保通网络可以支持双栈协议——它需要允许IPv6和IPv4同时运行。毕竟IPv6不只是做为后备计划的。而且研究显示,伴随邻居发现(NDP)和路由优化,使用IPv6的网站要比普通网站快10%到15%。

    13. 减少使用第三方库,加载JavaScript异步操作

    当用户请求页面时,浏览器会抓取HTML同时生成DOM,然后抓取CSS并建立CSS对象模型,最后通过匹配DOM和CSS对象生成渲染树。在需要处理的JavaScript文件被解决之前,浏览器不会开始对页面进行渲染。作为开发者,我们要明确的告诉浏览器不要等待,直接开始渲染。具体方法是使用HTML中的deferasync两个属性。

    事实上,defer更好一些(因为对于IE9及以下用户对于IE9及以下用户,很有可能会中断脚本)。同时,减少第三方库和脚本的使用,尤其是社交网站的分享按键和嵌入(比如地图)。你可以使用静态的社交网站分享按键(例如SSBG的)和指向交互地图的静态链接去代替他们。

    请准备好然后定下目标!

    快速入门

    这份清单综合性很强,几乎介绍了所有的可用的优化方式。那么,如果你只有一个小时进行优化,你应该干什么呢?让我们从中总结10个最有用的来。别忘了在你开始优化前和结束优化后,记录你的结果,包括开始渲染时间以及在3G,有限连接下的速度。

    1. 有线连接下,你的目标是将开始渲染时间降低至1s一下,而3G的目标是保持在3s一下,SpeedIndex值保持在1000一下。为开始渲染时间和交互时间做优化。
    2. 为你主要的模板准备关键CSS文件,将它们放在页面的``中(你可以使用14KB)。
    3. 对于你自己和第三方的脚本文件,尽可能的延迟加载它们——尤其是社交网站按钮,播放器和高消耗的JavaScript文件。
    4. 使用更快的dns-lookuppreconnectprefetchpreloadprerender添加资源提示,从而加快传输速度。
    5. 将字体一类属性作为子集,异步加载(或者使用系统字体代替)。
    6. 优化图片,并考虑在关键页中使用WebP(例如登陆页面)。
    7. 确保HTTP的缓存头和安全头都被正确的设置。
    8. 在服务器上使用Brotli或Zopfli压缩算法。(如果不支持这两个,尝试一下Gzip)
    9. 如果HTTP/2可用,使用HPACK压缩算法,并监听混合内容的警告。如果你在使用LTS,就可以使用OCSP装订。
    10. 如果可能,将类似字体,JavaScript文件以及图片缓存在service worker缓存中——事实上越多越好!

    2 赞 5 收藏 评论

    图片 9

    15. 图片的进一步优化

    当你在编写登陆界面的时候,发现页面上的图片加载的特别快,这时你需要确认一下JPEG格式文件是否已经通过mozJPEG(它可以操作扫描等级从而提高渲染时间)优化和压缩,PNG格式对应Pingo,GIF需要用到Lossy GIF,SVG要使用SVGOMG。对图片不重要的部分进行模糊处理(使用高斯模糊过滤器处理他们),从而减少文件大小,最后你可能还要去彩色化使图片变成黑白,从而减少更多的容量。对于背景图片,使用Photoshop保持0到10%的质量输出是绝对可以接受的。

    如果你还觉得不够,那你可以通过多重背景图片技术来提高图片的感知性能。

    12. HTTP的缓存头使用的合理吗?

    仔细检查一下例如expirescache-controlmax-age以及其他HTTP缓存头是否被正确的使用。一般来说,资源不论在短时间(如果它会被频繁改动)还是不确定的时间内(如果它是静态的)都是可缓存的——你大可在需要的时候在URL中成改版本。

    如果可能,使用为指纹静态资源设计的Cache-control:immutable,从而避免二次验证(2016年12月,只有FireFox在https://处理中支持)。你可以使用,Heroku的primer on HTTP caching headers,Jake Archibald的 ”Caching Best Practices”,还有IIya Grigorik的HTTP caching primer作为指导。

    31. 你的开发流程是否使用Devtools进行了优化?

    选一个调试工具来对每一个按钮进行检查。确保自己明白如何分析渲染性能和控制台输出、明白如何调试JavaScript以及编辑CSS样式。Umar Hansa最近有一个关于使用DevTools调试和测试的分享,主要包括一些不常用的技巧和技术。

    1. 比你最强的竞争对手快20%

    根据一个心理学研究,你的网站最少在速度上比别人快20%,才能让用户感觉到你的网站比别人的更快。这个速度说的不是整个页面的加载时间,而是开始加载渲染的时间,首次有效渲染时间(例如页面需要加载主要内容的时间),或者交互时间(指的是页面或者应用中主要的页面加载完成,并主备好与用户进行交互的时间)。

    在Moto G(或中端三星设备)和Nexus 4(比较主流的设备)上衡量开始渲染时间(用WebPagetest)以及首页有效渲染时间(用Lighthouse),最好是在一个开放的实验室中,使用规范的3G,4G和Wi-Fi链接。

    图片 10
    Lighthouse,一个Google开发的新的性能审查工具

    你可以通过你的分析报告看看你的用户处在哪个阶段,选取其中前90%的用户体验来做测试。接着收集数据,建一个表格,筛去20%的数据并预设一个目标(如:性能预算)。现在你可以将上述两个值进行对比检测。如果你始终维持着你的目标并且通过一点一点改变脚本去加快交互时间,那么上述方法就是合理可行的。

    图片 11
    由Brad Frost创建的性能分析

    和你的同事分享这份清单。首先要确保团队中的每个人都熟悉这份清单。项目中每一个决定都会影响性能,如果前端工程师们都在积极的参与项目概念,UX以及视觉设计的决定,这将会给整个项目带来巨大收益。地图设计的决定违背了性能理念,所以他在这份清单内的顺序有待考虑。

    定义你所需要的环境

    14. 图片是否被正确优化?

    尽可能的使用带有srcsetsizes还有元素的[响应式图片](https://www.smashingmagazine.com/2014/05/responsive-images-done-right-guide-picture-srcset/)。你也可以利用元素的WebP格式,用JPEG格式作为替补(参见Andreas Bovens的code snippet)或是使用内容协商(使用接受头)。Sketch原本就支持WebP,WebP图片可以直接被Photoshop的WebP plugin导出。当然也有很多其他方法。

    图片 12
    响应图片断点生成器可自动处理图片

    你也可以使用客户端提示,现在浏览器也可以做到。在用来生成响应图片的源文件过少时,使用响应图片断点生成器或类似Cloudinary的服务自动的优化图片。在很多案例中,单独使用sresetsizes都带来了很大的收益。在本网站上,我们给文件添加-opt后缀——例如brotli-compression-opt.png;这样团队的每一个人就知道这些带着后最的图片是被优化过的。

    33. 有无建立持续监听?

    在进行快速、无限制的测试时,最好使用一个个人的WebPageTest实例。建立一个能自动预警的性能预算监听。建立自己的用户时间标记从而测量并监测具体商用的数据。使用SpeedCurve对性能的变化进行监控,同时利用New Relic获取WebPageTest没法提供的数据。SpeedTracker,Lighthouse和Calibre都是不错的选择。

    29. service workers是否为超高速缓存和网络提供预设机制?

    没有经过优化的网络可以比用户机器的本地缓存跑得更快。如果你的网站在HTTPS上运行,你可以参考“实用主义者的service workers手册”,然后把静态资源存在service worker的缓存中,把离线预设(甚至离线页面)存在用户机器方便检索,这样比多次进行网络连接更有效。你还可以参考Jake的离线使用手册和免费的Udactiy课程“离线网络应用”。如果浏览器支持,那就再好不过了,预设就能在任何地方代替网络了。

    18. 通过tree-shaking和code-splitting减少净负载

    Tree-shaking是通过保留那些在项目过程中真正需要的代码从而清理你的构建过程的一种方式。你可以用Webpack 2来提出那些没用的住配置文件,用UnCSS或Helium从CSS中取出不需要的样式。同理,也可以考虑学习一下如何编写高效的CSS选择器,以及如何避免膨胀和高费的样式。

    Code-splitting是另一个Webpack特性,它可以根据按需加载的块将你的代码分开。只要你在代码中定义了分离点,Webpack便会处理好相关的输出文件。它基本上能保证你初始下载的内容很小,而且在需求被添加时按需请求代码。

    Rollup所展示的结果要比Browserify配置文件所显示的好得多。所以当我们想使用类似工具的时候,或许应该看看Rollupify,它将ECMAScript2015模块变成了一个更大的CommonJS模块——因为小模块没准有出乎意料的高性能成本,这源自于你对打包工具模块系统的选择。

    本文由奥门新浦京网址发布于Wed前段,转载请注明出处:数据交互与本地存储,浅谈javascript函数节流

    关键词:

上一篇:没有了

下一篇:没有了