路由是根據不同的url地址來顯示不同的頁面或內容的功能,這個概念很早是由后端提出的。
后端之前是這么做的,當我們訪問 http://xxx.abc.com/xx 的時候,大致流程可以想象成這樣的:
1. 瀏覽器向服務器發出請求。
2. 服務器監聽到80端口,如果有請求過來,那么就解析url地址。
3. 服務器根據客戶端的路由配置,然后就返回相應的信息(比如html字符串、json數據或圖片等)。
4. 瀏覽器根據數據包的 Content-Type來決定如何解析數據。
如上就是后端路由最初始的實現方式,那么既然有后端路由,那為什么還需要我們前端路由呢?后端路由有一個很大的缺點就是每次路由切換的時候都需要去刷新頁面,然后發出ajax請求,然后將請求數據返回回來,那么這樣每次路由切換都要刷新頁面對於用戶體驗來說就不好了。因此為了提升用戶體驗,我們前端路由就這樣產生了。它就可以解決瀏覽器不會重新刷新了。
history模式
用url規范的路由,但跳轉時不刷新頁面
HTML5的History API為瀏覽器的全局history對象增加了該擴展方法。它是一個瀏覽器的一個接口,在window對象中提供了onpopstate事件來監聽歷史棧的改變,只要歷史棧有信息發生改變的話,就會觸發該事件
在html5中,History API 新增了操作會話瀏覽歷史記錄的功能。如下新增的幾個方法:
window.history.state. 該參數是只讀的,表示與會話瀏覽歷史的當前記錄相關聯的狀態對象。如下圖所示:
window.history.pushState(data, title, ?url): 在會話瀏覽歷史記錄中添加一條記錄。
window.history.replaceState(data, title, ?url): 該方法用法和history.pushState方法類似,但是該方法的含義是將修改會話瀏覽歷史的當前記錄,而不是新增一條記錄。也就是說把當前的瀏覽地址換成 replaceState之后的地址,但是瀏覽歷史記錄的總長度並沒有新增
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>history API test</title> </head> <body> <p>history API test</p> <button id="btn1">修改 url</button> <script> // 頁面初次加載,獲取 path document.addEventListener('DOMContentLoaded', () => { console.log('load', location.pathname) }) // 打開一個新的路由 // 【注意】用 pushState 方式,瀏覽器不會刷新頁面 document.getElementById('btn1').addEventListener('click', () => { const state = { name: 'page1' } console.log('切換路由到', 'page1') history.pushState(state, '', 'page1') // 重要!! }) // 監聽瀏覽器前進、后退 window.onpopstate = (event) => { // 重要!! console.log('onpopstate', event.state, location.pathname) } // 需要 server 端配合,可參考,vue-router官網 // https://router.vuejs.org/zh/guide/essentials/history-mode.html#%E5%90%8E%E7%AB%AF%E9%85%8D%E7%BD%AE%E4%BE%8B%E5%AD%90 </script> </body> </html>
hash模式
hash 變化會觸發網頁跳轉,即瀏覽器的前進,后退
hash 變化不會刷新頁面,spa必須特點
hash 永遠不會提交到server端(前端自生自滅)
hash路由模式是這樣的:http://xxx.abc.com/#/xx。 有帶#號,后面就是hash值的變化。改變后面的hash值,它不會向服務器發出請求,因此也就不會刷新頁面。並且每次hash值發生改變的時候,會觸發hashchange事件。因此我們可以通過監聽該事件,來知道hash值發生了哪些變化
我們先來了解下location有哪些屬性,如下: 復制代碼 // 完整的url location.href // 當前URL的協議,包括 :; 比如 https: location.protocol /* 主機名和端口號,如果端口號是80(http)或443(https), 那就會省略端口號,比兔 www.baidu.com:8080 */ location.host // 主機名:比如:www.baidu.com location.hostname // 端口號;比如8080 location.port // url的路徑部分,從 / 開始; 比如 https://www.baidu.com/s?ie=utf-8,那么 pathname = '/s'了 location.pathname // 查詢參數,從?開始;比如 https://www.baidu.com/s?ie=utf-8 那么 search = '?ie=utf-8' location.search // hash是頁面中的一個片段,從 # 開始的,比如 https://www.baidu.com/#/a/b 那么返回值就是:"#/a/b" location.hash
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>hash test</title> </head> <body> <p>hash test</p> <button id="btn1">修改 hash</button> <script> // hash 變化,包括: // a. JS 修改 url // b. 手動修改 url 的 hash,在瀏覽器器地址手動賦值 // c. 瀏覽器前進、后退 // onhashchange 事件在當前 URL 的錨部分(以 '#' 號為開始) 發生改變時觸發 window.onhashchange = (event) => { //http://localhost:8080/01-hash.html console.log('old url', event.oldURL) //http://localhost:8080/01-hash.html#/user console.log('new url', event.newURL) // #/user console.log('hash:', location.hash) } // 頁面初次加載,獲取 hash document.addEventListener('DOMContentLoaded', () => { //http://localhost:8080/01-hash.html hash是空的 console.log('hash:', location.hash) }) // JS 修改 url document.getElementById('btn1').addEventListener('click', () => { location.href = '#/user' }) </script> </body> </html>
hash模式的特點:
hash模式在瀏覽器地址欄中url有#號這樣的,比如(http://localhost:3001/#/a). # 后面的內容不會傳給服務端,也就是說不會重新刷新頁面。並且路由切換的時候也不會重新加載頁面。
history模式的特點:
瀏覽器地址沒有#, 比如(http://localhost:3001/a); 它也一樣不會刷新頁面的。但是url地址會改變。