整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

第69节 跨域请求-Web前端开发之JavaScript-零点程序员-王唯

域请求:

现代的所有的浏览器都遵守同源策略,所谓的源指的就是一个域名、一个服务器,同源是指两个脚本拥有相同的域名,不同源指的是不同的域名,同源策略指的是,一个源的脚本不能读取或操作其他源的http响应和cookie,也就是出于安全方面的考虑,页面中的JavaScript无法访问其他服务器上的数据,这就是所谓的“同源策略”。
同源是指协议、域名和端口都一致。

不同源限制的内容:

  • Cookie、LocalStorge、IndexedDb等存储性内容;
  • DOM节点;
  • Ajax请求;

跨域请求时,不同域的服务器是返回了数据的,只不过浏览器拦截了响应数据;同时也说明了跨域并不能完全阻止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方式,发送下列头部:

  • Origin:与简单的请求相同;
  • Access-Control-Request-Method:请求自身使用的方法;
  • Access-Control-Request-Headers:(可选)自定义的头部信息,多个头部以逗号分隔;

以下是一个带有自定义头部customHeader,并使用POST方法发送的数据,如:

  • Origin: http://www.zeronetwork.cn
  • Access-Control-Request-Method: POST
  • Access-Control-Request-Headers: customHeader

发送这个请求后,服务器端可以决定是否允许这种类型的请求,其通过在响应中发送如下头部与浏览器进行沟通:

  • Access-Control-Allow-Origin:与简单的请求相同;
  • Access-Control-Allow-Methods:允许的方法,多个方法以逗号分隔;
  • Access-Control-Allow-Headers:允许的头部,多个头部以逗号分隔;
  • Access-Control-Max-Age:应该将这个Preflight请求缓存多长时间(以秒表示)

例如,允许任何源、POST请求方式、自定义头customHeader以及请求的缓存时间:

  • Access-Control-Allow-Origin: https://www.zeronetwork.cn
  • Access-Control-Allow-Methods: POST
  • Access-Control-Allow-Headers: customHeader
  • Access-Control-Max-Age: 1728000

如:

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" +
"大小:" + 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是从其他域中加载代码执行,如果其他域不安全,很可能会在响应中夹带一些恶意代码;因此在使用不是你自己运维的Web服务时,一定得保证它安全可靠;
  • 其次,只能进行GET请求;
  • 最后,要确定JSONP请求是否失败比较麻烦,虽然HTML5给<script>元素新增了一个onerror事件处理程序,但目前还没有得到任何浏览器支持;

JSONP和AJAX对比:
JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式;但AJAX属于同源策略,采用CORS方案跨域,而JSONP属于非同源策略进行跨域请求;

window.postMessage()方法:

window.postMessage()方法可以安全地实现跨域通信;其是HTML5规范提供的一种受控机制来规避跨域安全限制的方法,采用异步的方式进行有限的通信,既可以用于同域传递消息,也可以用于跨域传递消息;

其应用的场景是:

  • 页面和其打开的新窗口的数据传递;
  • 多窗口之间消息传递;
  • 页面与嵌套的iframe消息传递;

一个窗口可以获得对另一个窗口的引用,比如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]);

  • otherWindow为其他窗口的一个引用;
  • message参数:将要发送到其他window的数据;它将会被结构化克隆算法序列化,即可以不受限制的将数据对象安全的传送给目标窗口而无需自己序列化;
  • targetOrigin:通过窗口的origin属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个URI;
  • transfer参数:可选,是一串和message同时传递的Transferable对象,这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权;

例如: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接口:
代表一段被目标对象接收的消息;
属性:

  • data属性:其保存着由发送者发送的字符串数据;
  • lastEventId属性:表示事件的唯一ID;
  • origin属性:返回一个表示消息发送者来源;
  • ports属性:MessagePort对象数组,表示消息正通过特定通道(数据通道)发送的相关端口;
  • source属性:是一个MessageEventSource对象,代表消息发送者;
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简介

1.HTML是什么?

HTML:htper text markup language超文本标记(标签)语言

由各种标签组成,用来制作网页,告诉浏览器如何显示页面

2.作用

  • 制作网页,控制网页和内容的显示
  • 插入图片、音乐、视频、动画等多媒体
  • 通过链接来检索信息
  • 使用表单获取用户的信息,实现交互

3.版本

w3c:world wide web consortium万维网联盟,制定web技术相关标准和规范的组织,HTML技术hi由w3c制定的标准

两个版本:HTML4.0.1、HTML5.0-----通常H5

官网:http://www.W3shcool.com.cn

4.扩展名

HTML文档是以.html或.htm结尾

二、HTML文档结构

1.基本结构

