事件的触发过程是怎么样的?知道什么是事件代理嘛?
- 事件的触发阶段分为捕获节点、目标阶段、冒泡节点(true为捕获,false为冒泡,默认为false)
node.addEventListener('click',function(){
console.log('click事件')
},true/false)
复制代码
- 可是使用stopPropagation来阻止事件冒泡
- stopImmediatePropagation 同样也能实现阻止事件,但是还能阻止该事件目标执行别的注册事件
- 事件代理(假如我们想要给动态生成的li绑定点击事件,直接绑定非常不好,这时可以直接绑定到他的父级ul上,然后通过判断e.target来判断)
let ul = document.querySelector('#ul')
ul.addEventListener('click', (event) => {
// 通过判断target是否为li来进行相对应的操作。
console.log(event.target);
})
复制代码
跨域
- 浏览器出于安全考虑(防止csrf攻击)是同源策略的。
- 只要协议、端口、域名有一个不相同就是跨域(跨域实际上请求是发出了的,只是浏览器拦截了响应)
跨域的九种方式
- JSONP(不安全,xss攻击)
通过
<script>
标签指向一个需要访问的地址并提供一个回调函数来接收数据当需要通讯时。并且只支持get请求。
//自己封装jsonp
function jsonp({url,params,cb}){
return new Promise((resolve,reject)=>{
let script = document.createElement('script');
window[cb] = function (data) {
resolve(data);
document.body.removeChild(script);
}
params = {...params,cb} // wd=b&cb=show
let arrs = [];
for(let key in params){
arrs.push(`${key}=${params[key]}`);
}
script.src = `${url}?${arrs.join('&')}`;
document.body.appendChild(script);
});
}
复制代码
- cors
主要是在服务器端设置响应头来进行跨域,具体如下
// 设置哪个源可以访问我
res.setHeader('Access-Control-Allow-Origin', origin);
// 允许携带哪个头访问我
res.setHeader('Access-Control-Allow-Headers','name');
// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods','PUT');
// 允许携带cookie
res.setHeader('Access-Control-Allow-Credentials', true);
// 预检的存活时间
res.setHeader('Access-Control-Max-Age',6);
// 允许返回的头
res.setHeader('Access-Control-Expose-Headers', 'name');
if(req.method === 'OPTIONS'){
res.end(); // OPTIONS请求不做任何处理
}
复制代码
- postMessage+iframe
// a.html
<iframe src="http://localhost:4000/b.html" frameborder="0" id="frame" onload="load()"></iframe>
<script>
function load() {
let frame = document.getElementById('frame');
frame.contentWindow.postMessage('我爱你','http://localhost:4000');
window.onmessage = function (e) {
console.log(e.data);
}
}
// b.html
<script>
window.onmessage = function (e) {
console.log(e.data);
e.source.postMessage('我不爱你',e.origin)
}
</script>
复制代码
- window.name + iframe
第一次加载c页面 赋值name 然后改变src重新onload,first为false,可以获取到iframe.contentWindow.name
// a.html
a和b是同域的 http://localhost:3000
c是独立的 http://localhost:4000
a获取c的数据
a先引用c c把值放到window.name,把a引用的地址改到b
<iframe src="http://localhost:4000/c.html" frameborder="0" onload="load()" id="iframe"></iframe>
<script>
let first = true
function load() {
if(first){
let iframe = document.getElementById('iframe');
iframe.src = 'http://localhost:3000/b.html';
first = false;
}else{
console.log(iframe.contentWindow.name);
}
}
</script>
// c.html
<script>
window.name = 'xxx'
</script>
复制代码
- hash+iframe
// a.html
<!-- 路径后面的hash值可以用来通信 -->
<!--a b同域-->
<!-- 目的a想访问c -->
<!-- a给c传一个hash值 c收到hash值后 c把hash值传递给b b将结果放到a的hash值中-->
<iframe src="http://localhost:4000/c.html#iloveyou"></iframe>
<script>
window.onhashchange = function () {
console.log(location.hash);
}
</script>
// b.html
<script>
window.parent.parent.location.hash = location.hash
</script>
// c.html
<script>
console.log(location.hash);
let iframe = document.createElement('iframe');
iframe.src = 'http://localhost:3000/b.html#idontloveyou';
document.body.appendChild(iframe);
</script>
复制代码
- document.domain
该方式只能用于二级域名相同的情况下,比如 a.test.com 和 b.test.com 适用于该方式。只需要给页面添加 document.domain = 'test.com' 表示二级域名都相同就可以实现跨域
- websocket(send,onmessage)
// server.js
let express = require('express');
let app = express();
let WebSocket = require('ws');
let wss = new WebSocket.Server({port:3000});
wss.on('connection',function(ws) {
ws.on('message', function (data) {
console.log(data);
ws.send('我不爱你')
});
})
// 高级api 不兼容 socket.io(一般使用它)
let socket = new WebSocket('ws://localhost:3000');
socket.onopen = function () {
socket.send('我爱你');
}
socket.onmessage = function (e) {
console.log(e.data);
}
复制代码
- nginx代理配置反向代理实现跨域
- http-proxy(具体查看文档,原理就是ajax请求一个服务器a,服务器代理请求b的服务器的数据,最终把b返回的数据返回给ajax)
什么是 Service Worker?
Service Worker 实现缓存功能一般分为三个步骤:首先需要先注册 Service Worker,然后监听到 install 事件以后就可以缓存需要的文件,那么在下次用户访问的时候就可以通过拦截请求的方式查询是否存在缓存,存在缓存的话就可以直接读取缓存文件,否则就去请求数据。以下是这个步骤的实现
// index.js
if (navigator.serviceWorker) {
navigator.serviceWorker
.register('sw.js')
.then(function(registration) {
console.log('service worker 注册成功')
})
.catch(function(err) {
console.log('servcie worker 注册失败')
})
}
// sw.js
// 监听 `install` 事件,回调中缓存所需文件
self.addEventListener('install', e => {
e.waitUntil(
caches.open('my-cache').then(function(cache) {
return cache.addAll(['./index.html', './index.js'])
})
)
})
// 拦截所有请求事件
// 如果缓存中已经有请求的数据就直接用缓存,否则去请求数据
self.addEventListener('fetch', e => {
e.respondWith(
caches.match(e.request).then(function(response) {
if (response) {
return response
}
console.log('fetch source')
})
)
})
复制代码