1. 后端路由階段
早期的網(wǎng)站開發(fā)整個
HTML頁面是由服務器來渲染的。服務器直接生產(chǎn)渲染好對應的HTML頁面, 返回給客戶端進行展示。
1.1 但是, 一個網(wǎng)站, 這么多頁面服務器如何處理呢?
一個頁面有自己對應的網(wǎng)址, 也就是
URL。URL會發(fā)送到服務器, 服務器會通過正則對該URL進行匹配, 并且最后交給一個Controller進行處理。Controller進行各種處理, 最終生成HTML或者數(shù)據(jù), 返回給前端。這就完成了一個
IO操作。
上面的這種操作, 就是后端路由,當我們頁面中需要請求不同的路徑內容時, 交給服務器來進行處理, 服務器渲染好整個頁面, 并且將頁面返回給客戶端,這種情況下渲染好的頁面, 不需要單獨加載任何的
js和css, 可以直接交給瀏覽器展示, 這樣也有利于SEO的優(yōu)化。
1.2 后端路由的缺點:
一種情況是整個頁面的模塊由后端人員來編寫和維護的;
另一種情況是前端開發(fā)人員如果要開發(fā)頁面, 需要通過
PHP和Java等語言來編寫頁面代碼;而且通常情況下HTML代碼和數(shù)據(jù)以及對應的邏輯會混在一起, 編寫和維護都是非常糟糕的事情。
2. 前端路由階段
2.1 前后端分離階段
隨著
Ajax的出現(xiàn), 有了前后端分離的開發(fā)模式。后端只提供
API來返回數(shù)據(jù), 前端通過Ajax獲取數(shù)據(jù), 并且可以通過JavaScript將數(shù)據(jù)渲染到頁面中。這樣做最大的優(yōu)點就是前后端責任的清晰, 后端專注于數(shù)據(jù)上, 前端專注于交互和可視化上。
并且當移動端
(iOS/Android)出現(xiàn)后, 后端不需要進行任何處理, 依然使用之前的一套API即可。
2.2 單頁面富應用階段
其實SPA最主要的特點就是在前后端分離的基礎上加了一層前端路由。
也就是前端來維護一套路由規(guī)則。
3. URL的hash 模式 和 HTML5 的 history 模式
3.1 URL的hash模式
-
URL的hash也就是錨點(#), 本質上是改變window.location的href屬性;我們可以通過直接賦值location.hash來改變href, 但是頁面不發(fā)生刷新。


3.2 HTML5的history模式
-
history對象的pushState方法傳遞三個參數(shù),第一個參數(shù)是一個對象。第二個參數(shù)是title, 第三個參數(shù)是路徑。


-
history模式的replaceState方法:替換路徑,不能通過返回箭頭返回。

-
history模式的go方法:到某個索引的路徑下:
history.go(-1) // 表示后退一步 和 history.back() 類似
history.go(1) // 表示前進一步 和 history.forward() 類似
4. Vue-Router的安裝配置
- Vue-router是
Vue.js官方的路由插件,它和
4.1 安裝 Vue-Router
- 安裝為一個運行時依賴:
npm install vue-router --save
創(chuàng)建一個
router文件夾,并在文件中創(chuàng)建一個index.js文件。在
index.js文件中引入VueRouter對象和Vue對象。
import VueRouter from 'vue-router';
import Vue from 'vue';
- 通過Vue.use(傳入插件)安裝該插件,任何Vue的插件都要使用 Vue.use進行安裝。
Vue.use(VueRouter);
- 創(chuàng)建
VueRouter對象實例,注意這里是 routes 而不是 routers 重要重要重要
// 路由數(shù)組
const routes = [];
// 2. 創(chuàng)建VueRouter對象
const router = new VueRouter({
// 配置組件之間的映射關系
// 對象屬性的簡寫
routes
});
- 導出
VueRouter對象實例:
export default router;
- 在
main.js中引入并使用router:

4.2 配置路由的映射關系
- 在
components文件夾下創(chuàng)建Home和About組件。
- 在
router/index.js下配置路由映射關系 。

- 使用
Vue中注冊的全局組件router-link和router-view實現(xiàn)頁面跳轉和渲染。
<div id="app">
<!-- router-link是Vue中注冊的全局組件 -->
<router-link to="/home">首頁</router-link>
<router-link to="/about">關于</router-link>
<router-view></router-view>
</div>
<router-link>: 該標簽是一個vue-router中已經(jīng)內置的組件, 它會被渲染成一個<a>標簽。<router-view>: 該標簽會根據(jù)當前的路徑, 動態(tài)渲染出不同的組件。默認顯示首頁:
/home,將進入頁面時將頁面重定向到Home頁面
// 路由數(shù)組
const routes = [
{
path: '/',
/* 將路徑重定向到home */
redirect: '/home'
},
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/about',
component: About
}
]
4.3 修改路由的模式為 history
- 默認情況下,路徑改變使用的是
URL的hash,如果希望使用HTML5的history模式可以進行如下的修改。

