一、前言
前端路由是什麼?如果你之前從事的是後端的工作,或者雖然有接觸前端,但是並沒有使用到單頁面應用的話,這個概念對你來說還是會很陌生的。那麼,為什麼會在單頁面應用中存在這麼一個概念,以及,前端路由與我們後端的路由有什麼異同呢。本章,我們就來簡單介紹下前端路由的概念,以及如何在 Vue 中使用 Vue Router 來實現我們的前端路由。
學習系列目錄地址:https://www.cnblogs.com/danvic712/p/9549100.html
倉儲地址:https://github.com/Lanesra712/VueTrial/blob/master/chapter02-bronze/router/sample.html
二、乾貨合集
在傳統的多頁面應用中,網站的每一個 URL 地址都是對應於伺服器磁碟上的一個實際物理檔案。例如,當我們訪問 https://www.yousite.com/index.html 這個網址的時候,伺服器會自動把我們的請求對應到當前站點路徑下面的 index.html 檔案,然後再給予響應,將這個檔案返回給瀏覽器。當我們跳轉到別的頁面上時,毫無疑問則會再重複一遍上面的過程。
但是在單頁面應用中,整個專案中只會存在一個 html 檔案,當使用者切換頁面時,只是通過對這個唯一的 html 檔案進行動態重寫,從而達到響應使用者的請求。也就是說,從切換頁面這個角度上說,應用只是在第一次開啟時請求了伺服器(非服務端渲染的單頁應用)。
因為訪問的頁面是並不真實存在的,所以如何正確的在一個 html 檔案中展現出使用者想要訪問的資訊就成為單頁面應用需要考慮的問題,而對於這一路由問題的解決方案,為了與我們後端傳統意義上的路由進行區別,就將此稱為前端路由。
1、前端路由的實現方式
目前的前端路由的實現方式主要是通過 hash 路由匹配或者是採用 html5 中的 history api 這兩種,也就是說,不管是 hash 路由還是使用 history 路由模式,其實都是基於瀏覽器自身的特性。
hash 路由:hash 這個概念,可能聽起來有些陌生,不過,其實我們在之前的前端開發中,其實是有所接觸的。例如,在某些情況下,我們需要定位頁面上的某些位置,就像下面的例子中展現的那樣,我想要通過點選不同的按鈕就跳轉到指定的位置,這裡我們使用的錨點定位其實就是 hash。
<div id="content"> <div class="btn-container"> <a class="btn" href="#image1">圖片1</a> <a class="btn" href="#image2">圖片2</a> </div> <img src="./xxx/xxx.jpg" id="image1"> <img src="./xxx/xxx.jpg" id="image2"> </div>
hash 路由的本質是瀏覽器 location 物件中的 hash 屬性,它會記錄連結地址中 '#' 後面的內容(e.g.:#part1)。因此,我們可以通過監聽 window.onhashchange 事件獲取到跳轉前後訪問的地址,從而實現地址切換的目的。
history 路由:在之前的 html 版本中,我們可以通過 history.back(), history.forward()和 history.go() 方法來完成在使用者歷史記錄中向後和向前的跳轉。而 history 路由則是使用了 html5 中新增的 pushState 事件和 replaceState() 事件。
通過這兩個新增的 API,就可以實現無重新整理的更改位址列連結,配合 AJAX 就可以做到整個頁面的無重新整理跳轉,具體實現的原理大家可以看看這篇文章 =》https://www.renfei.org/blog/html5-introduction-3-history-api.html
在 Vue 中,Vue Router 是官方提供的路由管理器。它和 Vue.js 的核心深度整合,因此,不管是採用 hash 的方式還是使用 history api 實現我們的前端路由都有很好的支援,所以這裡我們採用 Vue Router 這一元件來實現我們的前端路由。
2、路由實現
首先我們需要將 Vue Router 新增引用到我們的專案中,這裡我還是採用直接引用 js 檔案的方式為我們的示例程式碼新增前端路由支援。
在 Vue 中使用 Vue Router 構建單頁面應用,我們只需要將元件 (components) 對映到定義的路由 (routes) 規則中,然後告訴 Vue Router 在哪裡渲染它們,並將這個路由配置掛載到 Vue 例項節點上即可。
在 Vue Router 中,我們使用 router-link 標籤來渲染連結,當然,預設生成的是 a 標籤,如果你想要將路由資訊生成別的 html 標籤,則可以使用 tag 屬性指明需要生成的標籤型別。
<!-- 預設渲染成 a 標籤 --> <router-link to="/home">主頁</router-link> <!-- 渲染成 button 標籤 --> <router-link to="/home" tag="button">主頁</router-link>
可以看到,當我們指定 tag 屬性為 button 後,頁面渲染後的的標籤就變成了 button 按鈕。同樣的,它還是會監聽點選,觸發導航。
同時,從上圖可以看出,當前的連結地址為 #/home,也就是說,通過 router-link 生成的標籤,當頁面地址與對應的路由規則匹配成功後,將自動設定 class 屬性值為 .router-link-active。當然,我們也可以通過指定 active-class 屬性或者在構造 VueRouter 物件時使用 linkActiveClass 來自定義連結啟用時使用的 CSS 類名。
<!-- 使用屬性來設定自定義啟用類名 --> <router-link to="/home" active-class="aaaa">主頁</router-link> <!-- 在構造物件時設定全域性預設類名 --> const router = new VueRouter({ routes: [], linkActiveClass: 'aaaaa' })
當路由表構建完成後,對於指向路由表中的連結,需要在頁面上找一個地方去顯示已經渲染完成後的元件,這時,我們就需要使用 router-view 標籤去告訴程式,我們需要將渲染後的元件顯示在當前位置。
在下面的示例程式碼中,模擬了 Vue 中路由的使用,當訪問 #/home 時會進行載入 home 元件,而當連結跳轉到 #/account 時則會載入 account 元件。同時,我們可以發現,在 account 元件中又包含了兩個子路由,通過點選 account 元件中的子路由地址,從而載入對應的 login 元件和 register 元件。
<script src="../../lib/vue.js"></script> <script src="../../lib/vue-router.js"></script> <style> .container { background-color: aquamarine; margin-top: 20px; width: 740px; height: 300px; } </style> <div id="app"> <!-- 通過 router-link 標籤來生成導航連結 --> <router-link to="/home">主頁</router-link> <router-link to="/account">賬戶</router-link> <div class="container"> <!-- 將選中的路由渲染到 router-view 下--> <router-view></router-view> </div> </div> <template id="tmpl"> <div> <h3> account page </h3> <!-- 生成巢狀子路由地址 --> <router-link to="/account/login">登入</router-link> <router-link to="/account/register">註冊</router-link> <!-- 生成巢狀子路由渲染節點 --> <router-view></router-view> </div> </template> <script> // 1、定義路由跳轉的元件模板 const home = { template: '<div> home page </div>' } const account = { template: '#tmpl' } const login = { template: '<div> login page</div>' } const register = { template: '<div> register page</div>' } // 2、定義路由資訊 const routes = [{ path: '/', redirect: '/home' }, { path: '/home', component: home }, { path: '/account', component: account, children: [{ path: 'login', component: login }, { path: 'register', component: register } ] } ] const router = new VueRouter({ //mode: 'history', //使用 history 模式還是 hash 路由模式 routes }) // 3、掛載到當前 Vue 例項上 const vm = new Vue({ el: '#app', data: {}, methods: {}, router: router }); </script>
在上面的程式碼中,也使用到了巢狀路由和路由的重定向。通過使用路由重定向,我們可以將使用者訪問網站的根目錄 / 時進行重定向到 /home ,而巢狀路由則可以將 URL 中各段動態路徑也按某種結構對應到實際巢狀的各層元件。
例如,這裡的 login 元件和 register 元件,它們都是位於 account 元件中的,因此,在構建 url 時,我們應該將該地址位於 /account url 後面,從而更好地表達這種關係。所以這裡,我們在 account 元件中又新增了一個 router-view 標籤,用來渲染出巢狀的元件內容。同時,通過在定義 routes 時在引數中使用 children 屬性,從而達到配置巢狀路由資訊的目的。
PS:以 / 開頭的巢狀路徑會被當作根路徑,而我們的 login 元件和 register 元件都是包含在 account 中,所以這裡直接定義 path 引數即可。
三、總結
這一章主要是介紹瞭如何使用 Vue Router 在 Vue 中構建我們的前端路由。在實際開發中,對於一個路徑,可能會對應到多個元件,這時,如何將多個元件繫結到一個路徑下,就是我們需要解決的問題。另外,在實際使用中我們會遇到路由傳參,可能會因為 hash 路由不漂亮,從而準備採用 history 路由,對於這些需求的實現,將放在下一章中進行學習。