【前端指南】Dom操作、Ajax请求以及跨域解决方案

DOM操作

  • Document Object Model(文档对象模型)
    • DOM 操作,可以简单理解成“元素操作”
具体DOM操作
  • 更新:更新该DOM结点的内容,相当于更新了该DOM结点表示的HTML内容

  • 遍历:遍历该DOM节点下的子节点,以便进行进一步操作

  • 添加:在该DOM节点下新增一个子节点,相当于动态增加了一个HTML节点

  • 删除:将该节点从HTML中删除,相当于删掉了该DOM节点的内容以及他包含的所有子节点

  • 拿到这个DOM节点:

    • document.getElementById()
    • document.getElementsByTagName()
    • CSS选择器document.getElementsByClassName()
      • ID在HTML文档中是唯一的
更新DOM
  • 一种是修改innerHTML属性,这个方式非常强大,不但可以修改一个DOM节点的文本内容,还可以直接通过HTML片段修改DOM节点内部的子树
    • 用innerHTML时要注意,是否需要写入HTML。如果写入的字符串是通过网络拿到的,要注意对字符编码来避免XSS攻击
  • 第二种是修改innerText或textContent属性,这样可以自动对字符串进行HTML编码,保证无法设置任何HTML标签
  • 两者区别:两者的区别在于读取属性时,innerText不返回隐藏元素的文本,而textContent返回所有文本
插入DOM
  • 如果DOM结点是空的:innerHTML = ‘child’,就可以修改DOM节点的内容,相当于“插入”了新的DOM节点
  • 如果DOM结点不是空的:
    • 一个是使用appendChild,把一个子节点添加到父节点的最后一个子节点
      • 把<p id=“js”>JavaScript</p>添加到<div id=“list”>的最后一项
var
    js = document.getElementById('js'),
    list = document.getElementById('list');
list.appendChild(js);
  • parentElement.insertBefore(newElement, referenceElement);,子节点会插入到referenceElement之前
删除DOM
  • 删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置
  • 要删除一个节点,首先要获得该节点本身以及它的父节点,然后,调用父节点的removeChild把自己删掉

Ajax

定义
  1. 什么是Ajax?
    • 异步就按JavaScript和XML,是一种用于创建快速动态网页的技术,通过与服务器进行少量数据交换,Ajax可以使网页实现异步更新,这意味着可以在不重新加载整个页面的情况下,对网页的某部分进行更新
      • 传统的网页-不使用Ajax如果需要更新内容,必须重新加载整个网页面
  2. 同步与异步的区别
  • 同步提交:当用户发送请求时,当前网页不可以使用,服务器响应页面到客户端,相应完成,用户才可以使用页面
  • 异步提交:当用户发送请求时,当前页面还可以继续使用,当一部请求的数据响应给页面,页面把数据显示出来
  1. Ajax工作原理
  • 客户端发送请求,请求交给xhr
  • xhr把请求提交给服务器,服务期进行业务处理,
  • 服务器响应数据交给xhr对象
  • xhr对象接收数据,由JavaScript把数据写到页面上
实现Ajax的基本步骤-异步调用和局部刷新
  1. 创建XMLHttpRequest对象,即创建一个异步调用对象
  2. 创建一个新的HTTP请求,并制定该HTTP请求、URL及验证信息
  3. 设置响应HTTP请求状态变化的函数
  4. 发送HTTP请求
  5. 获取异步调用返回的数据
  6. 使用JavaScript和DOM实现局部刷新

代码中的参数解释如下所示:

  • method:该参数用于指定HTTP的请求方法,一共有get、post、head、put、delete五种方法,常用的方法为get和post
  • URL:该参数用于指定HTTP请求的URL地址,可以是绝对URL,也可以是相对URL
  • flag:该参数为可选,参数值为布尔型。该参数用于指定是否使用异步方式。true表示异步、false表示同步,默认为true
  • name:该参数为可选参数,用于输入用户名。如果服务器需要验证,则必须使用该参数
  • password:该参数为可选,用于输入密码。若服务器需要验证,则必须使用该参数