// 2. 創(chuàng)建VueRouter對象
const router = new VueRouter({
// 配置組件之間的映射關系
// 對象屬性的簡寫 但是這個屬性必須交 routes
routes,
mode:'history'
});
4.4 router-link 的其他屬性
router-link 標簽的 tag 屬性
- 可以 通過
tag設置router-link使用什么標簽來進行渲染。
<!-- router-link是Vue中注冊的全局組件 -->
<router-link tag="button" to="/home">首頁</router-link>
<router-link tag="button" to="/about">關于</router-link>

router-link 標簽的 replace 屬性
-
replace屬性設置之之后通過該標簽跳轉的路徑,不能通過瀏覽器的后退鍵返回。replace不會留下history記錄, 所以指定replace的情況下, 后退鍵返回不能返回到上一個頁面中。這就說明vue-router默認使用的是history的pushState。
<!-- router-link是Vue中注冊的全局組件 -->
<router-link tag="button" to="/home" replace>首頁</router-link>
<router-link tag="button" to="/about" replace>關于</router-link>

router-link 標簽的 active-class 屬性
- 默認情況下當點擊某個標簽,該標簽被激活之后,在其中會添加一個
class,router-link-active??梢酝ㄟ^該class設置激活樣式。
.router-link-active {
color: #f00;
}

- 該
class的名稱是可以被修改的,此時就需要在標簽中 使用active-class屬性對class的名稱進行修改。
<!-- router-link是Vue中注冊的全局組件 -->
<router-link tag="button" to="/home" replace active-class="active">首頁</router-link>
<router-link tag="button" to="/about" replace active-class="active">關于</router-link>
.active {
color: #00f;
}

在 router/index.js文件的router對象中使用linkActiveClass屬性統(tǒng)一修改樣式名稱



4.5 通過代碼實現(xiàn)路由的跳轉
- 在頁面中定義兩個按鈕實現(xiàn)路由的跳轉:利用
vue內置的$router的push和replace方法實現(xiàn)跳轉。
<!-- 通過代碼實現(xiàn)路由的跳轉 -->
<button @click="btnClickHome">首頁</button>
<button @click="btnClickAbout">關于</button>
/**
* 跳轉到 首頁
*/
btnClickHome() {
// this.$router.push('/home');
this.$router.replace('/home'); // 跳轉之后不能通過瀏覽器的后退按鈕返回
},
/**
* 實現(xiàn)跳轉到關于
*/
btnClickAbout() {
// this.$router.push('/about');
this.$router.replace('/about'); // 跳轉之后不能通過瀏覽器的后退按鈕返回
}
5. vue-router 動態(tài)路由的使用
- 創(chuàng)建一個
User組件并在router/index.js中配置路由:
// 路由數(shù)組
const routes = [
{
path: '/',
/* 將路徑重定向到home */
redirect: '/home'
},
{
path: '/home',
name: 'Home',
component: Home
},
{
path: '/about',
component: About
},
{
path: '/user/:userId',
component: User
}
];

