1.什么是浏览器对象模型
BOM :Browser Object Model(浏览器对象模型),浏览器模型提供了独⽴于内容的、可以与浏览器
窗⼝进⾏滑动的对象结构,就是浏览器提供的 API
其主要对象有:
-
window 对象——BOM 的核⼼,是 js 访问浏览器的接⼝,也是 ES 规定的 Global 对象
-
location 对象:提供当前窗⼝中的加载的⽂档有关的信息和⼀些导航功能。既是 window 对象属
性,也是 document 的对象属性
-
navigation 对象:获取浏览器的系统信息
-
screen 对象:⽤来表⽰浏览器窗⼝外部的显⽰器的信息等
-
history 对象:保存⽤⼾上⽹的历史信息
2.浏览器事件
浏览器事件模型中过程分为三个阶段:捕获阶段、目标阶段、冒泡阶段,事件的流转顺序为捕获阶段 -> 目标阶段 ->冒泡阶段,捕获阶段为从外向内捕获,冒泡阶段为从内向外冒泡
通常有以下几种方式触发事件
<button onclick="buttonClick()">按钮</button>
<button id="button">按钮</button>
<script>
var btn = document.getElementById('button');
btn.onclick = function(){
//TODO 一些事情
};
</script>
<button id="button">按钮</button>
<script>
const btn = document.getElementById('button');
btn.addEventListener('click',function(e){
//TODO 一些事情
},false)
</script>
第三种就是事件监听,也就是我们所说的事件模型的捕获阶段,冒泡阶段,其中第三个参数true表示捕获阶段,false表示冒泡阶段,默认不传为false,下面来看个例子。
<div id="parent" class="flex-center">
parent
<p id="child" class="flex-center">
child
<span id='son' class="flex-center">
son
</span>
</p>
</div>
<script>
const parent = document.getElementById("parent");
const child = document.getElementById("child");
const son = document.getElementById("son");
window.addEventListener("click", function (e) {
// e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
console.log("window 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
parent.addEventListener("click", function (e) {
// e.stopPropagation();
// e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
console.log("parent 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
child.addEventListener("click", function (e) {
console.log("child 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
son.addEventListener("click", function (e) {
console.log("son 捕获", e.target.nodeName, e.currentTarget.nodeName);
}, true);
window.addEventListener("click", function (e) {
// e.target.nodeName 指当前点击的元素, e.currentTarget.nodeName绑定监听事件的元素
console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
parent.addEventListener("click", function (e) {
console.log("parent 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
child.addEventListener("click", function (e) {
console.log("child 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
son.addEventListener("click", function (e) {
console.log("son 冒泡", e.target.nodeName, e.currentTarget.nodeName);
}, false);
</script>
当我点击son时候,上述的输出顺序依次为
window 捕获 SPAN undefined
parent 捕获 SPAN DIV
child 捕获 SPAN P
son 捕获 SPAN SPAN
son 冒泡 SPAN SPAN
child 冒泡 SPAN P
parent 冒泡 SPAN DIV
window 冒泡 SPAN undefined
target与currentTarget如备注描述,为什么要讲这两个,因为涉及到接下来的事件委托
运用事件模型的流转来写一个事件委托
<ul id="ul">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
</ul>
<script>
const ul = document.querySelector('ul');
ul.addEventListener('click',function(e){
const target = e.target;
if(target.tagName.toLowerCase() === "li") {
const liList = document.querySelectorAll('li');
const index = Array.prototype.indexOf.call(liList,target);
alert(`内容为${target.innerHTML},索引为${index}`);
}
})
</script>
3.ajax 及 fetch API 详解
ajax
底层使用的是XMLHttpRequest
,fetch
同XMLHttpRequest
非常类似,都是用来做网络请求。但是同复杂的XMLHttpRequest
的API相比,fetch
使用了Promise
,这让它使用起来更加简洁,从而避免陷入”回调地狱”。
1.使用XMLHttpRequest实现一个请求
let xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:3000/test');
xhr.onreadystatechange = function () {
if(xhr.status !== 4) return;
if(xhr.status === 200 || xhr.status === 304){
console.log(xhr.responseText);
}else{
console.log('HTTP Request Error',xhr.status,xhr.statusText);
}
}
xhr.timeout = 3000;
xhr.ontimeout = function() {
console.log('request timeout',xhr.responseURL);
}
xhr.send();
2.使用fetch实现一个请求
(1).fetch没有超时时间
(2).默认不带cookie
(3).错误不会reject
(4).需要借用AbortController中止fetch
fetch('http://localhost:3000/test',{method:'GET'})
.then(response=>response.json())
.then(json=>console.log(json))
.catch(error=>console.error('报错信息:',error));
3.为fetch设置超时设置,超时后中止请求
const fetchAbsortTimeout = (url,options,timeout=3000) => {
const controller = new AbortController();
options.signal = controller.signal;
return new Promise((resolve,reject)=>{
fetch(url,options)
.then(response=>response.json)
.then(resolve)
.catch(reject)
setTimeout(()=>{
controller.abort();
reject('超时!')
},timeout)
})
}
const requestOptions = {method:'GET'};
fetchAbsortTimeout('http://localhost:3000/test',requestOptions,3000)
.then(json=>{console.log(json)})
.catch(reason=>{console.log('报错信息:',reason)})
△4.衍生一下,写一个通用的异步函数超时处理
const asyncTimeout = (asyncFn,timeout = 3000) =>{
return new Promise((resolve,reject) => {
try{
asyncFn().then(res=>{resolve(res)})
} catch (e) {
throw e;
}
setTimeout(()=>{reject()},timeout);
})
}