注意:如果HTML文件放在Web服务器上,在Netscape浏览器中的JavaScript安全机制不允许与本机之外的主机进行通信。也就是说,使用open()方法只能打开与HTML文件在同一个服务器上的文件。而在IE浏览器中则无此限制(虽然可以打开其他服务器上的文件,但也会有警告提示)

  1. 未初始化状态。在创建完XMLHttpRequest对象时,该对象处于未初始化状态,此时XMLHttpRequest对象的readyState属性值为0
  2. 初始化状态。在创建完XMLHttpRequest对象后使用open()方法创建了HTTP请求时,该对象处于初始化状态。此时XMLHttpRequest对象的readyState属性值为1
  3. 发送数据状态。在初始化XMLHttpRequest对象后,使用send()方法发送数据时,该对象处于发送数据状态,此时XMLHttpRequest对象的readyState属性值为2
  4. 接收数据状态。Web服务器接收完数据并进行处理完毕之后,向客户端传送返回的结果。此时,XMLHttpRequest对象处于接收数据状态,XMLHttpRequest对象的readyState属性值为3
  5. 完成状态。XMLHttpRequest对象接收数据完毕后,进入完成状态,此时XMLHttpRequest对象的readyState属性值为4。此时接收完毕后的数据存入在客户端计算机的内存中,可以使用responseText属性或responseXml属性来获取数据
完整Ajax实例
<html>
<head>
<title>AJAX实例</title>
<script language="javascript" type="text/javascript">   
    function ajaxHttpRequestFunc(){
		let xmlHttpRequest;  // 创建XMLHttpRequest对象,即一个用于保存异步调用对象的变量
		if(window.ActiveXObject){ // IE浏览器的创建方式
            xmlHttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
        }else if(window.XMLHttpRequest){ // Netscape浏览器中的创建方式
            xmlHttpRequest = new XMLHttpRequest();
        }
		xmlHttpRequest.onreadystatechange=function(){ // 设置响应http请求状态变化的事件
            console.log('请求过程', xmlHttpRequest.readyState);
			if(xmlHttpRequest.readyState == 4){ // 判断异步调用是否成功,若成功开始局部更新数据
				console.log('状态码为', xmlHttpRequest.status);
				if(xmlHttpRequest.status == 200) {
					console.log('异步调用返回的数据为:', xmlHttpRequest .responseText);
					document.getElementById("myDiv").innerHTML = xmlHttpRequest .responseText; // 局部刷新数据到页面
				} else { // 如果异步调用未成功,弹出警告框,并显示错误状态码
					alert("error:HTTP状态码为:"+xmlHttpRequest.status);
				}
			}
		}
		xmlHttpRequest.open("GET","https://www.runoob.com/try/ajax/ajax_info.txt",true); // 创建http请求,并指定请求得方法(get)、url(https://www.runoob.com/try/ajax/ajax_info.txt)以及验证信息
		xmlHttpRequest.send(null); // 发送请求
    }
</script>
</head>
<body>
    <div id="myDiv">原数据</div>
    <input type = "button" value = "更新数据" onclick = "ajaxHttpRequestFunc()">
</body>
</html>

常见的前端跨域解决方案

什么是跨域?
  • 跨域是指浏览器允许向服务器发送跨域请求, 从而克服Ajax只能同源使用的限制
什么是同源策略?
  • 一种约定,指“协议+域名+端口”三者相同,即使两个不同的域名指向同一个IP地址,也非同源
  • 同源限制以下操作:
    • cookie、localStorage和indexDB无法获取
    • DOM和JS对象无法获取
    • AJAX请求不能发送
常见跨域场景
URL说明是否允许通信
http://www.domain.com/a.js
http://www.domain.com/b.js
http://www.domain.com/lab/c.js
同一域名,不同文件或路径允许
http://www.domain.com:8000/a.js
http://www.domain.com/b.js
同一域名,不同端口不允许
http://www.domain.com/a.js
https://www.domain.com/b.js
同一域名,不同协议不允许
http://www.domain.com/a.js
http://192.168.4.12/b.js
域名和域名对应相同ip不允许
http://www.domain.com/a.js
http://x.domain.com/b.js
http://domain.com/c.js
主域相同,子域不同不允许
http://www.domain1.com/a.js
http://www.domain2.com/b.js
不同域名不允许
六种跨域解决方案
JONSP跨域

原理:利用script标签没有跨域限制,通过script标签src属性,发送带有callback参数的GET请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据

  1. 原生JS实现
 <script>
    var script = document.createElement('script');
    script.type = 'text/javascript';
 
    // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
    script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
    document.head.appendChild(script);
 
    // 回调执行函数
    function handleCallback(res) {
        alert(JSON.stringify(res));
    }
 </script>

服务端返回如下:
handleCallback({“success”: true, “user”: “admin”})

  1. jQuery Ajax实现:
