备战前端面试—JS-Web-API篇
Ajax
XHR 的概念
考点1:XHR 对象
XHR 是什么?
XHR(XMLHttpRequest)
即 XMLHttpRequest 对象。XMLHttpRequest 对象提供了对 HTTP 协议的完全的访问,包括做出 POST 和 HEAD 请求以及普通的 GET 请求的能力。它可以操作任何数据,而不仅仅是 XML 格式。XMLHttpRequest 可以同步或异步地返回 Web 服务器的响应,并且能够以文本或者一个 DOM 文档的形式返回内容。
XHR 提供了哪些常用的方法?
XHR 分为同步和异步模式。
异步模式:
xhr.open(method, URL, [async, user, password])
此方法指定了请求的主要参数:
- method:请求的方法,限定为
GET
、POST
、HEAD
之一。 - URL:要请求的 url。通常是字符串,也可以是 url 对象(如果有搜索参数,避免转码问题)。
- async:如果显示地设定为 false,将采用同步模式。
- user,password:HTTP 基本身份验证(如果需要的话)的登录名和密码。
发送请求:
xhr.send([body])
body:可选参数,请求体。
之后需要监听 XHR 事件,以作出响应:
这三个事件是最常用的:
- load:当请求完成(
200
、500
),并且响应已完全下载。 - error:当无法发送请求,如网络中断、URL 无效。
- progress:在下载期间定期触发,报告当前进度。
一旦有了结果,可以从 XHR 的以下属性中获得结果:
- status:HTTP 状态码(一个数字):
200
,404
,403
等,如果出现非 HTTP 错误,则为0
。 - statusText:HTTP 状态消息(一个字符串):状态码为
200
对应于OK
,404
对应于Not Found
,403
对应于Forbidden
。 - response:服务器的响应体。
可以设置超时时间,如果给定时间内请求没有成功执行,请求就会取消,同时触发 timeout 事件:
xhr.timeout = 10000; // timeout 单位是 ms,此处即 10 秒
我们可以使用
xhr.responseType
属性来设置响应格式:""
(默认)—— 响应格式为字符串,"text"
—— 响应格式为字符串,"arraybuffer"
—— 响应格式为ArrayBuffer
"blob"
—— 响应格式为Blob
"document"
—— 响应格式为 XML document(可以使用 XPath 和其他 XML 方法),"json"
—— 响应格式为 JSON(自动解析)。
我们可以随时终止请求。调用
xhr.abort()
即可。
同步请求:
如果在
open
方法中将第三个参数async
设置为false
,那么请求就会以同步的方式进行。JS 脚本将在
send()
处暂停,并在收到响应后恢复执行。这会阻塞页面加载。基于这些原因,同步请求使用的非常少,几乎从不使用。- method:请求的方法,限定为
AJAX 的相关应用
考点1: jQuery Ajax
什么是 Ajax?如何使用?
AJAX(Async Javascript and XML)
即异步的
JavaScript
和XML
,是一种创建交互式网页应用的网页开发技术,可以在不重新加载整个网页的情况下,与服务器交换数据,并且更新部分网页。jquery 的 ajax:
$.ajax({ type: 'POST', url: url, data: data, dataType: dataType, success: function () {}, error: function () {} });
Ajax 的原理是什么?如何实现?
ajax 原理简单来说是通过 XHR 对象向服务器发送异步请求,同时在接收到响应后,使用 JS 操作 DOM 更新页面。
实现过程:
创建核心对象 XHR
const xhr = new XMLHttpRequest()
通过 XHR 的 open 方法与服务器建立连接
xhr.open(method, url, [async][, user][, password])
构建请求所需的内容,通过 send 方法将请求发送给服务器
xhr.send([body])
通过 XHR 对象的 onreadystatechange 事件监听服务端通信状态
关于
XMLHttpRequest.readyState
属性有五个状态:0:UNSET,未打开,open 方法还未调用
1:OPEND,未发送,send 方法还未调用
2:HEADERS_RECEIVED,已获取响应头,服务端已返回响应头和响应状态
3:LOADING,下载响应体,响应体下载中,responseText 已获取部分内容
4:DONE,请求结束,整个请求过程完毕
接收并处理服务端响应的数据结果
将处理结果更新到
HTML
页面中
封装以后的 ajax 代码:
function ajax(options) { const xhr = new XMLHttpRequest(); //初始化配置 options = options || {}; options.type = (options.type || "GET").toUpperCase(); options.dataType = options.dataType || "json"; const params = options.data; //发送请求 if (options.type === "GET") { xhr.open("GET", options.url + "?" + params, true); xhr.send(null); } else if (options.type === "POST") { xhr.open("POST", options.url, true); xhr.send(params); } //接收请求 xhr.onreadystatechange = function () { //请求完成 if (xhr.readyState === 4) { let status = xhr.status; if (status >= 200 && status < 300) { options.success && options.success(xhr.responseText, xhr.responseXML); } else { options.error && options.error(status); } } }; } ajax({ type: "POST", dataType: "json", data: {}, url: "https://xxxxx", success: function () {}, error: function () {}, });
考点2:Fetch API
什么是 fetch?如何使用?
fetch 是脱离了 XHR 的全新 API,是 ajax 的替代方案。解决了 ajax 在使用时必须引入 jQuery 的缺陷,并且是基于 Promise 的实现,符合关注分离,没有将输入、输出和用事件来跟踪的状态混杂在一个对象里,更加人性化,同时写法简单方便。
优势:
- 更加底层,提供的API丰富(request, response)
- 脱离了 XHR,是ES规范里新的实现方式
- 支持 async/await 以书写同步代码的方式完成异步操作
缺点:
- 是一个低层次的 API,使用时仍然需要封装。
- 默认不带 cookie,需要进行设置。
- 只有网络错误能得到处理,服务器返回错误码时不会 reject。
// Example POST method implementation: postData('http://example.com/answer', {answer: 42}) .then(data => console.log(data)) // JSON from `response.json()` call .catch(error => console.error(error)) function postData(url, data) { // Default options are marked with * return fetch(url, { body: JSON.stringify(data), // must match 'Content-Type' header cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'same-origin', // include, same-origin, *omit headers: { 'user-agent': 'Mozilla/4.0 MDN Example', 'content-type': 'application/json' }, method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, cors, *same-origin redirect: 'follow', // manual, *follow, error referrer: 'no-referrer', // *client, no-referrer }) .then(response => response.json()) // parses response to JSON }
考点3:Axios
什么是 axios?如何使用?
axios 是对原生 XHR 的封装,ajax 的另一个替代方案。同时也是 Promise 的实现版本,符合最新 ES 规范。可用于 NodeJS 和浏览器。
有以下几条特性:
- 在浏览器中创建 XMLHttpRequests
- 在 node.js 中直接创建 http 请求
- 支持 Promise API
- 支持拦截请求和响应
- 客户端支持防止CSRF(让你的每个请求都带一个从 cookie 中拿到的key)
- 提供了一些并发请求的接口
使用上也简化了,更加灵活:
const config = { url: 'http://api.com', method: 'POST', header: { 'Content-Type': 'application/json' }, data: { name: 'John', age: 22 } } axios(config);
DOM
DOM 操作
考点1:DOM 方法
常用的原生 DOM 操作方法有哪些?
创建节点:
createElement
:创建新元素const divEl = document.createElement("div");
createTextNode
:创建文本节点const textEl = document.createTextNode("content");
createDocumentFragment
:创建文档碎片,是更轻量级的文档const fragment = document.createDocumentFragment();
createAttribute
:创建属性节点,可以是自定义属性const dataAttribute = document.createAttribute('custom');
查询节点:
querySelector
:传入有效的 css 选择器,即可选中首个 DOM 元素document.querySelector('.element') document.querySelector('#element') document.querySelector('div') document.querySelector('[name="username"]') document.querySelector('div + p > span')
querySelectorAll
:返回一个包含节点子树内所有匹配的元素节点列表,没有则返回空列表。const container = document.querySelector("#test"); const matches = container.querySelectorAll("div.highlighted > p");
getElementsBy系列
:document.getElementById('id属性值');//返回拥有指定id的对象的引用 document.getElementsByClassName('class属性值');//返回拥有指定class的对象集合 document.getElementsByTagName('标签名');//返回拥有指定标签名的对象集合 document.getElementsByName('name属性值'); //返回拥有指定名称的对象结合
更新节点:
innerHTML
:可修改节点内部的子树// 获取<p id="p">...</p > var p = document.getElementById('p'); // 设置文本为abc: p.innerHTML = 'ABC'; // <p id="p">ABC</p > // 设置HTML: p.innerHTML = 'ABC <span style="color:red">RED</span> XYZ'; // <p>...</p >的内部结构已修改
innerText、textContent
:自动对文本进行 HTML 编码// 获取<p id="p-id">...</p > var p = document.getElementById('p-id'); // 设置文本: p.innerText = '<script>alert("Hi")</script>'; // HTML被自动编码,无法设置<script>节点: // <p id="p-id"><script>alert("Hi")</script></p >
两者的区别在于读取属性时,
innerText
不返回隐藏元素的文本,而textContent
返回所有文本style
:DOM
节点的style
属性对应所有的CSS
,可以直接获取或设置。遇到-
需要转化为驼峰命名// 获取<p id="p-id">...</p > const p = document.getElementById('p-id'); // 设置CSS: p.style.color = '#ff0000'; p.style.fontSize = '20px'; // 驼峰命名 p.style.paddingTop = '2em';
添加节点:
innerHTML
:如果是空节点,会添加新节点。否则会直接替换掉原来的所有子节点const div = document.createElement('div'); div.innerHTML = '<span>child</span>'
appendChild
:把一个子节点添加到父节点的末尾,如果该节点已存在,会先删除再插入const list = document.getElementById('list'), const haskell = document.createElement('p'); haskell.id = 'haskell'; haskell.innerText = 'Haskell'; list.appendChild(haskell);
insertBefore
:把子节点插入到父节点中指定的节点之前parentElement.insertBefore(newElement, referenceElement)
setAttribute
:在指定元素中添加一个属性节点,如果元素中已有该属性改变属性值const div = document.getElementById('id') div.setAttribute('class', 'white');//第一个参数属性名,第二个参数属性值。
删除节点:
removeChild
:首先要获得该节点本身以及它的父节点,然后,调用父节点的removeChild
把它删掉// 拿到待删除节点: const self = document.getElementById('to-be-removed'); // 拿到父节点: const parent = self.parentElement; // 删除: const removed = parent.removeChild(self); removed === self; // true
删除后的节点虽然不在文档树中了,但其实它还在内存中,可以随时再次被添加到别的位置。
DOM 渲染
考点1:DOM 渲染方式
什么是 SPA?与传统 web 开发有什么区别?
SPA(single page application)
即单页面应用。是一种客户端渲染方式。服务端返回宿主 html 模板,再由 JS 操作 DOM 渲染页面,请求数据。传统 web 开发,网页内容在服务端渲染完成,⼀次性传输到浏览器。
SPA
在用户的角度提供了更优秀的交互体验,从开发者的角度上也减少了代码编写的工作量,提高了工作效率。目前主流的网站开发方式均为SPA
。什么是 SSR?SSR 解决了什么问题?
SSR(server-side rendering)
即服务端渲染,指由服务端完成 html 结构的拼接,发送到浏览器,再将其激活(为其绑定状态与事件)成为可交互页面的过程。由后端渲染首屏 dom 结构后返回,前端拿到首屏结构及
SPA
结构,应用激活后仍按SPA
方式运行。SSR
在SPA
的基础上进行改良,主要解决了以下问题:seo
。搜索引擎优先爬取页面 html 结构,使用SSR
时,服务端已经生成了业务相关的 html,有利于seo
。- 首屏直接渲染。用户无需等待所有 JS 加载,由服务端返回首屏页面。
同时也存在缺点:
- 增加项目复杂度
- 库的支持不友好
- 代码兼容问题
- 服务端负载变大
考点2:首屏和白屏
首屏和白屏是什么?如何计算?
白屏时间:
从输入 URL 到浏览器开始渲染
<body>
标签或者解析完<head>
标签(对应DOMContentLoaded
结束)的这段时间就是白屏时间。计算方式:
DOMContentLoadedEventEnd - fetchStart
首屏时间:
从输入 URL 到浏览器中当前视口的内容渲染完毕,呈现出具体画面的这段时间就是首屏时间。
计算方式:参考阿里ARMS,使用ARMS的计算方法,将可见dom元素数量增长最快的时间点作为首屏时间。
DOM 事件
考点1:事件与事件流
什么是事件?什么是事件流?
JS 和 html 之间的交互是通过事件实现的。事件就是用户或浏览器执行的某种操作,比如鼠标点击、移入移出。
当事件发生时,浏览器会创建一个事件对象
event
,并将详细信息放入其中,作为参数传递给事件处理程序。<input type="button" value="Click me" id="elem"> <script> elem.onclick = function(event) { // 显示事件类型、元素和点击的坐标 alert(event.type + " at " + event.currentTarget); alert("Coordinates: " + event.clientX + ":" + event.clientY); }; </script>
DOM 结构是一个以 document 为根节点的多叉树。当一个 html 元素产生事件时,该事件会在该元素节点与根节点之间传播,在其经过的路径上所有节点都会接收到该事件,这个传播过程就是 DOM 事件流。事件流描述的是从页面中接收事件的顺序。
考点2:事件模型
事件模型有哪几种?
事件模型可以分为三种:
- 原始事件模型(DOM0级)
- 标准事件模型(DOM2级)
- IE事件模型(基本不用)
原始事件模型:
事件绑定监听函数比较简单,有两种方式:
- HTML代码中直接绑定
<input type="button" onclick="fun()">
- 通过
JS
代码绑定
var btn = document.getElementById('.btn'); btn.onclick = fun;
特性:
- 绑定速度快
DOM0
级事件具有很好的跨浏览器优势,会以最快的速度绑定,但由于绑定速度太快,可能页面还未完全加载出来,以至于事件可能无法正常运行。- 只支持冒泡,不支持捕获
- 同一个类型的事件只能绑定一次
标准事件模型:
一个事件分三个阶段:
- 事件捕获阶段:事件从
document
一直向下传播到目标元素,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。(很少被使用) - 事件处理阶段:事件到达目标元素,触发目标元素的监听函数。
- 事件冒泡阶段:事件从目标元素冒泡到
document
,依次检查经过的节点是否绑定了事件监听函数,如果有则执行。
事件捕获:
使用
on<event>
属性或使用 HTML 特性(attribute)或使用两个参数的addEventListener(event, handler)
添加的处理程序,对捕获一无所知,它们仅在第二阶段和第三阶段运行。为了在捕获阶段捕获事件,我们需要将处理程序的
capture
选项设置为true
:elem.addEventListener(..., {capture: true}) // 或者,用 {capture: true} 的别名 "true" elem.addEventListener(..., true)
capture
选项有两个可能的值:- 如果为
false
(默认值),则在冒泡阶段设置处理程序。 - 如果为
true
,则在捕获阶段设置处理程序。
事件处理:
引发事件的那个嵌套层级最深的元素被称为目标元素,可以通过
event.target
访问。事件冒泡:
当一个事件发生在一个元素上,将会从目标元素冒泡到
document
。它会首先运行在该元素上的处理程序,然后运行其父元素上的处理程序,然后一直向上到其他祖先上的处理程序。父元素上的处理程序始终可以获取事件实际发生位置的详细信息。通常,它会一直上升到
<html>
,然后再到document
对象,有些事件甚至会到达window
,它们会调用路径上所有的处理程序。但是任意处理程序都可以决定事件已经被完全处理,并停止冒泡。
用于停止冒泡的方法是
event.stopPropagation()
。如果一个元素在一个事件上有多个处理程序,即使其中一个停止冒泡,其他处理程序仍会执行。
有一个
event.stopImmediatePropagation()
方法,可以用于停止冒泡,并阻止当前元素上的处理程序运行。使用该方法之后,其他处理程序就不会被执行。
IE事件模型:
共有两个过程:
- 事件处理阶段:事件到达目标元素, 触发目标元素的监听函数。
- 事件冒泡阶段:事件从目标元素冒泡到
document
, 依次检查经过的节点是否绑定了事件监听函数,如果有则执行
解释下什么是事件委托?应用场景?
事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown……)的处理委托给另一个元素。
事件委托,会把一个或者一组元素的事件委托到它的父层或者更外层元素上,真正绑定事件的是外层元素,而不是目标元素。当事件响应到目标元素上时,会通过事件冒泡机制从而触发它的外层元素的绑定事件,然后在外层元素上去执行函数。父元素可以通过
event.target
访问目标元素。优点:
- 简化初始化并节省内存:无需添加许多处理程序。
- 更少的代码:添加或移除元素时,无需添加/移除处理程序。
- DOM 修改 :我们可以使用 innerHTML 等,来批量添加/移除元素。
局限性:
- 首先,事件必须冒泡。而有些事件不会冒泡(
focus
、blur
)。此外,低级别的处理程序不应该使用event.stopPropagation()
。 - 其次,委托可能会增加 CPU 负载,因为容器级别的处理程序会对容器中任意位置的事件做出反应,而不管我们是否对该事件感兴趣。
mousemove
、mouseout
这样的事件,虽然有事件冒泡,但是只能不断通过位置去计算定位,对性能消耗高,因此也是不适合于事件委托的。
应用场景:
如果我们有一个列表,列表之中有大量的列表项,我们需要在点击列表项的时候响应一个事件,如果给每个列表项一一都绑定一个函数,那对于内存消耗是非常大的。这时候就可以事件委托,把点击事件绑定在父级元素
ul
上面,然后执行事件的时候再去匹配目标元素。还有一种场景是上述列表项并不多,我们给每个列表项都绑定了事件,但是如果用户能够随时动态的增加或者去除列表项元素,那么在每一次改变的时候都需要重新给新增的元素绑定事件,给即将删去的元素解绑事件,如果用了事件委托就没有这种麻烦了,因为事件是绑定在父层的,和目标元素的增减是没有关系的,执行到目标元素是在真正响应执行事件函数的过程中去匹配的。
BOM
BOM 概念
考点1:BOM 与 DOM
说说你对 BOM 的理解?
BOM(Browser Object Model)
,浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象。其作用就是和浏览器进行一些交互操作。如前进后退、滚动条上下滚动、刷新、浏览器窗口变化,以及获取客户的一些信息如:浏览器版本,屏幕分辨率。
浏览器的全部内容可以看成
DOM
,而整个浏览器可以看成BOM
。DOM
的顶级对象是document
,而BOM
的顶级对象是window
。
考点2:页面生命周期
说说 HTML 页面的生命周期?
HTML 页面的生命周期包含三个重要事件:
DOMContentLoaded
—— 浏览器已完全加载 HTML,并构建了 DOM 树,但像<img>
和样式表之类的外部资源可能尚未加载完成。load
—— 浏览器不仅加载完成了 HTML,还加载完成了所有外部资源:图片,样式等。beforeunload/unload
—— 当用户正在离开页面时。
DOMContentLoaded
事件:触发时机:
发生在
document
对象上。在 DOM 树构建完毕后,就会触发此事件,此时页面只包含基本的 DOM 结构。当浏览器处理一个 HTML 文档,并在文档中遇到
<script>
标签时,就会在继续构建 DOM 之前运行它。这是一种防范措施,因为脚本可能想要修改 DOM,甚至对其执行document.write
操作,所以DOMContentLoaded
必须等待脚本执行结束。外部样式表不会影响 DOM,因此DOMContentLoaded
不会等待它们。<script> function ready() { alert('DOM is ready'); // 图片目前尚未加载完成(除非已经被缓存),所以图片的大小为 0x0 alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`); } document.addEventListener("DOMContentLoaded", ready); </script> <img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">
但如果在样式后面有一个脚本,那么该脚本必须等待样式表加载完成:
<link type="text/css" rel="stylesheet" href="style.css"> <script> // 在样式表加载完成之前,脚本都不会执行 alert(getComputedStyle(document.body).marginTop); </script>
当
DOMContentLoaded
等待脚本时,它现在也在等待脚本前面的样式。常见的应用场景:
Firefox,Chrome 和 Opera 都会在
DOMContentLoaded
中自动填充表单。
load
事件:触发时机:
当整个页面的资源(包括图片、样式和其他资源)都加载完毕时,会触发 window 对象上的 load 事件。可以通过
onload
属性获取此事件。<script> window.onload = function() { // 与此相同 window.addEventListener('load', (event) => { alert('Page loaded'); // 此时图片已经加载完成 alert(`Image size: ${img.offsetWidth}x${img.offsetHeight}`); }; </script> <img id="img" src="https://en.js.cx/clipart/train.gif?speed=1&cache=0">
beforeunload
事件:触发时机:
如果访问者触发了离开页面的导航或试图关闭窗口,
beforeunload
处理程序将要求进行更多确认。如果我们要取消事件,浏览器会询问用户是否确定。
window.onbeforeunload = function() { return "There are unsaved changes. Leave now?"; };
unload
事件:触发时机:
当访问者离开页面时,
window
对象上的unload
事件就会被触发。我们可以在那里做一些不涉及延迟的操作,例如关闭相关的弹出窗口。let analyticsData = { /* 带有收集的数据的对象 */ }; window.addEventListener("unload", function() { navigator.sendBeacon("/analytics", JSON.stringify(analyticsData)); });
BOM 对象
考点1:Window 对象
怎么理解 window 对象?
BOM
的核心对象是window
,它表示浏览器的一个实例。在浏览器中,
window
对象有双重角色,即是浏览器窗口的一个接口,又是全局对象。因此所有在全局作用域中声明的变量、函数都会变成
window
对象的属性和方法。如何控制 window 窗口?
关于窗口控制方法如下:
moveBy(x,y)
:从当前位置水平移动窗体x个像素,垂直移动窗体y个像素,x为负数,将向左移动窗体,y为负数,将向上移动窗体moveTo(x,y)
:移动窗体左上角到相对于屏幕左上角的(x,y)点resizeBy(w,h)
:相对窗体当前的大小,宽度调整w个像素,高度调整h个像素。如果参数为负值,将缩小窗体,反之扩大窗体resizeTo(w,h)
:把窗体宽度调整为w个像素,高度调整为h个像素scrollTo(x,y)
:如果有滚动条,将横向滚动条移动到相对于窗体宽度为x个像素的位置,将纵向滚动条移动到相对于窗体高度为y个像素的位置scrollBy(x,y)
: 如果有滚动条,将横向滚动条向左移动x个像素,将纵向滚动条向下移动y个像素
window.open()
既可以导航到一个特定的url
,也可以打开一个新的浏览器窗口如果
window.open()
传递了第二个参数,且该参数是已有窗口或者框架的名称,那么就会在目标窗口加载第一个参数指定的URLwindow.open('htttp://www.vue3js.cn','topFrame') ==> < a href=" " target="topFrame"></ a>
window.open()
会返回新窗口的引用,也就是新窗口的window
对象const myWin = window.open('http://www.vue3js.cn','myWin')
window.close()
仅用于通过window.open()
打开的窗口新创建的
window
对象有一个opener
属性,该属性指向打开他的原始窗口对象
考点2:Location 对象
什么是 location 对象?有什么作用?
Location 对象是浏览器提供的原生对象,提供 URL 相关的信息和操作方法。通过
window.location
和document.location
属性,可以拿到这个对象。location
属性描述如下:属性名 例子 说明 hash “#contents” url中#后面的字符,没有则返回空串 host www.wrox.com:80 服务器名称和端口号 hostname www.wrox.com 域名,不带端口号 href http://www.wrox.com:80/WileyCDA/?q=javascript#contents 完整url pathname “/WileyCDA/“ 服务器下面的文件路径 port 80 url的端口号,没有则为空 protocol http: 使用的协议 search ?q=javascript url的查询字符串,通常为?后面的内容 除了
hash
之外,只要修改location
的一个属性,就会导致页面重新加载新URL
location.reload()
,此方法可以重新刷新当前页面。这个方法会根据最有效的方式刷新页面,如果页面自上一次请求以来没有改变过,页面就会从浏览器缓存中重新加载如果要强制从服务器中重新加载,传递一个参数
true
即可
考点3:History 对象
什么是 history 对象?有什么作用?
history
对象主要用来操作浏览器URL
的历史记录,可以通过参数向前,向后,或者向指定URL
跳转。常用的属性如下:
history.go()
接收一个整数数字或者字符串参数:向最近的一个记录中包含指定字符串的页面跳转
history.go('xxx.com')
当参数为整数数字的时候,正数表示向前跳转指定的页面,负数为向后跳转指定的页面
history.go(3) //向前跳转三个记录 history.go(-1) //向后跳转一个记录
history.forward()
:向前跳转一个页面history.back()
:向后跳转一个页面history.length
:获取历史记录数
了解过 vue-router 吗?history 模式和 hash 模式有什么区别?
hash 模式:
形式上:hash 模式 url 里面永远带着
#
号,开发当中默认使用这个模式。本质是一个浏览器内置的发布订阅,改变 hash 会广播到
onhashchange
事件,可以在window对象上监听这个事件:window.onhashchange = function(event){ console.log(event.oldURL, event.newURL); let hash = location.hash.slice(1); document.body.style.color = hash; }
每次 hash 发生变化,新旧 url 都会被记录下来,从而可以实现前进后退操作。
history 模式:
原理是利用了 history 对象的 API。其中比较重要的两个是
pushState
和replaceState
。history 不是依靠 url 改变来切换路由的,因为 hash 不变的情况下 url 改变不会触发任何事件,所以需要依赖内部实现的发布订阅模式,通知相应的组件。并且这个过程需要实现持久化存储,保证在刷新之后还能停留在当前路由。
使用 history 模式,如果直接输入 URL 回车或者刷新是会发送真实请求的。因此在服务端需要配置重定向返回
index
,再由前端处理路由匹配。
- Post link: https://blog.sticla.top/2021/08/13/front-end-interview-review-js-web-api/
- Copyright Notice: All articles in this blog are licensed under unless otherwise stated.
GitHub Issues