- 在
APP.vue中使用router-link配置路由實現(xiàn)跳轉:在配置時一并傳遞參數(shù)。
<!-- 實現(xiàn)動態(tài)路由 -->
<router-link to="/home">首頁</router-link>
<router-link to="/about">關于</router-link>
<!-- 在此使用動態(tài)路由 使用 v-bind 動態(tài)綁定 -->
<router-link :to="`/user/` + userId">用戶</router-link>

- 在跳轉到
User組件之后,在User頁面獲取到路徑中的userId參數(shù):這里需要通過一個$route的屬性獲取。使用$route.params.userId獲取。但是這里的userId是與路由配置中的userId一一對應的。
<div>
<h2>我是User組件</h2>
<!-- 獲取到路徑中傳遞的用戶名 的兩種方式-->
<!-- 1. 直接在Mustache語法中寫 -->
<h2>{{$route.params.userId}} 您好!</h2>
<!-- 2. 通過計算屬性的方式 -->
<h2>{{userId}} 您好!</h2>
</div>
computed: {
userId() {
return this.$route.params.userId
}
}

6. vue-router 打包文件的解析

7. 路由的懶加載
路由懶加載的官方解釋:首先, 我們知道路由中通常會定義很多不同的頁面,這個頁面最后被打包在哪里呢? 一般情況下, 是放在一個
js文件中,但是, 頁面這么多放在一個js文件中, 必然會造成這個頁面非常的大,
如果我們一次性從服務器請求下來這個頁面, 可能需要花費一定的時間, 甚至用戶的電腦上還出現(xiàn)了短暫空白的情況。路由懶加載做了什么? 答: 路由懶加載的主要作用就是將路由對應的組件打包成一個個的
js代碼塊。只有在這個路由被訪問到的時候, 才加載對應的組件。

7.2 各種路由懶加載的配置方式
- 方式一: 結合
Vue的異步組件和Webpack的代碼分析
const Home = resolve => { require.ensure(['../components/Home.vue'], () => { resolve(require('../components/Home.vue')) })};
- 方式二:
AMD寫法
const About = resolve => require(['../components/About.vue'], resolve);
- 方式三: 在
ES6中, 我們可以有更加簡單的寫法來組織Vue異步組件和Webpack的代碼分割
const Home = () => import('../components/Home.vue')
8. 認識路由的嵌套

8.1 嵌套路由配置案例
- 創(chuàng)建一個
HomeMessage和HomeNews組件。
<template>
<div>
<ul>
<li>消息1</li>
<li>消息2</li>
<li>消息3</li>
<li>消息4</li>
</ul>
</div>
</template>
<script>
export default {
name: "home-message"
}
</script>
<style scoped>
</style>
<template>
<div>
<ul>
<li>新聞1</li>
<li>新聞2</li>
<li>新聞3</li>
<li>新聞4</li>
</ul>
</div>
</template>
<script>
export default {
name: "home-news"
}
</script>
<style scoped>
</style>
- 配置嵌套路由 :
/* 使用懶加載的方式加載組件 */
const Home = () => import('../components/Home')
const HomeNews = () => import('../components/HomeNews')
const HomeMessage = () => import('../components/HomeMessage')
const About = () => import('../components/About')
const User = () => import('../components/User')
// 1. 通過Vue.use(傳入插件)安裝該插件,任何Vue的插件都要使用 Vue.use進行安裝
Vue.use(VueRouter);
// 路由數(shù)組
const routes = [
{
path: '/',
/* 將路徑重定向到home */
redirect: '/home'
},
{
path: '/home',
name: 'Home',
component: Home,
/* 配置路由的嵌套 */
children:[
/* 配置默認顯示首頁的時候一并顯示消息 */
{
path:'/',
redirect:'news'
}
,
{
/* 注意這里沒有 斜杠 / 這里是不能有 斜杠的 */
path:'news',
component:HomeNews
},
{
path:'message',
component:HomeMessage
}
]
},
{
path: '/about',
component: About
},
{
path: '/user/:userId',
component: User
}
];

