域請求:
現代的所有的瀏覽器都遵守同源策略,所謂的源指的就是一個域名、一個服務器,同源是指兩個腳本擁有相同的域名,不同源指的是不同的域名,同源策略指的是,一個源的腳本不能讀取或操作其他源的http響應和cookie,也就是出于安全方面的考慮,頁面中的JavaScript無法訪問其他服務器上的數據,這就是所謂的“同源策略”。
同源是指協議、域名和端口都一致。
不同源限制的內容:
跨域請求時,不同域的服務器是返回了數據的,只不過瀏覽器攔截了響應數據;同時也說明了跨域并不能完全阻止CSRF,因為請求畢竟是發出去了;
CORS(Cross-Origin Response Sharing)跨域資源共享:
通過XHR實現Ajax通信的主要限制,是跨域安全策略;默認情況下,只能訪問同一個域中的資源,這種安全策略可以預防某些惡意行為,如:
var xhr = new XMLHttpRequest();
xhr.onload = function(){
console.log(xhr.responseText);
}
xhr.open("GET", "https://www.zeronetwork.cn/study/index.html");
xhr.send(null);
其拋出了CORS policy異常;
XHR2規范了在通過HTTP響應中如何選擇合適的CORS(Cross-Origin Response Sharing,跨域資源共享)去跨域訪問資源;其定義了在必須訪問跨源資源時,瀏覽器與服務器應該如何溝通;CORS的基本思想是,就是使用自定義的HTTP頭部讓瀏覽器與服務器進行溝通,從面決定請求或響應是否應該成功;
比如一個簡單的使用GET或POST發送的請求,默認情況下它沒有自定義的頭,但一般會包括一個Origin請求頭,其中包含請求頁面的源信息(協議、域名和端口),以便服務器根據這個頭部信息來決定是否給予響應,如Origin頭部示例:
Origin: https://www.zeronetwork.cn
如果服務器認為這個請求可以接受,就在響應的Access-Control-Allow-Origin([??la?])頭中回發相同的源信息(如果是公共資源,可以回發”*”),例如:
Access-Control-Allow-Origin: https://www.zeronetwork.cn
如果沒有這個響應頭,或者有這個響應頭但與請求Origin頭信息不匹配,瀏覽器就會駁回請求;反之,瀏覽器會處理請求;
實現跨域:
IE和標準瀏覽器已經實現了各自的跨域解決方案;
標準瀏覽器對CORS的實現:
在標準瀏覽器中,客戶端在使用Ajax跨域請求時,拋出異常,不能訪問;如:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(){
if (xhr.readyState == 4 && xhr.status == 200) {
console.log(xhr.responseText);
}
}
xhr.open("GET","https://www.b.com/normal/example.json");
xhr.send(null);
被請求的服務端需要設置Access-Control-Allow-Origin響應頭,以便于瀏覽器識別它是否為可信源。
例如,在Apache服務器中,在服務器的配置中添加如下設置:
Header set Access-Control-Allow-Origin 'origin-list'
對于Nginx,設置此http頭的命令是:
add_header 'Access-Control-Allow-Origin' 'origin-list'
或者使用.htaccess文件配置,如:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
order allow,deny
allow from all
應用:
xhr.open("GET","https://www.b.com/cors/example.json");
單獨為某個后端程序設置響應頭,例如b.com/cors.php:
<?php
header("Access-Control-Allow-Origin: *");
echo "跨域訪問b.com/cors.php";
無論同源請求還是跨源請求都使用相同的接口,因此對地本地資源,最好使用相對URL,在訪問遠程資源時再使用絕對URL;這樣做能消除歧義,避免出現限制訪問頭部或本地cookie信息等問題。
IE對CORS的實現:
微軟在IE8中引入了XDR(XDomainRequest)對象,其與XHR類似,其可直接用于發起安全的跨域請求,實現安全可靠的跨域通信;
var xdr = new XDomainRequest();
console.log(xdr);
IE11和標準瀏覽器并不支持;
XDR對象的使用方法與XHR對象非常相似,兩者擁有幾乎相同的屬性和方法,也是調用open()方法,再調用send()方法;但與XHR對象的open()方法不同,XDR對象的open()方法只接收兩個參數:請求的類型和URL;如:
var xdr = new XDomainRequest();
console.log(xdr);
// xdr.open("GET", "http://www.c.com/nocors.php");
xdr.open("GET", "example.php");
xdr.onload = function(){
console.log(xdr.responseText);
}
xdr.send();
此時,不管是跨域的還是同源的都不允許訪問,拋出“在 Access-Control-Allow-Origin 標頭中未找到源”;
XDR對象的安全機制中部分實現了CORS,后端也需要設置 Access-Control-Allow-Origin響應頭,如c.com/cors.php:
<?php
header("Access-Control-Allow-Origin: *");
echo "設置了ACAO響應頭";
請求端:
xdr.open("GET", "http://www.c.com/cors.php");
XDR對象屬性和事件:
請求返回后,會觸發onload事件,響應的數據也會保存在responseText屬性中,響應的MIME類型保存在contentType屬性中,如:
var xdr = new XDomainRequest();
xdr.onload = function(){
console.log(xdr.contentType); // application/json
console.log(xdr.responseText);
}
xdr.open("post","http://www.c.com/cors/example.json");
xdr.send(null);
例如再請求一個同源的contentType.php:
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json");
echo '{"username":"王唯","age":18,"sex":true}';
在接收到響應后,只能訪問響應的原始文本,不能確定響應的狀態代碼(也就是它沒有status屬性);而且,只要響應有效就會觸發onload事件,如果失敗就會觸發error事件,但除了錯誤本身之外,沒有其他信息可以確定請求是否成功,所以唯一能夠確定的就只有請求未成功;
要檢測錯誤,如要指定error事件處理程序,如:
xdr.onerror = function(){
console.log("出現錯誤");
}
由于導致XDR請求失敗的因素很多,因此,最好通過error事件處理程序來捕獲該事件,否則,即使請求失敗也不會有任何提示。
在請求返回前調用abort()方法可以終止請求,如:
xdr.abort();
與XHR對象一樣,XDR也支持timout屬性和ontimeout事件,如:
xdr.timeout=1000;
xdr.ontimeout = function(){
console.log("請求超過1秒");
};
onprogress事件:
應該始終定義 xdr.onprogress 事件,即使它是一個空函數,否則 XDomainRequest 對于重復請求,可能不會觸發 onload 事件;
xdr.onprogress = function(event){
console.log(event);
};
XDR與XHR的不同之外:
1、必須使用 HTTP 或 HTTPS 協議訪問目標 URL:
因為XDR對象依賴于一個HTTP響應頭來實現訪問控制,所以它要求目標URL符合HTTP或HTTPS 協議,以便于XDR對象檢驗響應頭;
2、只支持GET和POST請求;
3、不能設置自定義請求頭信息,也不能訪問響應頭部信息;
4、只支持text/plain作為請求頭Content-Type的取值:在XDR中,不管是GET還是POST請求,Content-Type被限制成“text/plain”,所以服務端不會把請求主體數據解析成鍵值對,即不能從參數中獲取到POST的數據,只能讀取流數據,需要其自行解析,如:
var xdr = new XDomainRequest();
xdr.open("POST", "xdrpost.php");
xdr.onload = function(){
console.log(xdr.responseText);
};
var param = "username=wangwei&age=18";
xdr.send(param);
xdrpost.php:
<?php
header("Access-Control-Allow-Origin: *");
$content = file_get_contents("php://input");
// echo $content; // username=王 唯&age=18
$arr = explode("&", $content);
foreach ($arr as $value) {
$v = explode("=", $value);
echo "key:$v[0], value:$v[1] \r\n";
}
5、身份驗證和cookie不能和請求一起發送,也不會隨響應返回;
6、請求的URL必須和被請求的URL采用相同的協議:兩者的協議必須統一,要么是HTTP,要么是HTTPS;
7、所有XDR請求都是異步執行的,不能用它來創建同步請求;
Preflighted Requests:
CORS通過一種叫做Prelighted Requests的透明服務器驗證機制支持開發人員使用自定義的頭部、GET或POST之外的請求方式,以及不同類型的主體內容;
在使用下列高級選項來發送請求時,就會向服務器發送一個Preflight請求,這種請求使用OPTIONS方式,發送下列頭部:
以下是一個帶有自定義頭部customHeader,并使用POST方法發送的數據,如:
發送這個請求后,服務器端可以決定是否允許這種類型的請求,其通過在響應中發送如下頭部與瀏覽器進行溝通:
例如,允許任何源、POST請求方式、自定義頭customHeader以及請求的緩存時間:
如:
var xhr = new XMLHttpRequest();
xhr.onload = function(){
console.log(xhr.responseText);
}
xhr.open("OPTIONS","https://www.b.com/flighted.php",true);
xhr.setRequestHeader("customHeader", "customValue");
xhr.send(null);
后端flighted.php:
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
header("Access-Control-Allow-Methods: *");
header("Access-Control-Max-Age: 1728000");
echo "有Headers、Methods頭信息";
Preflight請求結束后,結果將按照響應中指定的時間緩存起來;
帶憑據的請求:
默認情況下,跨域請求不提供憑據(cookie、HTTP認證及客戶端SSL證明等);
通過將XHR對象的withCredentials屬性設置為true,可以指定某個跨域請求應該發送憑據(授權信息);如:
xhr.withCredentials = true;
xhr.send(null);
當使用帶有憑據的請求時,不能把Access-Control-Allow-Origin設為*,并且Access-Control-Allow-Origin只能設置一個域,不能是多個,否則會拋出異常;
后端c.com/credentials.php:
header("Access-Control-Allow-Origin: http://www.a.com");
echo "c.com/example.php,已經設置了ACAO";
如果服務端接受帶憑據的請求,必須設置Access-Control-Allow-Credentials: true響應頭;
如后端c.com/ credentials.php:
header("Access-Control-Allow-Origin: http://www.a.com");
header("Access-Control-Allow-Credentials: true");
echo "設置了Origin,也設置了Credentials";
echo json_encode($_COOKIE);
如果在同源下配置withCredentials,無論配置true還是false,效果都會相同,且會一直提供憑據信息;另外,同時還可以發送自定義請求頭,如后端credentials.php:
<?php
header("Access-Control-Allow-Origin: http://www.a.com");
header("Access-Control-Allow-Credentials: true");
header("Access-Control-Allow-Headers: customHeader");
echo "設置了Origin,也設置了Credentials";
echo json_encode($_COOKIE);
服務端還可以在Preflight響應中發送這個HTTP頭部,但不能把Access-Control-Allow-Headers設為*;
跨瀏覽器的CORS:
即使瀏覽器對CORS的支持程度并不一致,但所有瀏覽器都支持簡單的請求(非Preflight和不帶憑據的請求),因此有必要實現一個跨瀏覽器的方案:檢測XHR是否支持CORS的最簡單方式,就是檢查是否存在withCredentials屬性,再結合檢測XDomainRequest對象是否存在,就可以兼顧所有瀏覽器了,如:
function createCORSRequest(method, url, withCredentials){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr) {
xhr.open(method, url);
xhr.withCredentials = withCredentials;
}else if(typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
}else{
xhr = null;
}
return xhr;
}
var request = createCORSRequest("GET", "https://www.b.com/credentials.php", true);
if(request){
request.onload = function(){
console.log(request.responseText);
};
request.send(null);
}
示例:使用HEAD和CORS請求鏈接的詳細信息,如:
var supportsCORS = (new XMLHttpRequest).withCredentials != undefined;
var links = document.getElementsByTagName("a");
for(var i=0; i<links.length; i++){
var link = links[i];
if(!link.href) continue;
if(link.title) continue;
if(link.host !== location.host || link.protocol != location.protocol){
link.title = "站外鏈接";
if(!supportsCORS) continue;
}
if(link.addEventListener)
link.addEventListener("mouseover", mouseoverHandler, false);
else
link.attachEvent("onmouseover", mouseoverHandler);
}
function mouseoverHandler(e){
var link = e.target || e.srcElement;
var url = link.href;
var xhr = new XMLHttpRequest();
xhr.open("HEAD", url);
xhr.onreadystatechange = function(){
if(xhr.readyState !== 4) return;
if(xhr.status == 200){
var type = xhr.getResponseHeader("Content-Type");
var size = xhr.getResponseHeader("Content-Length");
var date = xhr.getResponseHeader("Last-Modified");
link.title = "類型:" + type + "\n" +
"大?。?#34; + size + "\n" +
"時間:" + date;
}else{
if(!link.title)
link.title = "獲取不到詳細信息:\n" +
xhr.status + " " + xhr.statusText;
}
};
xhr.send(null);
if(link.removeEventListener)
link.removeEventListener("mouseover", mouseoverHandler, false);
else
link.detachEvent("onmouseover", mouseoverHandler);
}
HTML:
<a href="https://www.zeronetwork.cn/edu/">edu</a>
<a href="https://www.zeronetwork.cn/study/">study</a>
<a href="http://www.a.com/ demo.html">a.com</a>
<a>no href</a>
<a href="https://www.apple.com" title="baidu">apple.com</a>
<a href="https://cn.bing.com">bing</a>
其它跨域技術:
雖然CORS技術已經無處不在,但在CORS出現之前,就已經存在一些跨域的技術了,雖然這些技術應用起來有些麻煩,但它們絕大部分不需要修改服務器端代碼,所以直到現在這些技術仍然被廣泛使用;
后端代理方式:
這種方式可以解決所有跨域問題,也就是將本域的后端程序作為代理,每次對其它域的請求都轉交給該代理程序,其通過模擬http請求去訪問其它域,再將返回的結果返回給前端,這樣做的好處是,無論訪問的是文檔、還是JS文件都可以實現跨域;
例如,b.com/data.php響應JSON字符串:
<?php
$json_str = '{"name":"wagwei","sex":true,"age":18}';
echo $json_str;
a.com/getdata.php服務端獲取b.com/data.php響應:
<?php
// 創建cURL資源
$ch = curl_init();
// 設置URL和相應的選項
curl_setopt($ch, CURLOPT_URL, "http://www.b.com/data.php");
curl_setopt($ch, CURLOPT_HEADER, 0);
// 抓取URL并把它傳遞給瀏覽器
curl_exec($ch);
// 關閉cURL資源,并釋放系統資源
curl_close($ch);
a.com/data.html使用Ajax請求同源的getdata.php:
var xhr = new XMLHttpRequest();
xhr.open("GET", "getdata.php");
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
console.log(xhr.responseText);
}
};
xhr.send(null);
基于iframe實現跨域:
基于iframe實現的跨域要求兩個域屬于同一個根域,如:www.a.com和b.a.com其使用同一協議(例如都是 http)和同一端口(例如都是80),此時在兩個頁面中同時設置document.domain為同一個主域,就實現了同域,從而可以實現通信;如b.a.com中的iframe.html:
<h1>iframe</h1>
<img src="images/hu.png" />
<script>
document.domain = "a.com";
function show(msg){
alert("收到的:" + msg);
}
if(parent.parentFun){
parent.parentFun();
}
</script>
www.a.com主頁面為:
<script>
function parentFun(){
alert("parentFun");
}
</script>
<iframe src="http://b.a.com/iframe.html" id="myframe"></iframe>
<script>
var myframe = document.getElementById("myframe");
document.domain = "a.com";
myframe.onload = function(){
var win = myframe.contentWindow;
console.log(win);
win.show("零點程序員");
var doc = myframe.contentDocument;
console.log(doc);
}
</script>
使用window.name和iframe進行跨域:
window的name屬性返回的是該window的名稱,它的值有個特點:在不同的頁面(甚至不同域名)加載后依舊存在,并且可以支持非常長的name值(2MB),即在一個窗口(window)的生命周期內,窗口載入的所有的頁面都是共享一個window.name,每個頁面對window.name都有讀寫的權限;
正因為window的name屬性的這個特征,所以可以使用window.name來進行跨域;例如a.html:
<h1>a.html</h1>
<script>
window.name = "頁面a設置的name值";
setTimeout(function(){
window.location = "b.html";
},3000); // 3秒后在當前window中載入新的頁面
</script>
b.html:
<h1>b.html</h1>
<script>
alert(window.name); // 頁面a設置的name值
</script>
跨域:例如,有一個a.com/a.html頁面,需要通過js來獲取位于另一個不同域上的頁面,如:b.com/b.html里的數據:
<script>
window.name = "b.com/b.html中的數據";
</script>
如果b.html不跳轉,其他頁也可以獲取數據,可以采用iframe;
如a.com/a.html:
<h1>a.html</h1>
<iframe id="iframe" src="http://www.b.com/b.html" style="display:none"></iframe>
<script>
var iframe = document.getElementById("iframe");
// iframe在一開始載入b.com/b.html會執行此函數
iframe.onload = function(){
// 當iframe.src為b.html時觸發,此時iframe和當前頁面已經同源,可以訪問
iframe.onload = function(){
var data = iframe.contentWindow.name;
alert(data);
};
// 這里的b.html為隨便一個頁面,只要與當前頁面同源就可以,
// 目錄是讓iframe與當前頁面同源
iframe.src = "b.html";
}
</script>
使用location.hash+iframe跨域:
假設a.com/a.html要向b.com/b.html傳遞信息;如a.com/a.html:
<h1>a.html</h1>
<script>
function checkHash(){
try{
var data = location.hash ? location.hash.substring(1) : '';
console.log("收到的數據是:" + data);
}catch(e){}
}
setInterval(checkHash, 5000);
window.onload = function(){
var iframe = document.createElement("iframe");
// iframe.style.display = "none";
iframe.src = "http://www.b.com/b.html#param"; // 傳遞的location.hash
document.body.appendChild(iframe);
};
</script>
b.com/b.html:
<h1>b.html</h1>
<script>
function checkHash(){
var data = "";
// 模擬一個簡單的參數處理操作
switch(location.hash){
case "#param":
data = "somedata";
break;
case "#other":
// ...
break;
default:
break;
}
data && callBack("#" + data);
}
function callBack(hash){
// ie、chrome的安全機制無法修改parent.location.hash
//所以要利用一個中間的www.csdnblogs.com域下的代理iframe
var proxy = document.createElement("iframe");
proxy.style.display = "none";
proxy.src = "http://www.a.com/c.html" + hash;
// 注意該文件在a.com中
document.body.appendChild(proxy);
}
window.onload = checkHash;
</script>
a.com/c.html:
<script>
//因為parent.parent和自身屬于同一個域,所以可以改變其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);
</script>
圖像Ping:
使用<img>標簽,也可以動態創建圖像,使用它們的onload和onerror事件處理程序來確定是否接收到了響應;例如:
var img = new Image();
img.onload = img.onerror = function(){
console.log("Done");
};
img.src = "https://www.zeronetwork.cn/study/pingimg.php?name=wangwei";
pingimg.php:
if($_GET['name']){
echo $_GET['name'];
}
圖像Ping有兩個主要的缺點,一是只能發送GET請求,二是無法訪問服務器的響應文本,因此,圖像Ping只能用于瀏覽器與服務器間的單向通信;提交的數據是通過查詢字符串形式發送的,但響應可以是任意內容,但通常是像素圖或204響應;
通過圖像Ping,瀏覽器得不到任何具體的數據,但通過偵聽load和error事件,它能知道響應是什么時候接收到的,此時可以實現一些自身的邏輯;
示例:圖像Ping最常用于跟蹤用戶點擊頁面或動態廣告曝光次數,如:
<input type="button" id="btn" value="圖像Ping請求" />
<div id="result"></div>
<script>
var increment = (function(){
var counter = 0;
return function(){
return ++counter;
};
})();
var btn = document.getElementById("btn");
btn.addEventListener("click", function(event){
var sum = increment();
var result = document.getElementById("result");
var img = result.getElementsByTagName("img")[0];
if(!img)
img = new Image();
img.onload = img.onerror = function(){
result.appendChild(img);
var oSpan = document.getElementById("sum");
if(!oSpan){
oSpan = document.createElement("span");
oSpan.id = "sum";
}
oSpan.innerHTML = "發送請求的次數:" + sum;
result.appendChild(oSpan);
};
if(sum % 2)
img.src = "https://www.zeronetwork.cn/study/images/ad1.jpg?sum=" + sum;
else
img.src = "https://www.zeronetwork.cn/study/images/ad2.jpg?sum="+sum;
</script>
基于<script>標簽實現跨域:
在某些HTML元素中,可以通過它的src屬性跨域請求內容,例如img、iframe等,也就是沒有跨域的限制;同樣,script也可以,也就是利用script來執行跨域的javascript代碼,從而實現前端跨域請求數據的目的;例如:
<script>
var script = document.createElement('script');
script.src = "http://www.b.com/scripts/demo.js";
document.body.appendChild(script);
script.onload = function(){
show("從a.com傳過去的數據");
}
</script>
b.com/scripts/demo.js:
function show(msg){
alert("收到的數據:" + msg);
}
alert("www.b.com/script/demo.js");
JSONP:
JSONP是JSON with padding(填充式JSON或參數式JSON)的簡寫,是應用JSON的新方法,其利用<script>標簽沒有跨域限制的特點,可以得到從其他源動態產生的JSON數據,但JSONP請求一定需要對方服務器的支持才可以;
JSONP看起來與JSON差不多,是被包含在函數調用中的JSON,形如:callback({“name”: “wangwei”});
JSONP由兩部分組成:回調函數callback和json數據;回調函數是當響應到來時應該在頁面中調用的函數,其名字一般是在請求中指定的,需要在本地實現;而數據就是傳入回調函數中的JSON數據;整個JSONP就是一個標準的JavaScript語句;
JSONP后端服務:被請求服務端程序必須提供JSONP的服務,一般情況下,其會返回標準的JSONP;
例如,被請求服務端b.com/jsonptest.php返回JSONP的簡單形式:
<?php
echo 'alert({"name":"王唯","age":18})';
在請求端中使用<script>引入該文件,如:
<script src="http://www.b.com/jsonptest.php"></script>
請求端和服務端共同約定使用自定義函數,而不是內置函數;例如b.com/jsonptest.php:
echo 'handlerJSONP({"name":"王唯","age":18})';
請求端實現handlerJSONP()函數,并使用<script>引入b.com/jsonptest.php文件,如:
<script>
function handlerJSONP(response){
alert("姓名:" + response.name + "\n" + "年齡:" + response.age);
}
</script>
<script src="http://www.b.com/jsonptest.php"></script>
一般來說,后端程序通過查詢字符串允許客戶端指定一個函數名,然后用這個函數名去填充響應,例如:
<script>
function handlerJSONP(response){
alert(response);
}
</script>
<script src="http://www.b.com/jsonptest.php?callback=handlerJSONP"></script>
b.com/jsonptest.php:
header('Content-type: application/json');
//獲取回調函數名
$callback = htmlspecialchars($_REQUEST['callback']);
//json數據
$json_data = '["王唯","靜靜","娟子","大國"]';
//輸出jsonp格式的數據
echo $callback . "(" . $json_data . ")";
JSONP是通過動態<script>元素來使用的,例如:
// ...
var script = document.createElement("script");
script.src = "http://www.b.com/jsonptest.php?callback=handlerJSONP";
document.body.insertBefore(script, document.body.firstChild);
請求端與后端就該函數名有個約定,使用隨機名,如:hander1234();而查詢字符串的名字一般約定使用”json”或”callback”,當然也可以是其他任意的名稱;
JSONP之所以在開發人員中極為流行,主要原因是它非常簡單易用;與圖像Ping相比,它的優點在于能夠直接獲取響應文本,支持在瀏覽器與服務器之間雙向通信;
在某些時候,處理完JSONP數據后,動態創建的<script>就可以刪除了;
function clickHandler(e){
var script = document.createElement("script");
script.id = "jsonp_script";
script.src = "http://www.a.com/jsonp.php?callback=handlerResponse";
document.body.insertBefore(script, document.body.firstChild);
}
function handlerResponse(response){
console.log(response);
var script = document.getElementById("jsonp_script");
script.parentNode.removeChild(script);
}
var btn = document.getElementById("btn");
btn.addEventListener("click", clickHandler);
定義將被腳本執行的回調函數
getJSONP[cbnum] = function(response){
try{
callback(response);
}finally{
delete getJSONP[cbnum];
script.parentNode.removeChild(script);
}
};
script.src = url;
document.body.appendChild(script);
}
getJSONP.counter = 0; // 用于創建唯一回調函數名稱的計數器
function handlerResponse(response){
console.log(response);
}
getJSONP("http://www.a.com/jsonp.php", handlerResponse);
示例:某接口的應用:
<input type="button" id="btn" value="jsonp請求">
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
var script = document.createElement("script");
script.id = "jsonscript";
script.src = "https://suggest.taobao.com/sug?code=utf-8&q="+ encodeURIComponent("衣服") +"&callback=jsonpCallback";
document.body.appendChild(script);
});
function jsonpCallback(response){
console.log(response);
var script = document.getElementById("jsonscript");
script.parentNode.removeChild(script);
}
</script>
JSONP的不足:
JSONP和AJAX對比:
JSONP和AJAX相同,都是客戶端向服務器端發送請求,從服務器端獲取數據的方式;但AJAX屬于同源策略,采用CORS方案跨域,而JSONP屬于非同源策略進行跨域請求;
window.postMessage()方法:
window.postMessage()方法可以安全地實現跨域通信;其是HTML5規范提供的一種受控機制來規避跨域安全限制的方法,采用異步的方式進行有限的通信,既可以用于同域傳遞消息,也可以用于跨域傳遞消息;
其應用的場景是:
一個窗口可以獲得對另一個窗口的引用,比如iframe的contentWindow屬性、執行window.open返回的窗口對象、或者是命名過或數值索引的window.frames,然后在窗口上調用targetWindow.postMessage()方法分發一個MessageEvent消息;接收消息的窗口觸發onmessage事件,并接收分發過來的消息;
例如a.com/post.html,獲取iframe:
<h1>a.com/post.html</h1>
<iframe id="iframe" src="http://www.b.com/message.html"></iframe>
<script>
var iframe = document.getElementById("iframe");
var win = iframe.contentWindow;
console.log(win);
</script>
b.com/ message.html:
<h1>b.com/message.html</h1>
語法:otherWindow.postMessage(message, targetOrigin, [transfer]);
例如:a.com/post.html:
// ...
win.postMessage("來自a.com/post.html的消息","*");
b.com/message.html:
window.addEventListener("message", function(event){
console.log(event); // MessageEvent
});
需要延遲執行postMessage()方法,延遲的方式有多種,使用setTimeout()、iframe的onload事件、發送者的onload事件或者使用按鈕的click事件處理程序,如a.com/post.html:
setTimeout(function(){
win.postMessage("來自a.com/post.html的消息","*");
},500);
// 或:
var iframe = document.getElementsByTagName("iframe")[0];
iframe.onload = function() {
var iframe = document.getElementById("iframe");
var win = iframe.contentWindow;
win.postMessage("來自a.com/post.html的消息","*");
}
// 或:
var btnSend = document.getElementById("btnSend");
btnSend.addEventListener("click", function(){
var iframe = document.getElementsByTagName("iframe")[0];
var win = iframe.contentWindow;
win.postMessage("來自a.com/post.html的消息","*");
});
使用postMessage()將數據發送到其他窗口時,最好指定明確的targetOrigin,而不是*,原因是惡意網站可以在用戶不知情的情況下更改窗口的位置,甚至可以攔截所發送的數據;
win.postMessage("來自a.com/post.html的消息","http://www.b.com"); // 或
win.postMessage("來自a.com/post.html的消息","http://www.b.com/"); // 或
win.postMessage("來自a.com/post.html的消息","http://www.b.com/error.html");
在發送消息的時候,如果目標窗口的協議、主機地址或端口這三者的任意一項不匹配targetOrigin的值,那么消息就不會被發送;只有三者完全匹配,消息才會被發送;這個機制用來控制消息可以發送到哪些窗口。
MessageEvent接口:
代表一段被目標對象接收的消息;
屬性:
window.addEventListener("message", function(event){
console.log(event);
console.log(event.data); // 來自a.com/post.html的消息
console.log(event.lastEventId); // 空
console.log(event.origin); // http://www.a.com
console.log(event.ports); // []
console.log(event.source); // window http://www.a.com/post.html
});
如果不希望接收message,就不要實現message事件;如果希望從其他網站接收message,最好使用origin或source屬性驗證消息發送者的身份;如:
window.addEventListener("message", function(event){
if(event.origin != "http://www.a.com")
return;
console.log(event.data);
});
雖然postMessage()是單向的通信,但可以使用source屬性在具有不同origin的兩個窗口之間建立雙向通信;
例如a.com/message.html:
<iframe id="iframe" src="http://www.b.com/message.html"></iframe>
<input type="button" id="btn" value="send" />
<script>
var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
var iframe = document.getElementById("iframe");
var win = iframe.contentWindow;
win.postMessage("來自a.com/post.html的消息","http://www.b.com/");
});
window.addEventListener("message", function(event){
console.log("a.com收到:" + event.data);
});
</script>
b.com/message.html:
window.addEventListener("message", function(event){
if(event.origin != "http://www.a.com")
return;
console.log("b.com收到:" + event.data);
event.source.postMessage("b.com/message回發的消息", event.origin);
});
與使用open()方法打開的窗口通信:
在向使用open()方法打開的窗口發送消息時,需要延遲執行,如:
btnOpen.addEventListener("click", function(){
var win = window.open("http://www.b.com/message.html","_blank","width:600px,height:400px");
setTimeout(function(){
win.postMessage("從a.com中打開","http://www.b.com");
},1000);
});
window.addEventListener("message", function(event){
console.log("a.com收到:" + event.data);
});
或者反向發送消息,例如a.com/post.html:
var btnOpen = document.getElementById("btnOpen");
btnOpen.addEventListener("click", function(){
var win = window.open("http://www.b.com/message.html","_blank","width:600px,height:400px");
});
window.addEventListener("message", function(event){
console.log("a.com收到:" + event.data);
});
b.com/message.html:
<script>
window.onload = function(){
var targetWindow = window.opener;
console.log(targetWindow);
targetWindow.postMessage("message.html is ready","http://www.a.com");
}
window.addEventListener("message", function(event){
console.log("b.com收到:");
console.log(event.data);
event.source.postMessage("b.com/message.html回發的消息", event.origin);
});
</script>
postMessage()還可以發送結構化數據,該數據將會自動被(結構化克隆算法)序列化,如:
var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
var iframe = document.getElementById("iframe");
var win = iframe.contentWindow;
var person = {
name:"wanwei",
sex: true,
age: 18,
friends: ["jingjing","daguo"],
// smoking: function(){console.log(this.name)}, // 異常 could not be cloned.
other1: undefined,
other2: null
}
win.postMessage(person,"http://www.b.com/");
b.com/message.html:
window.addEventListener("message", function(event){
console.log("b.com收到:");
console.log(event.data);
});
因為是跨域,所以即使取得外源窗口的window對象,也無法操作對方的DOM,但是通過接收到的消息,自行構建DOM;
例如a.com/post.html:
var btn = document.getElementById("btn");
btn.addEventListener("click", function(){
var iframe = document.getElementById("iframe");
var win = iframe.contentWindow;
var person = {
name:"wanwei",
sex: true,
age: 18,
friends: ["jingjing","daguo"],
}
win.postMessage(person,"http://www.b.com/");
});
window.addEventListener("message", function(event){
if(event.origin == "http://www.b.com"){
if(event.data.state){
document.getElementById("btn").setAttribute("disabled",true);
// ...
}
}
});
b.com/message.html:
window.addEventListener("message", function(event){
if(event.origin == "http://www.a.com"){
var person = event.data;
var h1 = document.createElement("h1");
h1.innerText = person.name + "信息";
document.body.appendChild(h1);
var p = document.createElement("p");
p.innerHTML = "性別:" + (person.sex ? "男" : "女");
p.innerHTML += "<br/>年齡:" + person.age;
p.innerHTML += "<br/>朋友:" + person.friends.join(",");
document.body.appendChild(p);
event.source.postMessage({state:1}, event.origin);
}
});
示例,后臺管理的應用,main.html:
<style>
*{margin:0; padding:0;}
ul,li{list-style: none;}
.top{width:100%; height:100px; background-color:yellowgreen;}
.left{width:20%; height: 100%; float: left; background-color:yellow;}
.left ul li{padding:10px;}
.left ul li a{color:#000; text-decoration: none;}
iframe{width:80%; float: right; border:none;}
.bg{
position: fixed; left:0; top: 0; display: none;
width:100%; height:100%; background-color: rgba(0, 0, 0, .5);
}
.showBg{display: block !important}
.confirm{
position:fixed; width:400px; height:200px; z-index: 2;
left: 50%; top: 50%; transform: translate(-50%, -50%);
padding: 20px; text-align: center; background-color: #FFF;
}
</style>
<div class="top"></div>
<div class="left">
<ul>
<li><a href="console.html" target="iframe">控制臺</a></li>
<li><a href="content.html" onclick="sendMessage()" target="iframe">系統設置</a></li>
</ul>
</div>
<iframe name="iframe" src="console.html"></iframe>
<div class="bg">
<div class="confirm">
<p>是否確認保存?</p>
<p><input type="button" id="btnCancel" value="取消" />
<input type="button" id="btnSave" value="保存" /></p>
</div>
</div>
<script>
var iframe = null;
window.onload = function(){
var leftDiv = document.getElementsByClassName("left")[0];
iframe = document.getElementsByTagName("iframe")[0];
iframe.style.height = leftDiv.style.height = (document.documentElement.scrollHeight - 100) + "px";
}
function sendMessage(){
iframe.onload = function(){
iframe.contentWindow.postMessage({
method: 'dataId',
data: {dataId: 1}
}, "*");
}
}
window.addEventListener("message", function(event){
if(event.data.method == "showBg"){
document.getElementsByClassName("bg")[0].classList.add("showBg");
}
});
var btnCancel = document.getElementById("btnCancel");
btnCancel.addEventListener("click", function(){
if(iframe){
iframe.contentWindow.postMessage({
method: "cancel"
}, "*");
document.getElementsByClassName("bg")[0].classList.remove("showBg");
}
});
var btnSave = document.getElementById("btnSave");
btnSave.addEventListener("click", function(){
if(iframe){
iframe.contentWindow.postMessage({
method: "save"
}, "*");
document.getElementsByClassName("bg")[0].classList.remove("showBg");
}
});
</script>
console.html:
<h1>控制臺</h1>
content.html:
<style>
.container{width:60%; margin: 0 auto;}
</style>
<div class="container">
<p>設置1:<input type="text" /></p>
<p>設置2:<input type="text" /></p>
<p>設置3:<input type="text" /></p>
<p>設置4:<input type="text" /></p>
<p><input type="button" id="btnConfirm" value="保存" /></p>
</div>
<script>
window.addEventListener("message", function(event){
if(event.data.method == "dataId"){
console.log(event.data.data.dataId);
}else if(event.data.method == "cancel"){
console.log("取消操作");
}else if(event.data.method == "save"){
console.log("保存成功");
}
});
var btnConfirm = document.getElementById("btnConfirm");
btnConfirm.addEventListener("click", function(){
window.parent.postMessage({
method: "showBg"
}, "*");
});
</script>
示例,修改信息:
content.html:
<div class="container">
<h1>用戶信息</h1>
<p>ID:001</p>
<p>姓名:<span id="usernameSpan">王唯</span>
<input type="button" id="editInfo" value="修改個人信息" /> </p>
<p>單位:<span id="jobSpan">零點網絡</span>
<input type="button" id="editJob" value="修改工作信息" /></p>
<p>地址:<input type="text" id="address" value="北京市東城區" /></p>
<p>電話:<input type="text" id="tel" value="13888888888" /></p>
<p><input type="button" id="btnConfirm" value="保存" /></p>
</div>
<script>
window.addEventListener("message", function(event){
if(event.data.method == "dataId"){
console.log(event.data.data.dataId);
}else if(event.data.method == "cancel"){
console.log("取消操作");
}else if(event.data.method == "save"){
document.getElementById("usernameSpan").innerText = event.data.data.username;
console.log("保存成功");
}
});
var btnConfirm = document.getElementById("btnConfirm");
btnConfirm.addEventListener("click", function(){
window.parent.postMessage({
method: "showBg"
}, "*");
});
var editInfo = document.getElementById("editInfo");
editInfo.addEventListener("click", function(){
var win = window.open("editInfo.html", "_blank","width:200px,height:500px");
setTimeout(function(){
win.postMessage({
method: "info",
dataId: 2
});
},500);
});
</script>
editInfo.html:
<form>
<input type="hidden" id="ID" name="ID" />
<p>姓名:<input type="text" id="username" name="username" /></p>
<p>性別:<input type="radio" id="male" name="sex" value="1" />男
<input type="radio" id="female" name="sex" value="0" />女</p>
<p>年齡:<input type="text" id="age" name="age" /></p>
<p><input type="button" id="btnCancel" value="取消" />
<input type="button" id="btnSave" value="保存" /></p>
</form>
<script>
window.addEventListener("message", function(event){
if(event.data.method == "info"){
// Ajax請求,從數據庫中取出這條記錄
var id = event.data.dataId;
var xhr = new XMLHttpRequest();
xhr.open("GET", "getInfo.php?action=showInfo&ID=" + id);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
// console.log(xhr.response);
var person = xhr.response;
document.forms[0].elements['ID'].value = person.ID;
document.forms[0].elements['username'].value = person.username;
document.forms[0].elements['sex'].value = person.sex;
document.forms[0].elements['age'].value = person.age;
xhr = null;
}
};
xhr.responseType = "json";
xhr.send(null);
}
});
var btnCancel = document.getElementById("btnCancel");
btnCancel.addEventListener("click", function(){
window.opener.postMessage({method: "cancel"}, "*");
window.close();
});
var btnSave = document.getElementById("btnSave");
btnSave.addEventListener("click", function(){
// 保存到數據庫
var data = new FormData(document.forms[0]);
data.append("action", "update");
var xhr = new XMLHttpRequest();
xhr.open("POST", "getInfo.php");
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && xhr.status == 200){
var data = JSON.parse(xhr.responseText);
if(data.status){
var person = {
ID: document.forms[0].elements['ID'].value,
username: document.forms[0].elements['username'].value,
sex: document.forms[0].elements['sex'].value,
age: document.forms[0].elements['age'].value
};
window.opener.postMessage({
method: "save",
data: person
});
}
xhr = null;
}
};
xhr.send(data);
window.close();
})
</script>
editInfo.php:
<?php
require_once "conn.php";
if(isset($_REQUEST['action'])){
if($_REQUEST['action'] == 'showInfo'){
$ID = intval($_GET['ID']);
$sql = "select ID,username, sex, age from users where ID=$ID";
$result = $conn->query($sql);
$row = mysqli_fetch_array($result);
echo json_encode($row);
}elseif($_REQUEST['action'] == 'update'){
$ID = intval($_POST['ID']);
$username = $_POST['username'];
$sex = $_POST['sex'];
$age = $_POST['age'];
$sql = "update users set username='$username', sex='$sex', age='$age' where ID=$ID";
$result = $conn->query($sql);
if($result){
echo '{"status": 1}';
}else{
echo '{"status": 0}';
}
}
超鏈接打開的窗口也可使用postMessage()方法進行通信,但需要設置a標簽的target屬性為自定義值,如:
<p><a href="http://www.b.com/content.html" target="mywin">零點程序員</a></p>
b.com/content.html:
console.log(window.opener); // Window or global
console.log(window.name); // "mywin"
發送消息,b.com/content.html:
if(window.opener){
console.log(window.opener);
window.opener.postMessage("我已經打開了","*");
}
主頁面:
/一、html
//a、HTML語法規范
//a.1基本語法概述
1、HTML標簽是由尖括號包圍的關鍵字,例如,
2、HTML標簽通常是成對出現的,例如和,我們成為雙標簽,標簽對中的第一個標簽是開始標簽,第二個標簽是結束標簽。
3、有些特殊的標簽是單個標簽(極少情況),例如
,我們稱為單標簽
//a.2標簽關系
雙標簽關系可以分為兩類:包含關系和并列關系。
//b、HTML基本結構標簽
//b.1第一個HTML網頁
每個網頁都會有一個基本的結構標簽(也稱為骨架標簽),頁面內容也是在這些基本標簽上寫的。
HTML頁面也稱為HTML文檔
標簽名 | 定義 | 說明 |
<html></html> | HTML標簽 | 頁面中最大的標簽,我們稱為根標簽 |
<head></head> | 文檔的頭部 | 注意在head標簽中我們必須要設置的標簽是title |
<title></title> | 文檔的標題 | 讓頁面擁有一個屬于自己的網頁標題 |
<body></body> | 文檔的主體 | 元素包含文檔的所有內容,頁面內容,基本都是放到body里面的 |
必須是.html或.htm,瀏覽器的作用是讀取HTML文檔,并以網頁的形式顯示出它們。
此時,用瀏覽器打開這個網頁,我們就可以預覽我們寫的第一個HTML文件了。
//c、開發工具vscode
1、<!DOCTYPE>標簽
文檔類型聲明,作用就是告訴瀏覽器使用哪種HTML版本來顯示網頁
<!DOCTYPE html>這句代碼的意思是:當前頁面采用的是HTML5來顯示頁面。
2、lang語言
用來定義當前文檔顯示的語言:
a、en定義語言為英語
b、zh-CN定義語言為中文
簡單來說定義為en就是英文網頁,定義為zh-CN就是中文網頁
其實對于文檔顯示來說,定義成en的文檔也可以顯示中文,定義zh-CN的文檔也可以顯示英文
這個屬性對于瀏覽器和搜索引擎(百度、谷歌等)還是有作用的
3、charset字符集
字符集是多個字符的集合,以便計算機能夠識別和存儲各種文字
在標簽內,通過標簽的charset屬性來規定HTML文檔應該使用哪種字符編碼。
charset常用的值:GB2312、BIG5、GBK和UTF-8,其中UTF-8也稱為萬國碼,基本包含了全世界所有國家需要用到的字符。
注意:上面語法是必須寫的代碼,否則可能引起亂碼的情況,一般情況下,統一使用"UTF-8"編碼,盡量統一寫成標準的"UTF-8",不要寫成"utf-8"或"UTF8"。
//d、HTML常用標簽
//d.1標簽語義
學習標簽是有技巧的,重點是記住每個標簽的語義,簡單理解就是指標簽的含義,即這個標簽是用來干嘛的
根據標簽的語義,在合適的地方給一個最為合理的標簽,可以讓頁面結構更清晰。
//d.2標題標簽
-
(重要)
為了使網頁更具有語義,我們經常會在頁面中用到標題標簽,HTML提供了6個等級的網頁標題集
-
特點:
1、加了標題的文字會變得更加粗,字號也會依次變大。
2、一個標題獨占一行。
//d.3段落和換行標簽(重要)
在網頁中,要把文字有條理地顯示出來,就需要將這些文字分段顯示,在HTML標簽中,
標簽用于定義段落,它可以將整個網頁分為若干段落。
<p>我是一個段落標簽</p>標簽語義:可以把HTML文檔分割為若干段落。
特點:
1、文本在一個段落中會根據瀏覽器窗口的大小自動換行。
2、段落和段落之間保有一個較大的空隙。
在HTML中,一個段落中的文字從左到右依次排列,直到瀏覽器的右端,然后自動換行,如果希望某段文本強制換行顯示,就需要使用換行標簽
<br />
單詞break的縮寫,意為打斷,換行。
特點:
1、單標簽
2、
標簽只是簡單地開始新的一行,跟段落不一樣,段落之間會插入一些垂直的間距。
//d.4文本格式標簽
在網頁中,有時需要為文字設置粗體,斜體或下劃線等效果,這時就需要用到HTML中的文本格式標簽,使文字以特殊的方式顯示
標簽語義:突出重要性,比普通文字更重要。
語義 | 標簽 | 說明 |
加粗 | <strong></strong>或者<b></b> | 更推薦使用<strong></strong>標簽加粗,語義更強烈 |
傾斜 | <em><em> 或者<i><i> | 更加推薦使用<em><em>標簽,語義更加強烈 |
刪除線 | <del><del>或者<s><s> | 更加推薦使用<del><del>標簽,語義更加強烈 |
下劃線 | <ins><ins>或者<u><u> | 更加推薦<ins><ins>標簽,語義更加強烈 |
//d.5<div>和<span>標簽
<div>和<span>是沒有語義的,它們就是一個盒子,用來裝內容。
<div>這是頭部</div>
<span>今日價格</span>
div是division的縮寫,表示分割,分區,span意為跨度,跨距。
特點:
1、<div>標簽用來布局,但是現在一行只能放一個<div>,大盒子。
2、<span>標簽用來布局,一行上可以有多個<span>,小盒子
//d.6圖像標簽和路徑(重點)
1、圖像標簽
在HTML標簽中,<img>標簽用于定義HTML頁面中的圖像。
<img src="圖像url"/>
單詞image的縮寫,意為圖像
src是<img>標簽的必須屬性,它用于指定圖像文件的路徑和文件名。
所謂屬性:簡單理解就是屬于這個圖像標簽的特性。
圖像標簽的其他屬性:
屬性 | 屬性值 | 說明 |
src | 圖片路徑 | 必須屬性 |
alt | 文本 | 替換文本,圖像不能顯示的文字 |
title | 文本 | 提示文本,鼠標放到圖像上,顯示文字 |
width | 像素 | 設置圖像的寬度 |
height | 像素 | 設置圖像的高度 |
border | 像素 | 設置圖像的邊框粗細 |
HTML:htper text markup language超文本標記(標簽)語言
由各種標簽組成,用來制作網頁,告訴瀏覽器如何顯示頁面
w3c:world wide web consortium萬維網聯盟,制定web技術相關標準和規范的組織,HTML技術hi由w3c制定的標準
兩個版本:HTML4.0.1、HTML5.0-----通常H5
官網:http://www.W3shcool.com.cn
HTML文檔是以.html或.htm結尾
記事本notepad、sublime、Notepad++、Dreamweaver、VScode、Webstorm等
使用步驟:
使用技巧:
常見的瀏覽器:IE瀏覽器微軟、chrome谷歌瀏覽器、fifirefox火狐、safari蘋果
瀏覽器的作用是讀取html文件,并以網頁的形式來顯示
瀏覽器不會直接顯示html標簽,而是使用標簽來解釋網頁的內容
一個完整的html標簽的組成:
<標簽名 屬性名="屬性值">內容</標簽名>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>標簽</title>
</head>
<body bgcolor="red" text="blue">
html從入門到精通!
</body>
</html>
12345678910
屬性值要用雙撇號括起來,一般用雙引號
根據標簽是否關閉,分為,關閉型和非關閉型
<html></html>
<head></head>
<title></title>
非關閉型:沒有結束標簽
<meta>
<br>
<h1>....<h6>
根據標簽是否獨占一行,分為塊級標簽和行級標簽
塊級標簽:顯示為塊狀,獨占一行
<h1>大家好</h1>
<hr>
行級標簽:在行內顯示,可與其他內容在同一行顯示
<span></span>
注釋在瀏覽器中不會顯示,是用來標注解釋html語句,但通過查看源代碼的方式可以看到
語法:
<--注釋內容-->
也稱為特殊字符,用于顯示一些特殊符號,如<>&空格等
語法:
<&實體字符的名稱>
在html文檔的第一行,使用<!DOCTYPE html>
聲明HTML文檔的類型用來告訴瀏覽器頁面的文檔嘞型,用來制定html版本的規范
目前基本上最常用的html5
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
</html>
12345678910
1.基本標簽
1.1 有序列表
ol:ordered listli:list item默認使用阿拉伯數字、從1開始標記,可以通過屬性進行修改
· type屬性:設置列表的符號標記、取值;數字1(默認)、字母(a或A)、羅馬數字(i或I) · start屬性:設置起始值,值必須是數字
1.2 無序列表
ul:unodered list
li:list item
默認情況下使用實心圓表作為符號標記,可以通過屬性進行修改
· type屬性:設置列表的符號標記、取值:disc實心圓(默認)、circle空心圓、square正方形、none不 顯示項目符號
1.3 定義列表
dl:definition list
dt:definition title
dd:definition description
1.4 水平線標簽
hr:horizontal
常用屬性:
· color:顏色
兩種方式:
顏色名稱:如red、green、blue、white、black、pink、orange等
16進制的RGB表示法:Red、Green、Blue用法:#RRGGBB 每種顏色的取值范值0-255,轉換為16 進制00-FF
如: #FF0000 紅色 #00FF00綠色 #0000FF藍色 #FFFFFF白色、#CCCCCC #FF7300桔色
· size:粗細,數值
· width寬度
兩種寫法:
? 像素:絕對值(固定值)
? 百分比:相對值,相對于水平線標簽所在父容器寬度的百分比
· align對齊
? 取值:center居中 left right
1.5圖像標簽
img:image
常見的圖片格式:.jpg .png .gif .bmp
常見的屬性:
· src:source指定圖片的路徑(來源),必選叁數
如果圖片與html源代碼在同一個文件夾中,可以直接在src中寫圖片名稱即可
習慣上,我們會將多個圖片與html代碼文檔分別放在同一個文件夾project中的不同目錄下,此時需要 在src中指定圖片的路徑為相對路徑
路徑的分類:
? · 相對路徑
? 表示: ./當前路徑
…/當前位置的上一級文件夾
? 提示:…/image
? · alt:當圖片無法顯示時顯示的提示信息
? · title:當鼠標放到圖片上時顯示的提示信息
? · width和 height:設置圖片的寬度和高度
默認圖片以原始尺寸顯示
? 如果只設置其中一個,則另一個會按比例縮放
? 如果同時設置寬和高,可能導致圖片變形
? 兩種寫法:
? 像素:絕對值(固定值)
? 百分比:相對值,相對于父容器的尺寸的百分比
2.其他標簽
為了更好語義化
3.頭部標簽
· meta定義網頁的摘要信息,如字符編碼,關鍵詞,描述,作者等
· title定義網頁的標題
· style定義內容css樣式
· link引用外部css樣式
· script定義或引用腳本
· base定義基礎路徑
默認以當前頁面文件所在的位置為相對路徑參照
4.標簽嵌套
一個標簽中嵌套另外一個標簽
標簽不能亂嵌套
瀏覽器渲染后顯示的頁面代碼與編碼時有所不同
chrome瀏覽器提供的開發工具:幫助開發人員查看和調試頁面的
如何打開:
· Elements:從瀏覽器的角度來看頁面,瀏覽器渲染頁面時內部的結構
· console:控制臺,顯示各種警告和錯誤信息
· network:查看網絡請求信息,瀏覽器向服務器請求了哪些資源,資源大小,
加載資源所消耗的時間
四、超鏈接
1.簡介
使用超鏈接可以從一個頁面跳轉到另外一個頁面,實現頁面之間導航
當鼠標移動到超鏈接文本或圖片時,鼠標箭頭會變成一只小手
超鏈接有三種類型:
普通鏈接/頁面間的鏈接,跳轉到另一個頁面 錨鏈接:鏈接到錨點(鏈接到同一個頁面的指定位置) 功能鏈接:實現特殊功能(發郵件,下載)
2.基本用法
使用 標簽來創建超鏈接
語法格式:
常用屬性:
href:鏈接地址或路徑,鏈接地址
world
鏈接文本或圖片
1 2 3 4 5 1 target:鏈接打開的位置,取值
路徑分類:
絕對路徑 以根開始的路徑
file:///D:/software/b.html https://www.baidu.com/img/bd_logo1.png
相對路徑 相對于當前頁面文件所在的路徑,不是以根開始的路徑 ./ 當前路徑 …/ 當前位置上一級目錄
3.錨鏈接
3.1簡介
點擊鏈接后跳轉到某一個頁面的指定位置(錨點anchor)
錨鏈接的分類:
頁面內的錨鏈接 頁面間的錨鏈接
3.2 頁面內的錨鏈接
步驟:
3.3 頁面間的錨鏈接
4.功能鏈接
5.URL
5.1 簡介
URL:Uniform Resource Locator 統一資源定位器,用來定位資源所在的位置,最常見的就是網址
5.2 組成
一個完整的URL由8個部分組成:
協議:prococol 如 http:超文本傳輸協議,用來訪問WEB網站Hyper text Transfer protocal https:更加安全的協議 SSL安全套接子層 ftp文件傳輸協議,用來訪問服務器上的文件,實現文件的上傳和下載File Transfer protocol file:文件協議,用來訪問本地文件 主機名hostname服務器地址或服務器Netbios名稱,如www.baidu.com ftp://10.255.254.254 端口:port位于主機名的后面,使用冒號進行分隔 不同的協議使用不同的端口,如http使用80端口,https使用的443端口,ftp使用20和21 如果使用的是默認端口,則端口可以省略 如果使用的不是默認端口,則必須指定端口http://59.49.32.213:7070/ 路徑:path目標文件所在的路徑結構,如:www.baidu.com/img/ 資源resource要訪問的目標文件,如bd_logo1.png 查詢字符串:query string 也稱為參數 在資源后面使用?開頭的一組名稱/值
鏈接文本
鏈接文本
https://www.baidu.com/img/bd_logo1.png?name=tom&age=2&sex=male https://www.w3school.com.cn/html/html_quotation_elements.asp file:///C:/Users/Administrator/Desktop/project/code/09.%E5%B8%B8%E7%94%A8%E6%A0%87%E7%A D%BE3.html http://www.sxgjpx.net/ ftp://10.255.254.253/
1
1
1 2 3
4 5
名稱和值之間以=分隔,多個之間用&分隔,如:name=tom&age=2&sex=male 錨點anchor,在資源后面使用#開頭的文本,如#6 身份認證authentication,指定身份信息,如:ftp://賬戶:密碼@ftp.bbshh010.com
五、表格
1.簡介
表格是一個規則的行列結構,每個表格是由若干行組成,每行由若干個單元格組成
table row column
2.基本結構
2.1 table標簽
用來定義表格
常用屬性:
border:表格邊框 默認為0 width/height:寬度/高度 bordercolor:邊框的顏色 align:對齊方式,取值:left(默認) center居中 right居右 bgcolor:背景顏色 background:背景圖片 cellspacing間距:單元格與單元格之間的距離 cellpadding邊距:單元格中的內容到邊界之間的距離
2.2 tr標簽
用來定義行:table row
常用屬性:
align:水平對齊 取值:left(默認) center right valign垂直對齊 取值:top center bottom bgcolor:背景顏色 background:背景圖片
2.3 td標簽
用來定義單元格,table data
常用屬性:align、valign、bgcolor、background
注意:表格必須是由行組成,行必須由單元格來組成,數據必須放到單元格中
3.合并單元格
合并單元格也稱為單元格的跨行跨列
兩個屬性:
rowspan 設置單元格所跨的行數 colspan 設置單元格所跨的列數
步驟:
六、表單
1.簡介
表單是一個包含若干個表單元素的區域,用于獲取瑣類型的用戶數據
表單元素是允許用戶在表單輸入信息的元素,如文本框、密碼框、單選按鈕、復選框、下拉列表、按鈕等
2.表單結構
2.1表單語法
1
2.2form標簽
用來定義表單,可以包含多個表單元素
常用屬性:
action:提交數據給誰處理,即處理數據的程序,默認為當前頁面 method:提交數據的方式或方法,取值:get(默認),post get和post的區別: get:以查詢字符串的形式提交,在地址欄中能看到,長度有限制,不安全 post以表單數據組的形式進行提交,在地址欄中看不到,長度無限制,安全 enctype(encode type)編碼類型:提交數據的編碼,取值:application/X-www-form-urlencoded(默 認)、multipart/form-data(文件上傳)
3.表單元素
大多數的表單元素都是使用 標簽來定義的,通過設置屬性type來定義不同的表單元素
1
3.1單行文本框
常用屬性:
·name名稱,很重要,如果沒有定義name屬性,則該表單元素的數據是無法提交的
·value初始值
·size顯示寬度
·maxlength:大字符數,默認是沒有限制
·readonly只讀:readonly=“readonly”,可簡寫readonly,即只寫屬性名
·disabled禁用:disabled=“disabled”, 可簡寫disabled完全禁用
表單元素被提交的兩個條件,1.有name屬性2.非disabled
3.2 單選按鈕
常用屬性:
·name名稱:多個radio的name屬性必須相同,才能實現互斥(單選)
·value值
·checked:是否被選中,兩種狀態,選中,未選中 checked=“checked” 簡寫 checked
3.3 復選框
常用屬性與單選按鈕radio類似
3.4 文件選擇器
常用屬性:
·name:名稱
·accept設置可選擇的文件類型,用來限制上傳的文件類型
使用MIME格式字符串對資源類型進行限制
常見的MIME類型:
·純文本:text/plain text/xml text/html
· 圖像:image/png image/jpeg image/gif
4.特殊表單元素
4.1下拉列表
select常用屬性:
·name名稱
·size行數,同時顯示多個選項
·multiple允許同時選擇多個
option常用屬性:
·value選項值
·selected設置默認選中項
optgroup常用屬性:
·label分組的標簽
4.2文本域
·name名稱
·rows行數
·cols列數
5、其他標簽
5.1 label標簽
為表單元素提供標簽,當選中label標簽中的文本內容時會自動將光標切換到與之相關聯的表單元素。
常用屬性:
·for必須將該屬性值設置為與相關聯的表單元素的Id屬性值相同。
注:幾乎所有HTML標簽都具有id屬性,且id值必須唯一。
5.2 button標簽
也表示按鈕,與input按鈕類似
語法:
1按鈕文字或圖像
常用屬性:
·type按鈕的類型,取值: submit(默認)、reset、button
5.3 fieldset和legend標簽
fieldset標簽,對表單元素進行分組
legend標簽,對分組添加標題
七、內嵌框架
1、簡介
使用iframe可以在一個頁面中引用另一個頁面,實現復用、靈活
2、基本用法
語法:
1
常用屬性:
· src:引用的頁面
· width/height寬度/高度 ,像素或百分比
· frameborder是否顯示邊框,取值:1(yes) 0(no)—默認
· scrolling是否顯示滾動條,取值:yes no auto
· name屬性 為框架定義名稱
3、在框架中打開鏈接
1
2
3鏈接的文本或圖像
八、HTML5簡介
1、發展
W3C于1992年12月發布了HTML4.0.1標準
W3C于2014年10月發布了HTML5標準
2、特點
· 取消了過時的標簽,如font、center等,它們僅具有展示外觀的功能
· 增加了一些更具有語義化的標簽,如header、footer、aside等
· 增加了一些新功能標簽,如canvas、audio、video
· 增加了一些表單控件,如email、date、time、url、search等
· 可以直接在瀏覽器中繪畫(canvas),無需flash
· 增加了本地存儲的支持
3、兼容性
http://caniuse.com
提供了各種瀏覽器版本對HTML5和CSS規范的支持度
九、HTML5新增內容
1、結構相關的標簽
用來進行頁面結構布局,本身無任何特殊樣式,需要使用CSS進行樣式設置
· article定義一個獨立的內容,完整的文章
· section定義文檔的章節、段落
· header文章的頭部、頁眉、標題
· footer文章的底部、頁腳、標注
· aside定義側邊欄
· figure圖片區域
· figcaption為圖片區域定義標題
· nav定義導航菜單
結構標簽只是表明各部分的角色,并無實際的外觀樣式,與普通div相同
2、語義相關的標簽
2.1 mark標簽
標注,用來突出顯示文本,默認添加黃色背景
2.2 time標簽
定義日期和時間,便于搜索引擎智能查找
2.3 details和 summary標簽
默認顯示summary中的內容,點擊后顯示details中的內容
注:并不是所有的瀏覽器都兼容,chrome、opera支持、Firefox、IE瀏覽器不支持
2.4 meter標簽
計數儀,表示度量
常用屬性:
· max定義大值,默認為1
· min定義小值,默認為0
· value定義當前值
· high定義限定為高的值
· low定義限定為低的值
· optimum定義佳值
規則:
當value大于high時為綠色
當value在low與high之間時為黃色
當value小于low時為紅色
當value小于low時為綠色
當value在low與high之間時為黃色
當value大于high時為紅色
2.5 progress標簽
進度條,表示運行中的進度
常用屬性:
· value定義當前值
· max定義完成的值
3.表單相關
3.1 新增表單元素
新增以下type類型:
· email接收郵箱
· url接收URL
· tel接收電話號碼,目前僅在移動設備上有效
· search搜索文框
· number/range接收數字/數字滑塊,包含min,max,step屬性
· date/month/week/time/datetime日期時間選擇器,兼容性不好
· color顏色拾取
作用:
· 具有格式校驗的功能
· 可以與移動設備的鍵盤相關聯
3.2新增表單屬性
form標簽的屬性:
· autocomplete是否啟動表單的自動完成功能, 取值:on(默認)、o?
· novalidate提交表單時不進行校驗,默認會進行表單校驗
3.3 新增表單元素的屬性
新增表單元素屬性:input/select/textarea等
· placeholder提示文字
· required是否必填
· autocomplete是否啟用該表單元素的自動完成功能
· autofocus設置初始焦點元素
· pattern使用正則表達式(RegExp后面會講解),進行數據校驗
· list使文本元素具有下拉列表的功能,需要配合datalist和option標簽一起使用
· form可以將表單元素寫在form標簽外面,然后通過該屬性關聯指定的表單
4、多媒體標簽
4.1audio標簽
在頁面中插入音頻,不同的瀏覽器對音頻格式的支持不一樣
audio常用屬性:
· src音頻文件的來源
· controls是否顯示控制面板,默認不顯示
· autoplay是否自動播放,默認不自動播放
· loop是否循環播放
· muted是否靜音
· preload是否預加載,取值:none不預加載、auto預加載(默認)、metadata只加載元數據
如果設置了autoplay屬性,則該屬性無效
可以結合source標簽使用,指定多個音頻文,瀏覽器會檢測并使用第一個可用的音頻文件
4.2 video標簽
在頁面中插入視頻,不同的瀏覽器對視頻格式的支持不一樣
用法與audio標簽基本相同,增加屬性:
· widht/height視頻播放器的寬度/高度
· poster在視頻加載前顯示的圖片
<html>
<body>
<tiele>HTML技術</tiele>
</body>
<body>
大家好,歡迎學習html技術!
</body>
</html>1234567
效果
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-h271e4v6-1593240920352)(C:\Users\lenovo\Desktop\新建文件夾\靜態網頁2\案例\result\案例1.png)]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>標簽</title>
</head>
<body text="blue">
標簽的組成
<br>
html從入門到精通!
<hr>
<h1>標簽的分類</h1>
<hr>
<h2>標簽的分類</h2>
<hr>
<h6>標簽的分類</h6>
<hr>
<span>哈哈</span>嘿嘿
</body>
</html>1234567891011121314151617181920212223
效果
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-jx6zJE1P-1593240920354)(C:\Users\lenovo\Desktop\新建文件夾\靜態網頁2\案例\result\案例2.png)]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
圖書:<<HTML從入門到精通<<
<hr>
北京 上海 廣州
<hr>
在HTML中用<表示<小于號
<hr>
“HTML語言” 或 &qout;HTML語言&qout;
<hr>
版權所有? 2000-2020 高教培訓
<hr>
×關閉符號
</body>
</html>123456789101112131415161718192021222324
效果
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nuFLl3hm-1593240920355)(C:\Users\lenovo\Desktop\新建文件夾\靜態網頁2\案例\result\案例3.png)]
(剩下的下期出)
原文鏈接:https://blog.csdn.net/WanXuang/article/details/106982782?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160513384519724835852804%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=160513384519724835852804&biz_id=&utm_medium=distribute.pc_search_top_result.none-task-code-2~all~top_position~default-1-106982782-12.nonecase&utm_term=html
作者:WanXuang
出處:從CSDN
*請認真填寫需求信息,我們會在24小時內與您取得聯系。