數據交互與本地存儲
閱讀目錄
- 一:Iframe父頁面與子頁面之間的調用
- 二:理解JSONP跨域技術的基本原理
- 三:iframe之間通信問題
- 四:iframe高度自適應的問題。
- 五:本地存儲cookie,sessionStorage, localStorage比較及使用
- 六:window.name 實現跨域數據傳輸。
- 七:使用HTML5中postMessage 實現ajax中的POST跨域問題
一: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代碼如下:
<!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代碼如下:
<!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對象是否相同。如下代碼:
function getFrame(f){ var frames = document.getElementsByTagName("iframe"); for(i=0;i<frames.length;i++){ if(frames[i].contentWindow == f){ return(frames[i]) } } }
2. 在子頁面iframe2.html中如下調用父頁面的方法 getFrame.
/* 獲取自身的iframe */ var aa = parent.getFrame(this); console.log(aa); $(aa).attr("flag",true);
給iframe2設置屬性 flag: true, 如下截圖:
4. 父頁面iframe1.html調用子頁面 iframe2.html的元素及函數.
如下調用有誤的:
console.log(document.getElementById("iframe2").contentWindow.b());
因為iframe2.html 有可能未加載完成,所以要等iframe2加載完成后再進行調用,
所以我們需要 iframe2.onload = function(){}; 這樣再進行調用。為了兼容IE,我們可以如下封裝一個方法:
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的基本原理是:利用在頁面中創建<script>節點的方法向不同域提交http請求的方法稱為JSONP。
JSONP的具體實現方法如下:
首先我們為了演示跨域,我們在host文件夾下綁定如下2個域名如下:
127.0.0.1 abc.example1.com
127.0.0.1 def.example2.com
其中在abc.example1.com域名下有一個a.html頁面;訪問頁面路徑如下:
http://abc.example1.com/iframe/a.html
1. 我們在域名下abc.example1.com下的a.html頁面引入一個域名為def.example2.com下的a.js文件;如下:
<script type="text/javascript" src="http://def.example2.com/iframe/a.js"></script>
然后在a.js代碼變為如下:
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引入文件如下:
<script>
function jsonp(){
alert(1)
}
</script>
<script type="text/javascript" src="http://def.example2.com/iframe/a.js"></script>
其中域名為def.example2.com下的a.js內容為:jsonp(); 我們繼續來運行下頁面,可以看到,還是可以彈出對話框 1;
3. 如果我在外面的調用方法能否傳遞一個參數呢?我們繼續和第二點一樣,只是方法里面多了一個參數傳進去即可:如下代碼:
def.example2.com下的a.js內容為:jsonp("我是來測試的");abc.example1.com下的a.html文件內容為:
<script>
function jsonp(html){
alert(html)
}
</script>
<script type="text/javascript" src="http://def.example2.com/iframe/a.js"></script>
我們運行下頁面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,這樣就實現在不同的域名下了;
如下代碼:
<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調用的問題;
2. 由於它是get請求,傳遞的參數都拼在url后面,因此數據安全性不高;
三:iframe之間通信問題
1. iframe通信 分為:同域通信 和 跨域通信。所謂同域通信是指 http://localhost/demo/iframe/iframeA.html 下的a.html頁面嵌套 iframe 比如: <iframe src="http://localhost/demo/iframe/iframeB.html" id="iframeA" name="iframeA">的B.html頁面,這兩個頁面數據進行通信,比如我想在父頁面A.html 調用子頁面當中的函數 我們很容易想到或者google下 ;document.getElementById('iframeA').contentWindow.b(); 這種方法,其中b 是子頁面B.html中的一個函數。但是這樣調用下有個問題我糾結了很久,就是既然在火狐下報這樣的錯誤, 如下圖所示:
b不是個函數 但是我在子頁面明明定義了這么一個函數,那么為什么會報這樣的錯誤呢?經過仔細分析及google,發現有這么一個問題需要理解,當iframe沒有加載完成后 我就去執行這個js會報這樣的錯誤,所以就試着在火狐下 用iframe.onload 這個函數 進行測試,果然沒有報錯,是正確的 所以就確定是這個問題。所以就想寫個兼容IE和火狐 google寫個函數 來確定iframe已經加載完成!,其實給個回調函數來調用我們上面的方法。
綜合上面的思路 A.html 就可以寫個這樣的代碼:
<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 如下:
<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代碼如下:
<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代碼如下:
/* * 子頁調用父頁的方法 */ document.domain = 'example.com'; //window.top.test(); window.parent.test();
還是這兩個頁面 我想父頁調用子頁 如下方法:
a.html代碼如下:
/* * 跨域 父頁想調用子頁的的函數 */ 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函數 代碼如下:
document.domain = 'example.com'; function child(){console.log('我是子頁');}
就可以跨域調用了 不管是子頁面調用父頁面 還是父頁面調用子頁面。一切ok!
三:是不同主域跨域;
雖然google有幾種方法關於不同主域上的跨域問題 有通過location.hash方法或者window.name方法或者html5及flash等等,
但是我覺得下面iframe這種方法值得學習下,如下圖所示:
域a.com的頁面request.html(即http://a.com/demo/ajax/ajaxproxy/request.html)里面嵌套了一個iframe指向域b.com
(http://b.com/demo/ajax/ajaxproxy/response.html)的response.html,而response.html里又嵌套了域a.com的proxy.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
b.com域下有:
response.html
Process.php
先來看看request.html頁面如下:
<!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代碼如下:
<!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 $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代碼:
<!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代碼如下:
<!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代碼如下:
<!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代碼如下:
<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代碼如下:
<!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代碼如下:
<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只有從http://www.zuixiandao.cn/books/中才能訪問,那么http://www.zuixiandao.cn的頁面就不會發送cookie信息。
6. Cookie失效時間的概念:表示cookie何時應該被刪除,默認情況下,瀏覽器會話結束時即將刪除所有的cookie,不過也可以自己設置
刪除時間的。這個值是個GMT格式的日期(Wdy DD-Mon-YYYY HH:MM:SS GMT),用於指定應該刪除cookie的准確時間,因此,
cookie可在瀏覽器關閉后依然保存在用戶的機器上(同一個瀏覽器,不同的瀏覽器不能保存),如果設置的日期是過期的日期,那么cookie立刻刪掉。
7. Cookie安全標志 指定后,cookie只有在使用SSL連接的時候才發送到服務器。比如:cookie信息只能發送給https://www.zuixiandao.cn,
而http://www.zuixiandao.cn的請求則不能發送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的封裝代碼如下:
// 獲取所有的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代碼:
<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代碼如下:
<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如下:
三:IE用戶數據;
在IE5.0中,微軟通過一個自定義行為引入了持久化用戶數據的概念,用戶數據允許每個文檔最多128kb的數據,每個域名最多1MB的數據,
要使用持久化數據,首先必須如下所示,使用css在某個元素上指定userData行為:
<div style="behavior:url(#default#userData)" id="dataStore">IE用戶數據</div>
針對IE有如下使用方法:
1. getAttribute(“key”) 獲取指定的屬性值。
2. load(object) 從 userData 存儲區載入存儲的對象數據。
3. removeAttribute(“key”) 移除對象的指定屬性。
4. save(object) 將對象數據存儲到一個 userData 存儲區。
5. setAttribute(“key”,”value”) 設置指定的屬性值。
我們繼續做一個demo來演示下在IE瀏覽器下的存儲的demo。
HTML代碼如下:
<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代碼如下:
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如下:
四:sessionStorage 和 localStorage
Html5新增了兩個本地存儲數據,分別是sessionStorage 和 localStorage.
瀏覽器支持程度如下:
注意: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代碼如下:
<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代碼如下:
<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>
如上的代碼,我們現在繼續來看看效果如下:使用
我們還可以做一點復雜的應用,比如如下一個表格有一些字段,比如姓名,email,tel,及備注字段,我們先保存到本地去,然后根據姓名這個字段進行搜索就可以搜索到數據到,我們可以稱為這是簡單的本地數據庫,如下代碼:
<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代碼如下:
// 保存數據 $("#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頁面,代碼如下:
<iframe src="http://abc.example.com/demo/tugenhua0707/storage/data.html" id="iframe"></iframe>
其中data.html 頁面 使用一個window.name = “111”;來保存數據。
現在我們接下來在app.html頁面 如何來調用同域下的data.html下的window.name的數據,首先我們先要獲取到這個iframe,然后判斷iframe是否加載完,加載完后就獲取這個iframe中的window.name,
App.html JS的代碼如下:
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代碼如下:
<iframe src="http://def.example.com/demo/tugenhua0707/storage/data.html" id="iframe"></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代碼如下:
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代碼如下:
<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代碼如下:
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代碼:
<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代碼如下:
var parentwin = window.parent; window.addEventListener("message",function(e){ document.getElementById("test2").innerHTML = "從父窗口傳來的域" +e.origin + ",和內容數據:" + e.data; parentwin.postMessage('HI!你給我發了"<span>'+e.data+'"</span>。',"http://abc.example.com"); },false);
當我點擊abc.html頁面后,可以看到效果如下,從def.html返回內容了。如下:
我們需要知道如下幾條信息:
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代碼:
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代碼如下:
//獲取跨域數據 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 $data=array( url =>1, name =>'2', 'xx-xx'=>"xx" ); echo json_encode($data); ?>
如上實現方式 就可以實現ajax post跨域了。