- 因為這兩個組件需要在
Home組件中切換顯示,所以還需在Home組件中使用router-link和router-view進行配置。
<template>
<div>
<h2>我是Home組件</h2>
<router-link to="/home/news">新聞</router-link>
<router-link to="/home/message">消息</router-link>
<router-view></router-view>
</div>
</template>

9. vue-router 參數(shù)傳遞
9.1 參數(shù)傳遞的方式一 user/:userId

9.2 參數(shù)傳遞的方式二 query參數(shù)對象傳遞案例
- 創(chuàng)建一個新的組件
Profile
<template>
<div>
<h2>我是Profile組件</h2>
</div>
</template>
<script>
export default {
name: "profile"
}
</script>
<style scoped>
</style>
- 為組件配置路由 :

- 使用
router-link的方式實現(xiàn)路由的跳轉并傳遞query參數(shù)對象。

- 使用觸發(fā)事件的方式實現(xiàn)路由的跳轉:通過
this.$router.push(``)的方式實現(xiàn)路由跳轉。

10. vue-router 和 vue-route 是由區(qū)別的
$router為VueRouter實例,想要導航到不同URL,則使用$router.push方法。$route為當前router跳轉對象里面可以獲取name、path、query、params等。

11. 導航守衛(wèi)
1.有時可能需要在跳轉過程之間做一些新的操作。就可以使用導航守衛(wèi)監(jiān)聽跳轉過程。
-
URL組成:
URL= scheme(協(xié)議)://host(主機):port(端口)/path(路徑)?query(查詢)#fragment(片段);
11.1 當頁面跳轉的時候如果需要改變 title 該如何做?
網(wǎng)頁標題是通過
<title>來顯示的, 但是SPA只有一個固定的HTML, 切換不同的頁面時, 標題并不會改變。但是我們可以通過
JavaScript來修改<title>的內容window.document.title = '新的標題'。
- 那么在
Vue項目中, 在哪里修改? 什么時候修改比較合適呢?
使用導航守衛(wèi)在路由跳轉前進行修改頁面 title操作
使用
router實例對象的beforeEach方法前置守衛(wèi)函數(shù),函數(shù)中傳遞一個鉤子函數(shù),鉤子函數(shù)需要 3 個參數(shù)。to , from ,next。需要向下執(zhí)行就需要調用next()。在執(zhí)行
next()之前將title進行修改。但是動態(tài)的title從哪里來呢?

11.2 導航守衛(wèi)的分類
全局路由守衛(wèi);
路由獨享守衛(wèi);
組件內守衛(wèi)。
參考。
12. vue-router 的 keep-alive
-
keep-alive是一個標簽,是一個保持組件為活躍狀態(tài),不會被頻繁的創(chuàng)建和頻繁的銷毀。

12.1 利用 keep-alive 和 activated 、beforeRouteLeave 導航守衛(wèi)實現(xiàn)記住上一個頁面的選擇案例


- 當
router-view標簽外面包裹了keep-alive標簽之后activated方法就會有效:在該方法中實現(xiàn)路由的跳轉。

- 當離開當前的組件之前記錄一下當前的路徑
path。
在beforeRouteLeave方法中就是離開組件之前記住上次的路徑
只有使用 keep-alive標簽包裹的組件使用 activated 和 deactived 才是有效的。
12.2 keep-alive的其他屬性
keep-alive 是 Vue 內置的一個組件,可以使被包含的組件保留狀態(tài),或避免重新渲染。
include: 字符串或正則表達,只有匹配的組件會被緩存;exclude: 字符串或正則表達式,任何匹配的組件都不會被緩存;
<!-- 但是中間不要隨便加空格 -->
<keep-alive exclude="profile,User">
<router-view></router-view>
</keep-alive>
