閱讀目錄javascript
一:vue-router是什麼?html
四:理解vue設置路由導航的兩種方法。html5
五:理解動態路由和命名視圖java
六:理解嵌套路由node
七:在nginx上部署vue項目(history模式)webpack
八:vue-router 之 keep-alivenginx
一. vue-router是什麼?git
vue-router是vue.js官方的路由插件,它和vue.js是集成的。它用於構建單頁面應用,vue的單頁面應用是基於路由和組件的,路由是用於設定訪問路徑的,而且路徑和組件會產生映射起來。在vue-router單頁面應用中,路徑之間的切換,能夠理解爲組件的切換,路由模塊的本質:是創建起url和頁面之間的映射關係。
二:vue-router的實現原理
vue-router是用於構建單頁面的,單頁面的核心是更新視圖而不會從新請求頁面,這也就是爲何在頁面中不用a標籤的緣由,由於頁面只有一個index.html。那麼它在實現單頁面前端路由時,提供了兩種模式,hash模式和History模式。默認狀況下是使用hash模式。
2.1 hash模式
hash是URL的錨點(#), 表明網頁中的一個位置,若是隻改變#後的部分,瀏覽器會滾動到相應的位置,而不會從新加載網頁,而且每次改變#後的部分,都會在瀏覽器的訪問歷史中增長一條記錄,當咱們使用後退按鈕的時候,就能夠返回到上一個位置。所以hash模式經過錨點值的改變,根據不一樣的值,渲染指定DOM位置的不一樣數據。
2.2 history模式
上面是經過hash模式的,頁面的地址就會加上 # 號,好比咱們的地址相似這樣的:http://localhost:8080/#/,咱們使用history的話,那麼訪問頁面的時候就和日常同樣,不帶井號的;以下地址也能夠訪問 http://localhost:8080/ ,使用路由history模式的話,只須要在配置路由規則時,加入 'mode': 'history'便可,它是利用html5中的 history.pushState的API來完成的URL跳轉,無需從新加載頁面的。
不過這種配置須要後臺開發支持一下的,具體怎麼配置,下面會詳細講到。
三:vue-router使用及代碼配置
在vue-router中,定義了兩個標籤<router-link>和<router-view>來對應點擊和顯示,<router-link>是點擊的部分,<router-view>是定義顯示的部分,當咱們點擊以後,路由匹配組件的內容後會在<router-view>顯示出來,<router-link>還須要一個屬性 to, 它的含義就是到哪裏去的意思。
好比 <router-link to="/home">111</router-link> 的含義是當咱們點擊111的時候,它會找到home相對應的組件,而後會在 <router-view>中顯示出來。
理解配置路由
路由通常使用兩個部分組成,path和component,path指路徑,component指的是組件,它是一個對象,好比 { path: '/home', component: home }
好比咱們這邊定義兩條路由,以下代碼:
const routes = [ { path: '/home', component: Home }, { path: '/xxx', component: XXX } ];
2. 建立router管理
建立router對路由進行管理,它是由構造函數 new vueRouter()建立,接收上面的routes參數。以下代碼:
const router = new vueRouter({ routes: routes });
3. 實列注入到vue根實列中
咱們接着把上面router實列注入待vue根實列中,咱們就可使用路由了。以下代碼:
new Vue({ el: '#app', router: router, render: h => h(Index) });
在配置代碼以前,咱們仍是看看咱們的項目整個目錄結構以下:(基於第十三篇文章的基礎之上再進行構建的)。
### 目錄結構以下: demo1 # 工程名 | |--- dist # 打包後生成的目錄文件 | |--- node_modules # 全部的依賴包 | |--- app | | |---index | | | |-- views # 存放全部vue頁面文件 | | | |-- components # 存放vue公用的組件 | | | |-- app.js # vue入口配置文件 | | | |-- router.js # 路由配置文件 | |--- views | | |-- index.html # html文件 | |--- webpack.config.js # webpack配置文件 | |--- .gitignore | |--- README.md | |--- package.json | |--- .babelrc # babel轉碼文件
在app/index/views 新建home.vue 和 xxx.vue 文件。
1. home.vue 代碼以下:
<style lang='stylus'> .home-container width 100% </style> <template> <div class="home-container"> <h1>歡迎來到Home</h1> <p>{{msg}}</p> </div> </template> <script type="text/javascript"> export default { data() { return { msg: '我是Home組件' } } } </script>
xxx.vue 代碼以下:
<style lang='stylus'> .xxx-container width 100% </style> <template> <div class="xxx-container"> <h1>歡迎來到xxx</h1> <p>{{msg}}</p> </div> </template> <script type="text/javascript"> export default { data() { return { msg: '我是XXX組件' } } } </script>
2. 接着在 app/index/views 新建index.vue, 代碼以下:
<style lang="stylus"> </style> <template> <div id="app"> <header> <router-link to='/home'>Home</router-link> <router-link to='/xxx'>XXX</router-link> </header> <!-- 對應組件的內容渲染到router-view中 --> <router-view></router-view> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
3. 在 app/index/router.js定義router,路徑到組件的映射。 添加以下代碼:
import Vue from 'vue'; import VueRouter from 'vue-router'; // 引入組件 import home from './views/home'; import xxx from './views/xxx'; // 告訴 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/home', component: home }, { path: '/xxx', component: xxx }, { path: '*', // 其餘沒有的頁面都重定向到 home頁面去 redirect: '/home' } ] var router = new VueRouter({ routes: routes }); export default router;
固然上面引入組件的方法,咱們還能夠懶加載的方式加載,懶加載引入的優勢是:當咱們訪問頁面的時候纔會去加載相關的資源,這樣的話,能提升頁面的訪問速度。
好比以下這樣:component: resolve => require(['@/views/HelloWorld'], resolve) // 使用懶加載
所以咱們能夠把上面的代碼寫成以下:
import Vue from 'vue'; import VueRouter from 'vue-router'; /* // 引入組件 import home from './views/home'; import xxx from './views/xxx'; */ // 告訴 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/home', component: resolve => require(['./views/home'], resolve) // 使用懶加載 }, { path: '/xxx', component: resolve => require(['./views/xxx'], resolve) // 使用懶加載 }, { path: '*', // 其餘沒有的頁面都重定向到 home頁面去 redirect: '/home' } ] var router = new VueRouter({ base: '/app/index', // 配置單頁應用的基路徑 routes: routes }); export default router;
如上base的含義:應用的基路徑,好比整個單頁應用服務在 /app/index 下,那麼base就應該設置爲 /app/index.
4. 實列注入到vue根實列中。
把路由注入到根實列中,啓動路由,咱們在app/index/app.js 入口文件添加以下代碼:
import Vue from 'vue'; import Index from './views/index'; // 引入路由 import router from './router'; new Vue({ el: '#app', router: router, render: h => h(Index) });
所以要運行上面代碼以前,咱們先要 下載 vue-router 到咱們項目中來,以下代碼命令:
npm i vue-router --save
下載完成後,咱們再來運行打包命令,npm run dev 後,就能夠啓動頁面了。
在頁面訪問以下
四:理解vue設置路由導航的兩種方法。
vue設置路由導航的兩種方法有 <router-link :to=''> 和 router.push().
4.1 to的值能夠是一個字符串路徑,或者一個描述地址的對象。好比以下都是能夠的。
// 字符串 <router-link to='/home'>Home</router-link> // 對象 <router-link :to="{path: '/home'}">Home</router-link> // 命名路由 <router-link :to="{name: 'home'}">Home</router-link> /* 若是是命名路由的話,須要在router.js 加上name字段,以下代碼: const routes = [ { path: '/home', name: 'home', component: resolve => require(['./views/home'], resolve) // 使用懶加載 }, { path: '/xxx', name: 'xxx', component: resolve => require(['./views/xxx'], resolve) // 使用懶加載 }, { path: '*', // 其餘沒有的頁面都重定向到 home頁面去 redirect: '/home' } ] */ // 直接路由帶查詢參數query,地址欄就變成 /home?id=1 <router-link :to="{path: 'home', query: {id: 1 }}">Home</router-link> // 若是是path的話,路由帶參數params的話,params是不會生效的。以下代碼 params的參數是不會在地址欄中顯示的。 <router-link :to="{path: 'home', params: {id: 1 }}">Home</router-link> // 命名路由帶路由參數params,地址欄仍是 /home, 可是能夠經過 this.$route.params.id拿到值的 <router-link :to="{name: 'home', params: {id: 1 }}">Home</router-link>
4.2 router.push()方法
// 支持字符串 this.$router.push('xxx'); // 支持對象 this.$router.push({ path: 'xxx' }); // 支持命名路由方式 this.$router.push({ name: 'xxx' }); // 直接路由帶查詢參數 query, 地址欄變成 /xxx?id=1 this.$router.push({ path: 'xxx', query: { id: 1 } }); // 命名路由帶查詢參數query,地址欄變成 /xxx?id=1 this.$router.push({ name: 'xxx', query: { id: 1 } }); // 若是提供了path,直接路由帶參數params, params不會生效,在xxx頁面經過 // console.log(this.$route.params.id) 是獲取不到值的。 this.$router.push({ path: 'xxx', params: { id: 1 } }); // 命名路由帶路由參數params,地址欄是/xxx。在xxx頁面經過 console.log(this.$route.params.id) 是能夠獲取到值的。 this.$router.push({ name: 'xxx', params: { id: 1 } });
總結:1. 不管是直接路由path仍是命名路由name,帶查詢參數query,地址欄會變成 /url?查詢參數名=查詢參數值
2. 直接路由path帶路由參數params,params不生效。在xxx頁面經過 console.log(this.$route.params.id) 是獲取不到值的。
3. 命名路由name帶路由參數params地址欄保持是 /url/路由參數值。在xxx頁面經過 console.log(this.$route.params.id) 是能夠獲取到值的。
五:理解動態路由和命名視圖
5.1 動態路由
動態路由也能夠叫作路由傳參。
在前面咱們介紹了路由導航功能是不能傳遞參數的,咱們能夠叫他們靜態路由,而能傳遞參數的路由模式,而且對應的路由數量是不肯定的,所以咱們能夠叫他動態路由。
應用場景:當咱們的多個頁面或組件都要被屢次重複利用的時候,咱們的路由都指向同一個組件,這時候從不一樣的地方進入相同的組件的時候,咱們根據傳遞的參數不一樣,來渲染不一樣的數據。
好比以下代碼:
const routes = [ { path: '/xxx/:id', // 動態路由信息 name: 'xxx', component: resolve => require(['./views/xxx'], resolve) // 使用懶加載 } ];
如上代碼 path: /xxx/:id, 這種形式,這樣定義以後,vue-router將會匹配全部的 /xxx/1, /xxx/2,.....
好比我如今有多個頁面須要進入xxx組件內,這時候咱們能夠在配置路由路徑後加個:id。index.vue 改爲以下代碼:
<template> <div id="app"> <header> <router-link to="home">Home</router-link> <router-link to='xxx/on'>XXX</router-link> </header> <!-- 對應組件的內容渲染到router-view中 --> <router-view></router-view> </div> </template>
當我點擊 XXX 時候,會進入xxx組件內,那麼在xxx.vue組件內,能夠經過 this.$route.params.id 獲取傳的參數值了。
以下圖所示:
5.2 理解命名視圖
有時候咱們想同時顯示多個視圖,好比一個單頁應用頁面,有側導航(sidebar) 和 頭部(header) 和 main(主內容)等三個視圖,這個時候命名視圖就派上用場了。
咱們能夠在頁面中擁有多個單獨命名的視圖,而不是和咱們上面同樣只有一個單獨的視圖。若是 router-view 沒有設置名字,那麼默認爲default。
如今咱們能夠在 app/index/components 新建文件夾爲sidebar, header, main, 及在各對應的目錄下新建index.vue.
如今咱們的項目的目錄結構變成以下了:
### 目錄結構以下: demo1 # 工程名 | |--- dist # 打包後生成的目錄文件 | |--- node_modules # 全部的依賴包 | |--- app | | |---index | | | |-- views # 存放全部vue頁面文件 | | | | |-- home.vue | | | | |-- index.vue | | | | |-- xxx.vue | | | |-- components # 存放vue公用的組件 | | | | |--- header | | | | | |-- index.vue # 公用的頭部組件 | | | | |--- main | | | | | |-- index.vue # 主體組件 | | | | |--- sidebar | | | | | |-- index.vue # 側導航公用的組件 | | | | | | | | |-- app.js # vue入口配置文件 | | | |-- router.js # 路由配置文件 | |--- views | | |-- index.html # html文件 | |--- webpack.config.js # webpack配置文件 | |--- .gitignore | |--- README.md | |--- package.json | |--- .babelrc # babel轉碼文件
app/index/components/header/index.vue 代碼以下:
<style lang="stylus"> * {margin: 0; padding: 0} .header-container width 100% height 50px background #000 div font-size 16px color #fff text-align center </style> <template> <div class="header-container"> <div>個人頭部導航</div> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
app/index/components/sidebar/index.vue 代碼以下:
<style lang="stylus"> .sidebar-container width 200px height 100% min-height 500px background red float left div font-size 12px color #fff text-align center </style> <template> <div class="sidebar-container"> <div>個人左側導航</div> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
app/index/components/main/index.vue 代碼以下:
<style lang="stylus"> .main-container margin-left 200px height 100% min-height 500px background green div font-size 12px color #fff text-align center </style> <template> <div class="main-container"> <div>個人主體部分</div> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
框架搭建完成後,咱們須要在index.vue 代碼變成以下:
<style lang="stylus"> </style> <template> <div id="app"> <!-- <header> <router-link to="/home">Home</router-link> <router-link to='/xxx/on'>XXX</router-link> </header> --> <router-view name="Header"></router-view> <router-view name="Sidebar"></router-view> <router-view name="Main"></router-view> <!-- 對應組件的內容渲染到router-view中 --> <router-view></router-view> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
接着咱們須要在router.js下配置代碼以下:
import Vue from 'vue'; import VueRouter from 'vue-router'; // 引入組件 import home from './views/home'; import xxx from './views/xxx'; // 告訴 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/home', name: 'home', components: { default: resolve => require(['./views/home'], resolve), // 使用懶加載 Header: resolve => require(['./components/header/index'], resolve), // 使用懶加載 Sidebar: resolve => require(['./components/sidebar/index'], resolve), // 使用懶加載 Main: resolve => require(['./components/main/index'], resolve) // 使用懶加載 } }, { path: '/xxx/:id', name: 'xxx', components: { default: resolve => require(['./views/xxx'], resolve), // 使用懶加載 Header: resolve => require(['./components/header/index'], resolve), // 使用懶加載 Sidebar: resolve => require(['./components/sidebar/index'], resolve), // 使用懶加載 Main: resolve => require(['./components/main/index'], resolve) // 使用懶加載 } }, { path: '*', // 其餘沒有的頁面都重定向到 home頁面去 redirect: '/home' } ] var router = new VueRouter({ base: '/app/index', // 配置單頁應用的基路徑 routes: routes }); export default router;
而後打包運行下,在瀏覽器上能夠看到以下圖所示的結構。
如上能夠看到,咱們可使用 命名視圖 來搭建咱們網站的框架,這能夠理解命名視圖的做用了。
六:理解嵌套路由
什麼是嵌套路由?好比咱們進入到咱們home頁面的時候,它下面還有分類,好比叫 java書籍,node書籍等,那麼當我點擊各個類目的時候,就對應到相應的組件。好比首先我進入的是 /home 這個路由,而後當我進入 /home下面的分類的 java書籍的話,那麼咱們的路由就是 /home/java, 若是進入分類的是 node書籍的話,那麼路由就是 /home/node 了。所以 vue提供了 childrens這個屬性來作這件事,它也是一組路由。
首先咱們在 app/index/views 下 新建 java.vue 和 node.vue.
java.vue代碼以下:
<style lang='stylus'> .java-container width 100% </style> <template> <div class="java-container"> <h1>歡迎來到java類書籍</h1> <p>{{msg}}</p> </div> </template> <script type="text/javascript"> export default { data() { return { msg: '我是java組件' } }, methods: { } } </script>
node.vue 代碼以下:
<style lang='stylus'> .node-container width 100% </style> <template> <div class="node-container"> <h1>歡迎來到node類書籍</h1> <p>{{msg}}</p> </div> </template> <script type="text/javascript"> export default { data() { return { msg: '我是node組件' } }, methods: { } } </script>
app/index/router.js 代碼就改爲以下:
import Vue from 'vue'; import VueRouter from 'vue-router'; // 引入組件 import home from './views/home'; import xxx from './views/xxx'; // 告訴 vue 使用 vueRouter Vue.use(VueRouter); const routes = [ { path: '/home', name: 'home', component: resolve => require(['./views/home'], resolve), // 子路由 children: [ { path: 'java', component: resolve => require(['./views/java'], resolve) }, { path: 'node', component: resolve => require(['./views/node'], resolve) } ] }, { path: '/xxx/:id', name: 'xxx', component: resolve => require(['./views/xxx'], resolve) }, { path: '*', // 其餘沒有的頁面都重定向到 home頁面去 redirect: '/home' } ] var router = new VueRouter({ base: '/app/index', // 配置單頁應用的基路徑 routes: routes }); export default router;
app/index/views/index.vue 代碼以下:
<style lang="stylus"> </style> <template> <div id="app"> <header> <router-link to="/home" tag='li'>Home</router-link> <router-link to="/home/java">java</router-link> <router-link to="/home/node">node</router-link> <router-link to='/xxx/on'>XXX</router-link> </header> <!-- <router-view name="Header"></router-view> <router-view name="Sidebar"></router-view> <router-view name="Main"></router-view> --> <!-- 對應組件的內容渲染到router-view中 --> <router-view></router-view> </div> </template> <script type="text/javascript"> export default { data() { return { } } } </script>
如上代碼增長完成後,進行打包,編譯都正常,可是點擊java或node的時候,子路由一直沒有渲染到對應的組件,網上不少資料說,子路由多寫了 /, 可是我router.js裏面也沒有這些東西的,可是通過搜索,發現問題並非在這裏,而是說在嵌套的子模塊裏面引用子路由的時候,也須要加上 <router-view></router-view> 這句代碼,以下是home.vue 代碼:
<template> <div class="home-container"> <h1>歡迎來到Home</h1> <p>{{msg}}</p> <p @click="func">進入index頁面</p> <router-view></router-view> </div> </template>
注意:路由嵌套的真正的含義是:點擊子路由的時候,父級組件仍是會顯示的,子組件也會顯示的,這纔是使用子路由嵌套的用途。
若是僅僅想顯示子組件的話,不想顯示父組件的話,那就不要使用路由嵌套,直接使用兄弟路由,寫死路徑便可。
好比
const router = [ { path: '/home', name: 'home', component: resolve => require(['./views/home'], resolve), }, // 兄弟路由 { path: '/home/java', name: 'home', component: resolve => require(['./views/java'], resolve), } ]
github源碼 webpack+vue+router