概述
前端路由
路由就是根據(jù)不同的url地址來展示不同的內(nèi)容或頁面.
Vue Router 是 Vue.js 官方的路由管理器
github: https://github.com/vuejs/vue-router
中文官方網(wǎng)站https://router.vuejs.org/zh/
中文API文檔 https://router.vuejs.org/zh/api/
vue-router安裝與結(jié)構(gòu)
npm isntall vue-router --save
vue-router是Vue的一個插件闲勺,需要在Vue的全局應(yīng)用中通過Vue.use()將他納入到Vue實例中
創(chuàng)建項目 router-demo
選擇Manually select features
$vue create router-demo
Vue CLI v3.9.2
? Please pick a preset: Manually select features
? Check the features needed for your project:
? Babel
? TypeScript
? Progressive Web App (PWA) Support
?? Router
? Vuex
? CSS Pre-processors
? Linter / Formatter
? Unit Testing
? E2E Testing
會在當(dāng)前項目src目錄下自動創(chuàng)建router.js文件
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/about',
name: 'about',
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
}
]
})
一條路由的實現(xiàn)需要三部分:
name 名稱
path, 路徑
component 組件
啟動路由器
在main.js 入口文件中啟動路由器
Helloworld
接著使用上面的
- 創(chuàng)建組件Bar.vue
<template>
<div >
<h1>Bar</h1>
<router-link to="foo">跳轉(zhuǎn)到Foo</router-link>
</div>
</template>
<script>
export default {
name: 'Bar',
}
</script>
- 創(chuàng)建組件Foo.vue
<template>
<div>
<h1>Foo</h1>
<router-link to="bar">跳轉(zhuǎn)到Bar</router-link>
</div>
</template>
<script>
export default {
name: "Foo",
}
</script>
<style scoped>
</style>
- 創(chuàng)建文件router,在其目錄下創(chuàng)建index.js文件
import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import Bar from '../components/Bar'
import Foo from '../components/Foo'
export default new Router({
routes: [
{
path:"/",
redirect:"/foo"
},
{
path: '/foo',
component: Foo
},
{
path: '/bar',
component: Bar
}
]
});
- 將App.vue修改
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<router-view></router-view>
</div>
</template>
<style>
#app {
text-align: center;
margin-top: 60px;
}
</style>
- 在main.js注冊路由器
import Vue from 'vue'
import App from './App.vue'
import router from './router/index'
Vue.config.productionTip = false;
new Vue({
router,
render: h => h(App),
}).$mount('#app')
動態(tài)路由
創(chuàng)建組件User.vue
<template>
<div>
{{$route.params.id}}
</div>
</template>
修改router目錄的index文件
import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import User from '../components/User'
export default new Router({
routes: [
{
path:'/user/:id',
component:User
}
]
});
訪問的http://localhost:8080/#/user/12347
設(shè)置“路徑參數(shù)”,將User.vue 修改成
<template>
<div>
{{$route.query.id}}
</div>
</template>
增加路由配置
{
path:'/user',
component:User
}
訪問路徑 http://localhost:8080/#/user?id=2
嵌套路由router-view
創(chuàng)建組件文件Profile.vue
<template>
<div>
用戶畫子界面
</div>
</template>
<script>
export default {
name: "Profile"
}
</script>
<style scoped>
</style>
修改路由文件router/index.js
import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import User from '../components/User'
import Profile from '../components/Profile'
export default new Router({
routes: [
{
path:'/user',
component:User,
children:[
{
path:"profile",
component:Profile
}
]
},
{
path:'/user/:id',
component:User
}
]
});
同一個路徑可以匹配多個路由,此時睹栖,匹配的優(yōu)先級就按照路由的定義順序:誰先定義的赃额,誰的優(yōu)先級就最高伸辟。
訪問http://localhost:8080/#/user/profile
路由組件傳參
方式 1: 路由路徑攜帶參數(shù)(param/query)
配置路由
children: [
{
path: 'mdetail/:id',
component: MessageDetail
}
]
路由路徑
參數(shù)傳遞 注意需要加上冒號:
<router-link :to="'/home/message/mdetail/'+m.id">{{m.title}}</router-link>
路由組件中讀取請求參數(shù),獲取傳遞數(shù)據(jù) 注意是route
而不是router
this.$route.params.id
方式2 <router-view>屬性攜帶數(shù)據(jù)
<router-view :msg="msg"></router-view>
緩存路由組件對象
- 默認(rèn)情況下, 被切換的路由組件對象會死亡釋放, 再次回來時是重新創(chuàng)建的
- 如果可以緩存路由組件對象, 可以提高用戶體驗
<keep-alive>
<router-view></router-view>
</keep-alive>
路由導(dǎo)航
相關(guān) API
- this.$router.push(path): 相當(dāng)于點擊路由鏈接(可以返回到當(dāng)前路由界面)
// 字符串
router.push('home')
// 對象
router.push({ path: 'home' })
// 命名的路由
router.push({ name: 'user', params: { userId: '123' }})
// 帶查詢參數(shù),變成 /register?plan=private
router.push({ path: 'register', query: { plan: 'private' }})
注意:如果提供了 path,params 會被忽略稻扬,上述例子中的 query 并不屬于這種情況攒巍。取而代之的是下面例子的做法嗽仪,你需要提供路由的 name 或手寫完整的帶有參數(shù)的 path:
const userId = '123'
router.push({ name: 'user', params: { userId }}) // -> /user/123
router.push({ path: `/user/${userId}` }) // -> /user/123
// 這里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user
- this.$router.replace(path): 用新路由替換當(dāng)前路由(不可以返回到當(dāng)前路由界面)
- this.$router.back(): 請求(返回)上一個記錄路由
- this.$router.go(-1): 請求(返回)上一個記錄路由
- this.$router.go(1): 請求下一個記錄路由
路由元數(shù)據(jù)
定義路由的時候可以配置 meta 字段:
import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import User from '../components/User'
import Profile from '../components/Profile'
const router = new Router({
routes: [
{
path:'/user',
component:User,
children:[
{
path:"profile",
component:Profile
}
]
},
{
path:'/user/:id',
component:User,
meta:{
requireAuth:true
}
}
]
});
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requireAuth)) {
next()
}
})
export default router
路由組件傳參
使用route的props進(jìn)行解耦.提高組件的復(fù)用,同時不改變url
修改user.vue組件文件如下
<template>
<div>
<p>姓名:{{this.name}}</p>
</div>
</template>
<script>
export default {
name: "User",
props:["name"]
}
</script>
<style scoped>
</style>
修改路由文件router/index.js 文件如下
import Router from 'vue-router'
import Vue from 'vue'
Vue.use(Router)
import User from '../components/User'
const router = new Router({
routes: [
{
path:"/user/profile",
component:User,
props:{name:"tony"}
},
{
path:"/user/search",
component:User,
props: (route)=>({name:route.query.name})
},
{
path:"/user/:name",
component:User,
props:true
},
]
});
function searchName(route){
return {name:(route.query.name)}
}
export default router
函數(shù)返回的是對象類型的 ,props: (route)=>({name:route.query.name}) 等價于
function searchName(route){
return {name:(route.query.name)}
}
訪問接口http://localhost:8081/#/user/search?name=tony
訪問接口http://localhost:8081/#/user/profile
訪問接口http://localhost:8081/#/user/tony
路由懶加載
當(dāng)打包構(gòu)建應(yīng)用時柒莉,JavaScript 包會變得非常大闻坚,影響頁面加載。如果我們能把不同路由對應(yīng)的組件分割成不同的代碼塊兢孝,然后當(dāng)路由被訪問的時候才加載對應(yīng)組件窿凤,這樣就更加高效了。
結(jié)合 Vue 的異步組件和 Webpack 的代碼分割功能跨蟹,輕松實現(xiàn)路由組件的懶加載雳殊。
首先,可以將異步組件定義為返回一個 Promise 的工廠函數(shù) (該函數(shù)返回的 Promise 應(yīng)該 resolve 組件本身):
const Foo = () => Promise.resolve({ /* 組件定義對象 */ })
第二窗轩,在 Webpack 2 中夯秃,我們可以使用動態(tài) import
語法來定義代碼分塊點 (split point):
import('./Foo.vue') // 返回 Promise
注意
如果您使用的是 Babel,你將需要添加 syntax-dynamic-import
插件痢艺,才能使 Babel 可以正確地解析語法仓洼。
結(jié)合這兩者,這就是如何定義一個能夠被 Webpack 自動代碼分割的異步組件堤舒。
const Foo = () => import('./Foo.vue')
在路由配置中什么都不需要改變色建,只需要像往常一樣使用 Foo
:
const router = new VueRouter({
routes: [
{ path: '/foo', component: Foo }
]
})
把組件按組分塊
有時候我們想把某個路由下的所有組件都打包在同個異步塊 (chunk) 中。只需要使用 命名 chunk
植酥,一個特殊的注釋語法來提供 chunk name (需要 Webpack > 2.4)镀岛。
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue')
const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
Webpack 會將任何一個異步模塊與相同的塊名稱組合到相同的異步塊中弦牡。
組件渲染
在index.html處有個id="app"的div,在App.vue中也有一個id="app"的div漂羊。頁面渲染的就是這個組件驾锰。
在這個App.vue中有個router-view標(biāo)簽,默認(rèn)在這渲染當(dāng)路由為"/"指向的組件走越,路由設(shè)置在src/router/index.js中
這樣就可以使用HelloWorld組件了椭豫。
這張圖可以更清楚得讓大家明白router-view標(biāo)簽的作用
*注意,當(dāng)有多個組件的時候旨指,就不是component屬性而是components赏酥,記得注冊的組件上面都要用import導(dǎo)入
當(dāng)組件里有自己的子組件的情況下,就需要使用到router-link標(biāo)簽了谆构,它其實是一個a標(biāo)簽
那么router-view和router-link的區(qū)別是什么呢裸扶?
目前來說,router-link和router-view結(jié)合使用搬素,可以在組件中通過點擊渲染子組件呵晨;
單獨使用router-view就可以在當(dāng)前組件中重根據(jù)name屬性選擇渲染組件;
單獨使用router-link就可以整個切換到to屬性指定路由的組件熬尺;
最后摸屠,這個單頁面開發(fā)的意思就是,這個項目只有index.html這個頁面粱哼,我們通過使用不同的組件像拼裝機器人一樣獲得不同的頁面展示季二,而src下的App.vue就是所有組件的父組件,所有其它組件都通過路由渲染到它里面的router-view中揭措,然后再將App.vue渲染到index.html中胯舷。