$.ajax({
    url: 'http://www.domain2.com:8080/login',
    type: 'get',
    dataType: 'jsonp',  // 请求方式为jsonp
    jsonpCallback: "handleCallback",  // 自定义回调函数名
    data: {}
});
  1. Vue axios实现
this.$http = axios;
this.$http.jsonp('http://www.domain2.com:8080/login', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) => {
    console.log(res); 
})
  • jsonp缺点:只能发送get请求
跨域资源共享CORS
  • 允许浏览器向跨源服务器,发出XMLHTTPRequest请求,从而克服了Ajax只能同源使用的限制,CORS需要浏览器和服务器同时支持
  • 只要同时满足以下两个条件,就属于简单请求
    1. 使用下列方法之一
      • head
      • get
      • post
    2. 请求的header是
      • Accept
      • Accept-Language
      • Content-Language
      • Content-Type:只限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain
    • 不同时满足上面两个条件,就属于非简单请求
response.addHeader(‘Access-Control-Allow-Origin:*’);//允许所有来源访问 
response.addHeader(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式
Nginx代理跨域
  • 通过配置文件设置请求响应头Access-Control-Allow-Origin…等字段
  • www.baidu.com/index.html需要调用www.sina.com/server.php,可以写一个接口www.baidu.com/server.php,由这个接口在后端去调用www.sina.com/server.php并拿到返回值,然后再返回给index.html
document.domain
  • 主要解决:window之间不能交互操作的跨域情况,且只能适用于主域相同子域不同的情况
  • 优点:可以实现不同window之间的相互访问和操作
  • 缺点:
    • 只适用于window之间的通信,不能用于xhr
    • 只能在主域相同且子域不同的情况下使用
  • 步骤:
    1. 在1页面中设置主域
    2. 在2页面中设置主域
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
<script type="text/javascript">
    document.domain = 'example.com';//设置成主域
    function test(){
        alert(document.getElementById('iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
    }
</script>
<script type="text/javascript">
    document.domain = 'example.com';//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
</script>
window.name
  • 关键点:window.name 在页面的生命周期中共享一个window.name
  • 优点:
    • 最简单的利用了浏览器的特性来做到不同域之间的数据传递
    • 不需要前端和后端的特殊配置
  • 缺点:
    • 大小限制:window.name最大size是2M左右,不同浏览器中会有不同约定
  • 安全性:页面所有window都可以修改,不安全
  • 数据类型:限于字符串,如果是对象或者其他会自动被转化为字符串
  • 使用方式:直接修改window.name即可
postMessage
  • 关键点:通过window.postMessage的方式进行使用,并可以监听其发送的消息
  • 优点:不需要后端介入就可以做到跨域,一个函数外加两个参数(请求url, 发送数据)就可以搞定;移动端兼容性好
  • 缺点:无法做到一对一的传递方式:发出消息相当于一个广播的过程,该页面总有onmessage都会受到,所以需要做到消息的判断
  • 安全性问题:
    • 三方可以通过截获,注入html或者脚本的形式监听到消息,从而到达篡改的效果,一定要做好相关限制
    • 发送的数据会通过结构化克隆算法进行序列化,只有满足该算法要求的算法才能够被解析,否则会报错
  • 使用方式:通信的函数,sendMessage负责发送消息,bindEvent负责消息的监听并处理
Storage.prototype.sendMessage_=function(type,params,fn){
   if(this.topWindow){
       this.handleCookie_(type,params,fn);
       return;
   }
   var eventId = this.addToQueue_(fn,type);
   var storageIframe = document.getElementById('mip-storage-iframe');
   var element = document.createElement("a");
   element.href = this.origin;
   var origin = element.href.slice(0,element.href.indexOf(element.pathname)+1);
   storageIframe.contentWindow.postMessage({
       type:type,
       params:params,
       eventId:eventId
   },origin);
}
Storage.prototype.bindEvent_=function(){
   window.onmessage = function(res){
       //判断消息来源
       if(window == res.source.window.parent &&
           res.data.type === this.messageType.RES &&
           window.location.href.match(res.origin.host).length >0){
           var fn = this.eventQueue[res.data.eventId];
           fn && fn();
           delete this.eventQueue[res.data.eventId];
           var isEmpty = true;
           for(var t in this.eventQueue){
               isEmpty = false;
           }
           if(isEmpty){
               this.id = 0;
           }
       }
   }.bind(this);
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值