1.Ajax原理
Ajax的原理簡單來說是在用戶和服務器之間加了—個中間層(AJAX引擎),通過XmlHttpRequest對象來向服務器發異步請求,從服務器獲得數據,然后用javascript來操作DOM而更新頁面。使用戶操作與服務器響應異步化。這其中最關鍵的一步就是從服務器獲得請求數據
Ajax的過程只涉及JavaScript、XMLHttpRequest和DOM。XMLHttpRequest是ajax的核心機制
ajax 有那些優缺點?
優點:
通過異步模式,提升了用戶體驗.
優化了瀏覽器和服務器之間的傳輸,減少不必要的數據往返,減少了帶寬占用.
Ajax在客戶端運行,承擔了一部分本來由服務器承擔的工作,減少了大用戶量下的服務器負載。
Ajax可以實現動態不刷新(局部刷新)
缺點:
安全問題?AJAX暴露了與服務器交互的細節。
對搜索引擎的支持比較弱。
不容易調試。
2 異步加載JS的方式有哪些?
設置<script>屬性 async="async" (一旦腳本可用,則會異步執行)
動態創建?script DOM:document.createElement('script');
XmlHttpRequest?腳本注入
異步加載庫?LABjs
模塊加載器?Sea.js
3 那些操作會造成內存泄漏?
JavaScript 內存泄露指對象在不需要使用它時仍然存在,導致占用的內存不能使用或回收
未使用 var 聲明的全局變量
閉包函數(Closures)
循環引用(兩個對象相互引用)
控制臺日志(console.log)
移除存在綁定事件的DOM元素(IE)
setTimeout?的第一個參數使用字符串而非函數的話,會引發內存泄漏
垃圾回收器定期掃描對象,并計算引用了每個對象的其他對象的數量。如果一個對象的引用數量為 0(沒有其他對象引用過該對象),或對該對象的惟一引用是循環的,那么該對象的內存即可回收
4 說說你對AMD和Commonjs的理解
CommonJS是服務器端模塊的規范,Node.js采用了這個規范。CommonJS規范加載模塊是同步的,也就是說,只有加載完成,才能執行后面的操作。AMD規范則是非同步加載模塊,允許指定回調函數
AMD推薦的風格通過返回一個對象做為模塊對象,CommonJS的風格通過對module.exports或exports的屬性賦值來達到暴露模塊對象的目的
5 常見web安全及防護原理
sql注入原理
就是通過把SQL命令插入到Web表單遞交或輸入域名或頁面請求的查詢字符串,最終達到欺騙服務器執行惡意的SQL命令
總的來說有以下幾點
永遠不要信任用戶的輸入,要對用戶的輸入進行校驗,可以通過正則表達式,或限制長度,對單引號和雙"-"進行轉換等
永遠不要使用動態拼裝SQL,可以使用參數化的SQL或者直接使用存儲過程進行數據查詢存取
永遠不要使用管理員權限的數據庫連接,為每個應用使用單獨的權限有限的數據庫連接
不要把機密信息明文存放,請加密或者hash掉密碼和敏感的信息
XSS原理及防范
Xss(cross-site scripting)攻擊指的是攻擊者往Web頁面里插入惡意html標簽或者javascript代碼。比如:攻擊者在論壇中放一個看似安全的鏈接,騙取用戶點擊后,竊取cookie中的用戶私密信息;或者攻擊者在論壇中加一個惡意表單,當用戶提交表單的時候,卻把信息傳送到攻擊者的服務器中,而不是用戶原本以為的信任站點
XSS防范方法
首先代碼里對用戶輸入的地方和變量都需要仔細檢查長度和對”<”,”>”,”;”,”’”等字符做過濾;其次任何內容寫到頁面之前都必須加以encode,避免不小心把html tag?弄出來。這一個層面做好,至少可以堵住超過一半的XSS 攻擊
XSS與CSRF有什么區別嗎?
XSS是獲取信息,不需要提前知道其他用戶頁面的代碼和數據包。CSRF是代替用戶完成指定的動作,需要知道其他用戶頁面的代碼和數據包。要完成一次CSRF攻擊,受害者必須依次完成兩個步驟
登錄受信任網站A,并在本地生成Cookie
在不登出A的情況下,訪問危險網站B
CSRF的防御
服務端的CSRF方式方法很多樣,但總的思想都是一致的,就是在客戶端頁面增加偽隨機數
通過驗證碼的方法
6 用過哪些設計模式?
工廠模式:
工廠模式解決了重復實例化的問題,但還有一個問題,那就是識別問題
主要好處就是可以消除對象間的耦合,通過使用工程方法而不是new關鍵字
構造函數模式:
使用構造函數的方法,即解決了重復實例化的問題,又解決了對象識別的問題,該模式與工廠模式的不同之處在于
直接將屬性和方法賦值給?this對象;
7 offsetWidth/offsetHeight,clientWidth/clientHeight與scrollWidth/scrollHeight的區別
offsetWidth/offsetHeight返回值包含content + padding + border,效果與e.getBoundingClientRect()相同
clientWidth/clientHeight返回值只包含content + padding,如果有滾動條,也不包含滾動條
scrollWidth/scrollHeight返回值包含content + padding + 溢出內容的尺寸
8 javascript有哪些方法定義對象
對象字面量:?var obj = {};
構造函數:?var obj = new Object();
Object.create():?var obj = Object.create(Object.prototype);
9 你覺得jQuery源碼有哪些寫的好的地方
jquery源碼封裝在一個匿名函數的自執行環境中,有助于防止變量的全局污染,然后通過傳入window對象參數,可以使window對象作為局部變量使用,好處是當jquery中訪問window對象的時候,就不用將作用域鏈退回到頂層作用域了,從而可以更快的訪問window對象。同樣,傳入undefined參數,可以縮短查找undefined時的作用域鏈
jquery將一些原型屬性和方法封裝在了jquery.prototype中,為了縮短名稱,又賦值給了jquery.fn,這是很形象的寫法
有一些數組或對象的方法經常能使用到,jQuery將其保存為局部變量以提高訪問速度
jquery實現的鏈式調用可以節約代碼,所返回的都是同一個對象,可以提高代碼效率
10 Node的應用場景
特點:
1、它是一個Javascript運行環境
2、依賴于Chrome V8引擎進行代碼解釋
3、事件驅動
4、非阻塞I/O
5、單進程,單線程
優點:
高并發(最重要的優點)
缺點:
1、只支持單核CPU,不能充分利用CPU
2、可靠性低,一旦代碼某個環節崩潰,整個系統都崩潰
11 說幾條寫JavaScript的基本規范
不要在同一行聲明多個變量
請使用===/!==來比較true/false或者數值
使用對象字面量替代new Array這種形式
不要使用全局函數
Switch語句必須帶有default分支
If語句必須使用大括號
for-in循環中的變量 應該使用var關鍵字明確限定作用域,從而避免作用域污
12 js延遲加載的方式有哪些
設置<script>屬性?defer="defer"?(腳本將在頁面完成解析時執行)
動態創建?script DOM:document.createElement('script');
XmlHttpRequest?腳本注入
延遲加載工具?LazyLoad
13 defer和async
defer并行加載js文件,會按照頁面上script標簽的順序執行
async并行加載js文件,下載完成立即執行,不會按照頁面上script標簽的順序執行
14 說說嚴格模式的限制
變量必須聲明后再使用
函數的參數不能有同名屬性,否則報錯
不能使用with語句
不能對只讀屬性賦值,否則報錯
不能使用前綴0表示八進制數,否則報錯
不能刪除不可刪除的屬性,否則報錯
不能刪除變量delete prop,會報錯,只能刪除屬性delete global[prop]
eval不會在它的外層作用域引入變量
eval和arguments不能被重新賦值
arguments不會自動反映函數參數的變化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局對象
不能使用fn.caller和fn.arguments獲取函數調用的堆棧
增加了保留字(比如protected、static和interface)
15 attribute和property的區別是什么
attribute是dom元素在文檔中作為html標簽擁有的屬性;
property就是dom元素在js中作為對象擁有的屬性。
對于html的標準屬性來說,attribute和property是同步的,是會自動更新的
但是對于自定義的屬性來說,他們是不同步的
16 談談你對ES6的理解
新增模板字符串(為JavaScript提供了簡單的字符串插值功能)
箭頭函數
for-of(用來遍歷數據—例如數組中的值。)
arguments對象可被不定參數和默認參數完美代替。
ES6將promise對象納入規范,提供了原生的Promise對象。
增加了let和const命令,用來聲明變量。
增加了塊級作用域。
let命令實際上就增加了塊級作用域。
還有就是引入module模塊的概念。
17 異步編程的實現方式
回調函數
優點:簡單、容易理解
缺點:不利于維護,代碼耦合高
事件監聽(采用時間驅動模式,取決于某個事件是否發生):
優點:容易理解,可以綁定多個事件,每個事件可以指定多個回調函數
缺點:事件驅動型,流程不夠清晰
發布/訂閱(觀察者模式)
類似于事件監聽,但是可以通過‘消息中心’,了解現在有多少發布者,多少訂閱者
Promise對象
優點:可以利用then方法,進行鏈式寫法;可以書寫錯誤時的回調函數;
缺點:編寫和理解,相對比較難
Generator函數
優點:函數體內外的數據交換、錯誤處理機制
缺點:流程管理不方便
async函數
優點:內置執行器、更好的語義、更廣的適用性、返回的是Promise、結構清晰。
缺點:錯誤處理機制
18 項目做過哪些性能優化?
減少?HTTP?請求數
減少?DNS?查詢
使用?CDN
避免重定向
圖片懶加載
減少?DOM?元素數量
減少DOM?操作
使用外部?JavaScript?和?CSS
壓縮?JavaScript?、?CSS?、字體、圖片等
優化?CSS Sprite
使用?iconfont
字體裁剪
多域名分發劃分內容到不同域名
盡量減少?iframe?使用
避免圖片?src?為空
把樣式表放在link?中
把JavaScript放在頁面底部
19 瀏覽器緩存
瀏覽器緩存分為強緩存和協商緩存。當客戶端請求某個資源時,獲取緩存的流程如下
先根據這個資源的一些?http header?判斷它是否命中強緩存,如果命中,則直接從本地獲取緩存資源,不會發請求到服務器;
當強緩存沒有命中時,客戶端會發送請求到服務器,服務器通過另一些request header驗證這個資源是否命中協商緩存,稱為http再驗證,如果命中,服務器將請求返回,但不返回資源,而是告訴客戶端直接從緩存中獲取,客戶端收到返回后就會從緩存中獲取資源;
強緩存和協商緩存共同之處在于,如果命中緩存,服務器都不會返回資源; 區別是,強緩存不對發送請求到服務器,但協商緩存會。
當協商緩存也沒命中時,服務器就會將資源發送回客戶端。
當?ctrl+f5?強制刷新網頁時,直接從服務器加載,跳過強緩存和協商緩存;
當?f5刷新網頁時,跳過強緩存,但是會檢查協商緩存;
強緩存
Expires(該字段是?http1.0?時的規范,值為一個絕對時間的?GMT?格式的時間字符串,代表緩存資源的過期時間)
Cache-Control:max-age(該字段是?http1.1的規范,強緩存利用其?max-age?值來判斷緩存資源的最大生命周期,它的值單位為秒)
協商緩存
Last-Modified(值為資源最后更新時間,隨服務器response返回)
If-Modified-Since(通過比較兩個時間來判斷資源在兩次請求期間是否有過修改,如果沒有修改,則命中協商緩存)
ETag(表示資源內容的唯一標識,隨服務器response返回)
If-None-Match(服務器通過比較請求頭部的If-None-Match與當前資源的ETag是否一致來判斷資源是否在兩次請求之間有過修改,如果沒有修改,則命中協商緩存)
20 談談變量提升?
當執行 JS 代碼時,會生成執行環境,只要代碼不是寫在函數中的,就是在全局執行環境中,函數中的代碼會產生函數執行環境,只此兩種執行環境
變量提升
這是因為函數和變量提升的原因。通常提升的解釋是說將聲明的代碼移動到了頂部,這其實沒有什么錯誤,便于大家理解。但是更準確的解釋應該是:在生成執行環境時,會有兩個階段。第一個階段是創建的階段,JS 解釋器會找出需要提升的變量和函數,并且給他們提前在內存中開辟好空間,函數的話會將整個函數存入內存中,變量只聲明并且賦值為?undefined,所以在第二個階段,也就是代碼執行階段,我們可以直接提前使用
在提升的過程中,相同的函數會覆蓋上一個函數,并且函數優先于變量提升
21 什么是單線程,和異步的關系
單線程 - 只有一個線程,只能做一件事
原因 - 避免?DOM?渲染的沖突
瀏覽器需要渲染?DOM
JS?可以修改?DOM?結構
JS?執行的時候,瀏覽器?DOM?渲染會暫停
兩段 JS 也不能同時執行(都修改?DOM?就沖突了)
webworker?支持多線程,但是不能訪問?DOM
解決方案 - 異步
22 JavaScript 對象生命周期的理解
當創建一個對象時,JavaScript?會自動為該對象分配適當的內存
垃圾回收器定期掃描對象,并計算引用了該對象的其他對象的數量
如果被引用數量為?0,或惟一引用是循環的,那么該對象的內存即可回收
23 說說從輸入URL到看到頁面發生的全過程,越詳細越好
首先瀏覽器主進程接管,開了一個下載線程。
然后進行HTTP請求(DNS查詢、IP尋址等等),中間會有三次捂手,等待響應,開始下載響應報文。
將下載完的內容轉交給Renderer進程管理。
Renderer進程開始解析css rule tree和dom tree,這兩個過程是并行的,所以一般我會把link標簽放在頁面頂部。
解析繪制過程中,當瀏覽器遇到link標簽或者script、img等標簽,瀏覽器會去下載這些內容,遇到時候緩存的使用緩存,不適用緩存的重新下載資源。
css rule tree和dom tree生成完了之后,開始合成render tree,這個時候瀏覽器會進行layout,開始計算每一個節點的位置,然后進行繪制。
繪制結束后,關閉TCP連接,過程有四次揮手
24 說一下瀏覽器的緩存機制
瀏覽器緩存機制有兩種,一種為強緩存,一種為協商緩存
對于強緩存,瀏覽器在第一次請求的時候,會直接下載資源,然后緩存在本地,第二次請求的時候,直接使用緩存。
對于協商緩存,第一次請求緩存且保存緩存標識與時間,重復請求向服務器發送緩存標識和最后緩存時間,服務端進行校驗,如果失效則使用緩存
協商緩存相關設置
Exprires:服務端的響應頭,第一次請求的時候,告訴客戶端,該資源什么時候會過期。Exprires的缺陷是必須保證服務端時間和客戶端時間嚴格同步。
Cache-control:max-age:表示該資源多少時間后過期,解決了客戶端和服務端時間必須同步的問題,
If-None-Match/ETag:緩存標識,對比緩存時使用它來標識一個緩存,第一次請求的時候,服務端會返回該標識給客戶端,客戶端在第二次請求的時候會帶上該標識與服務端進行對比并返回If-None-Match標識是否表示匹配。
Last-modified/If-Modified-Since:第一次請求的時候服務端返回Last-modified表明請求的資源上次的修改時間,第二次請求的時候客戶端帶上請求頭If-Modified-Since,表示資源上次的修改時間,服務端拿到這兩個字段進行對比
25 ajax、axios、fetch區別
jQuery ajax
$.ajax({type:'POST',url:url,data:data,dataType:dataType,success:function(){},error:function(){}});
優缺點:
本身是針對MVC的編程,不符合現在前端MVVM的浪潮
基于原生的XHR開發,XHR本身的架構不清晰,已經有了fetch的替代方案
JQuery整個項目太大,單純使用ajax卻要引入整個JQuery非常的不合理(采取個性化打包的方案又不能享受CDN服務)
axios
axios({method:'post',url:'/user/12345',data:{firstName:'Fred',lastName:'Flintstone'}}).then(function(response){console.log(response);}).catch(function(error){console.log(error);});
優缺點:
從瀏覽器中創建?XMLHttpRequest
從?node.js?發出?http?請求
支持?Promise API
攔截請求和響應
轉換請求和響應數據
取消請求
自動轉換JSON數據
客戶端支持防止CSRF/XSRF
fetch
try{letresponse=awaitfetch(url);letdata=response.json();console.log(data);}catch(e){console.log("Oops, error",e);}
優缺點:
fetcht只對網絡請求報錯,對400,500都當做成功的請求,需要封裝去處理
fetch默認不會帶cookie,需要添加配置項
fetch不支持abort,不支持超時控制,使用setTimeout及Promise.reject的實現的超時控制并不能阻止請求過程繼續在后臺運行,造成了量的浪費
fetch沒有辦法原生監測請求的進度,而XHR可以
26 說幾條寫JavaScript的基本規范
代碼縮進,建議使用“四個空格”縮進
代碼段使用花括號{}包裹
語句結束使用分號;
變量和函數在使用前進行聲明
以大寫字母開頭命名構造函數,全大寫命名常量
規范定義JSON對象,補全雙引號
用{}和[]聲明對象和數組
27 如何編寫高性能的JavaScript
遵循嚴格模式:"use strict";
將js腳本放在頁面底部,加快渲染頁面
將js腳本將腳本成組打包,減少請求
使用非阻塞方式下載js腳本
盡量使用局部變量來保存全局變量
盡量減少使用閉包
使用?window?對象屬性方法時,省略?window
盡量減少對象成員嵌套
緩存?DOM?節點的訪問
通過避免使用?eval()?和?Function()?構造器
給?setTimeout()?和?setInterval()?傳遞函數而不是字符串作為參數
盡量使用直接量創建對象和數組
最小化重繪(repaint)和回流(reflow)
28 script 的位置是否會影響首屏顯示時間
在解析?HTML?生成?DOM?過程中,js?文件的下載是并行的,不需要?DOM?處理到?script?節點。因此,script的位置不影響首屏顯示的開始時間。
瀏覽器解析?HTML?是自上而下的線性過程,script作為?HTML?的一部分同樣遵循這個原則
因此,script?會延遲?DomContentLoad,只顯示其上部分首屏內容,從而影響首屏顯示的完成時間
29 解釋JavaScript中的作用域與變量聲明提升
JavaScript作用域:
在Java、C等語言中,作用域為for語句、if語句或{}內的一塊區域,稱為作用域;
而在?JavaScript?中,作用域為function(){}內的區域,稱為函數作用域。
JavaScript變量聲明提升:
在JavaScript中,函數聲明與變量聲明經常被JavaScript引擎隱式地提升到當前作用域的頂部。
聲明語句中的賦值部分并不會被提升,只有名稱被提升
函數聲明的優先級高于變量,如果變量名跟函數名相同且未賦值,則函數聲明會覆蓋變量聲明
如果函數有多個同名參數,那么最后一個參數(即使沒有定義)會覆蓋前面的同名參數
30 css定位
1 相對定位 relative
相對定位是元素在移動位置的時候,是相對于它原來的位置來說的(自戀型)
相對定位的特點:(務必記住)
它是相對于自己原來的位置來移動的(移動位置的時候參照點是自己原來的位置)。
原來在標準流的位置繼續占有,后面的盒子仍然以標準流的方式對待它。
因此,相對定位并沒有脫標。它最典型的應用是給絕對定位當爹的。。。
2 絕對定位 absolute
絕對定位是元素在移動位置的時候,是相對于它祖先元素來說的(拼爹型)。
絕對定位的特點:(務必記住)
如果沒有祖先元素(父元素)或者祖先元素沒有定位,則以瀏覽器為準定位(Document 文檔)。
如果祖先元素有定位(相對、絕對、固定定位),則以最近一級的有定位祖先元素為參考點移動位置。
絕對定位不再占有原先的位置。(脫標)
所以絕對定位是脫離標準流的。
3 固定定位?fixed
生成絕對定位的元素,相對于瀏覽器窗口進行定位。只需設置它相對于各個方向的偏移值,就可以將該元素固定在頁面固定的位置,通常用來顯示一些提示信息,脫離文檔流;
31 介紹事件“捕獲”和“冒泡”執行順序和事件的執行次數
按照W3C標準的事件:首是進入捕獲階段,直到達到目標元素,再進入冒泡階段
事件執行次數(DOM2-addEventListener):元素上綁定事件的個數
注意1:前提是事件被確實觸發
注意2:事件綁定幾次就算幾個事件,即使類型和功能完全一樣也不會“覆蓋”
事件執行順序:判斷的關鍵是否目標元素
非目標元素:根據W3C的標準執行:捕獲->目標元素->冒泡(不依據事件綁定順序)
目標元素:依據事件綁定順序:先綁定的事件先執行(不依據捕獲冒泡標準)
最終順序:父元素捕獲->目標元素事件1->目標元素事件2->子元素捕獲->子元素冒泡->父元素冒泡
注意:子元素事件執行前提 事件確實“落”到子元素布局區域上,而不是簡單的具有嵌套關系
在一個DOM上同時綁定兩個點擊事件:一個用捕獲,一個用冒泡。事件會執行幾次,先執行冒泡還是捕獲?
該DOM上的事件如果被觸發,會執行兩次(執行次數等于綁定次數)
如果該DOM是目標元素,則按事件綁定順序執行,不區分冒泡/捕獲
如果該DOM是處于事件流中的非目標元素,則先執行捕獲,后執行冒泡
事件的代理/委托
事件委托是指將事件綁定目標元素的到父元素上,利用冒泡機制觸發該事件
優點:
可以減少事件注冊,節省大量內存占用
可以將事件應用于動態添加的子元素上
缺點: 使用不當會造成事件在不應該觸發時觸發
32 Javascript垃圾回收方法
標記清除(mark and sweep)
這是JavaScript最常見的垃圾回收方式,當變量進入執行環境的時候,比如函數中聲明一個變量,垃圾回收器將其標記為“進入環境”,當變量離開環境的時候(函數執行結束)將其標記為“離開環境”
垃圾回收器會在運行的時候給存儲在內存中的所有變量加上標記,然后去掉環境中的變量以及被環境中變量所引用的變量(閉包),在這些完成之后仍存在標記的就是要刪除的變量了
引用計數(reference counting)
在低版本IE中經常會出現內存泄露,很多時候就是因為其采用引用計數方式進行垃圾回收。引用計數的策略是跟蹤記錄每個值被使用的次數,當聲明了一個 變量并將一個引用類型賦值給該變量的時候這個值的引用次數就加1,如果該變量的值變成了另外一個,則這個值得引用次數減1,當這個值的引用次數變為0的時 候,說明沒有變量在使用,這個值沒法被訪問了,因此可以將其占用的空間回收,這樣垃圾回收器會在運行的時候清理掉引用次數為0的值占用的空間
33 Vue-Router
1、hash模式
hash模式是開發中默認的模式,也稱作錨點,它的URL帶著一個#,例如:www.abc.com/#/vue,它的hash值就是#/vue。
特點:
hash值會出現在URL里面,但是不會出現在HTTP請求中,對后端沒有影響。所以改變hash值不會重新加載頁面。
這種模式的瀏覽器支持度很好,低版本的IE瀏覽器也支持這種模式。
hash路由被稱為是前端路由,已經成為SPA(單頁面應用)的標配。
原理:
hash模式的主要原理就是onhashchange()事件:
window.onhashchange = function(event){
console.log(event.oldURL, event.newURL);
let hash = location.hash.slice(1);
使用onhashchange()事件的好處就是,在頁面的hash值發生變化時,無需向后端發起請求,window就可以監聽事件的改變,并按規則加載相應的代碼。除此之外,hash值變化對應的URL都會被瀏覽器記錄下來,這樣瀏覽器就能實現頁面的前進和后退。雖然是沒有請求后端服務器,但是頁面的hash值和對應的URL關聯起來了。
獲取頁面hash變化的方法:
(1)監聽$route的變化:
// 監聽,當路由發生變化的時候執行
watch: {
? $route: {
? ? handler: function(val, oldVal){
? ? ? console.log(val);
? ? },
? ? // 深度觀察監聽
? ? deep: true
? }
},
(2)通過window.location.hash讀取#值:
window.location.hash 的值可讀可寫,讀取來判斷狀態是否改變,寫入時可以在不重載網頁的前提下,添加一條歷史訪問記錄。
2、history模式
history模式直接指向history對象,它表示當前窗口的瀏覽歷史,history對象保存了當前窗口訪問過的所有頁面網址。URL中沒有#,它使用的是傳統的路由分發模式,即用戶在輸入一個URL時,服務器會接收這個請求,并解析這個URL,然后做出相應的邏輯處理。
特點:
當使用history模式時,URL就像這樣:hhh.com/user/id。相比hash模式更加好看。
雖然history模式不需要#。但是,它也有自己的缺點,就是在刷新頁面的時候,如果沒有相應的路由或資源,就會刷出404來。
history api可以分為兩大部分,切換歷史狀態 和 修改歷史狀態:
修改歷史狀態:
包括了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法,這兩個方法應用于瀏覽器的歷史記錄棧,提供了對歷史記錄進行修改的功能。只是當他們進行修改時,雖然修改了url,但瀏覽器不會立即向后端發送請求。如果要做到改變url但又不刷新頁面的效果,就需要前端用上這兩個API。
切換歷史狀態:
包括forward()、back()、go()三個方法,對應瀏覽器的前進,后退,跳轉操作。
配置:
想要設置成history模式,就要進行以下的配置(后端也要進行配置):
const router = new VueRouter({
? mode: 'history',
? routes: [...]
})
3、兩者對比
調用 history.pushState() 相比于直接修改 hash,存在以下優勢:
pushState() 設置的新 URL 可以是與當前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,因此只能設置與當前 URL 同文檔的 URL。
pushState() 設置的新 URL 可以與當前 URL 一模一樣,這樣也會把記錄添加到棧中;而 hash 設置的新值必須與原來不一樣才會觸發動作將記錄添加到棧中。
pushState() 通過 stateObject 參數可以添加任意類型的數據到記錄中;而 hash 只可添加短字符串。
pushState() 可額外設置 title 屬性供后續使用。
hash模式下,僅hash符號之前的url會被包含在請求中,后端如果沒有做到對路由的全覆蓋,也不會返回404錯誤;history模式下,前端的url必須和實際向后端發起請求的url一致,如果沒有對用的路由處理,將返回404錯誤。
4、總結
hash模式URL上帶有#,僅 hash 符號之前的內容會被包含在請求中,如 www.hhh.com,因此對于后端來說,即使沒有做到對路由的全覆蓋,也不會返回 404 錯誤。
history模式URL上沒有#,前端的 URL 必須和實際向后端發起請求的 URL 一致,如 www.hhh.com/user/id。如果后端缺少對 /use/id 的路由處理,將返回 404 錯誤。