1.1简介

  • HTML标签是由尖括号括起来的关键词,如,通常是成对出现的,如<html></html>
  • <html>为根标签,包含: <head>头部和<body>主体部分
  • 头部提供关于网页的相关信息,如标题、文档类型、字符编码、关键字等摘要信息
  • 主体部分提供网页的显示内容,真正显示在页面中的内容
  • 合理地进行缩进
  • 标签名不区分大小写,但是一般要用小写

1.2.开发工具

记事本notepad、sublime、Notepad++、Dreamweaver、VScode、Webstorm等

使用步骤:

  1. 新建文件(cltr+N),然后保存(ctrl+s),指定扩展名为.html
  2. 编写HTML代码
  3. 在浏览器中打开文件

使用技巧:

  • 先保存再写代码,否则代码无颜色提示
  • 创建一个文件夹,用于保存所有的网页内容,将文件夹拖拽到sublime中,便于管理
  • 显示/隐藏侧边栏方式1:查看–>侧边栏–>显示/隐藏侧边栏方式2:ctrl+K紧接着按B
  • 显示多栏方式1:查看–>布局–>列数:2列方式2:Alt+shift+2

1.3浏览器

常见的浏览器:IE浏览器微软、chrome谷歌浏览器、fifirefox火狐、safari苹果

浏览器的作用是读取html文件,并以网页的形式来显示

浏览器不会直接显示html标签,而是使用标签来解释网页的内容

2.标签

2.1标签的组成

一个完整的html标签的组成:

<标签名 属性名="属性值">内容</标签名>

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="UTF-8">
		<title>标签</title>
	</head>
	<body  bgcolor="red" text="blue">
		html从入门到精通!
    </body>
</html>
12345678910

属性值要用双撇号括起来,一般用双引号

2.2标签的分类

根据标签是否关闭,分为,关闭型和非关闭型

  • 关闭型:有结束标签,即标签成对出现
<html></html>
<head></head>
<title></title>

非关闭型:没有结束标签

<meta>
<br>
<h1>....<h6>

根据标签是否独占一行,分为块级标签和行级标签

块级标签:显示为块状,独占一行

<h1>大家好</h1>
<hr>

行级标签:在行内显示,可与其他内容在同一行显示

<span></span>

2.3注释

注释在浏览器中不会显示,是用来标注解释html语句,但通过查看源代码的方式可以看到

语法:

<--注释内容-->

2.4实体字符

也称为特殊字符,用于显示一些特殊符号,如<>&空格等

语法:

<&实体字符的名称>

2.5文档类型

在html文档的第一行,使用<!DOCTYPE html>

声明HTML文档的类型用来告诉浏览器页面的文档嘞型,用来制定html版本的规范

目前基本上最常用的html5

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	
</body>
</html>
12345678910

三\常用标签

3.1基本标签

  • 块级标签\亲啊后有明显的间隔 |
    | h1…h5 | 标题标签 | 按照h1到h6逐渐变小.块级标签 |
    | | | |
    | | | |


  • 三、常用标签

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 页面内的锚链接
步骤:

  1. 定义锚点(标记)
  2. 链接锚点
    _self 自身,当前,默认值 _blank新的,空白的 _parent父层框架 _top顶层框架
    目标位置
    1 2 3 4
    1

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. 在跨越的单元格中设置rowspan/colspan属性 2. 将被跨越的单元格删除
    必须要保证每行的实际列数是相同的,否则表格可能会出错乱
    4.高级标签
    4.1caption标签
    表格的标题标签
    4.2thead标签
    表格的头部table head
    4.3th标签
    表格的头部标题table head title
    一般用在thead中,设置头部的标题,替代td标签,与td的区别,th中的文本会加粗且居中显示
    4.4tbody标签
    表格的主体table body
    4.5tfoot标签
    表格的底部table foot




六、表单
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定义佳值

规则:

  1. 如果optimum大于high,则表示值越大越好

当value大于high时为绿色

当value在low与high之间时为黄色

当value小于low时为红色

  1. 如果optimum小于low,则表示值越小越好

当value小于low时为绿色

当value在low与high之间时为黄色

当value大于high时为红色

  1. 当optimum介于low和high之间,则表示值在low和high之间好当value在low与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(默认)、off

· 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在视频加载前显示的图片

案例1hello.html

<html>
	<body>
		<tiele>HTML技术</tiele>
	</body>
	<body>
		大家好,欢迎学习html技术!
	</body>
</html>1234567

效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h271e4v6-1593240920352)(C:\Users\lenovo\Desktop\新建文件夹\静态网页2\案例\result\案例1.png)]

案例2标签的组成.html

<!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)]

案例3实体字符.html

<!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