写在前面
Vue Router 是 Vue.js 官方的路由管理器,我们用它来完成前端的路由管理。
PART01:做一个简单的导航
先安装vue-router
- vue create day03 ~ 新建今天的项目
- cd day03 ~ 进入项目
- npm install vue-router --save ~ 安装vue-router
新建两个页面
//components/Page1.vue
<template>
<div>我是页面1</div>
</template>
<script>
export default{
}
</script>
//components/Page2.vue
<template>
<div>我是页面2</div>
</template>
<script>
export default{
}
</script>
新建一个路由控制器
//routes.js
import VueRouter from "vue-router"
import Page1 from "./components/Page1"
import Page2 from "./components/Page2"
export default new VueRouter({
routes : [
{path:"/page1",component:Page1},
{path:"/page2",component:Page2},
]
})
在main.js里做个引入,使用这个路由控制器
//main.js
import VueRouter from "vue-router"
import router from "./routes"
Vue.use(VueRouter)
new Vue({
router : router,
……
})
在App.vue里体验一下这个小小的导航
<template>
<div id="app">
<div>
<router-link to="/page1">page1</router-link>
<router-link to="/page2">page2</router-link>
</div>
<hr/>
<router-view></router-view>
</div>
</template>
<script>
export default{
}
</script>
PART02:前端路由的两种模式
hash模式
hash 指的是 url后面的# 及 跟随该#的一系列字符。
hash原本是用来做页面定位的,hash值的改变不会触发请求但会触发hashchange事件。
通常我们用 监听hashchange事件 并 修改window.location.hash值 的方式,实现hash模式。
缺点:url丑、和锚点冲突、复杂参数难传、不利于SEO。
支持:能支持到IE8。
history模式
通过window.history.pushState()和window.history.replaceState()修改url,会导致向服务器发送请求,这就是history模式。
在history里增加一条记录:window.history.pushState(state,title,url)
修改history里的一条记录:window.history.replaceState(state, title, url)
其中:state是需要保存的数据,title是标题,url是要设定的url。
另外:浏览器的前进后退会触发popstate事件,上述方法不触发该事件。
支持:这两个方法是H5新加的,所以能支持到IE10。
vue-router中的它们
默认为hash模式,可以在routes.js中修改成history模式。
//routes.js
……
export default new VueRouter({
mode : "history",
……
PART03:动态路由
实际项目中,存在大量的动态路由,如产品页等等。
vue-router也支持通过参数传递的方式实现动态路由。
通过 this.$route 获取路由参数
//routes.js
……
export default new VueRouter({
routes : [
{path:"/page/:id",component:Page}
]
})
//App.vue
<template>
<div id="app">
<router-link to="/page/aaa">aaa</router-link>
<router-link to="/page/bbb">bbb</router-link>
<hr/>
<router-view></router-view>
</div>
</template>
//component/Page.vue
<template>
<p>我是:{{name}}</p>
</template>
<script>
export default{
computed : {
name(){
return this.$route.params.id
}
}
}
</script>
通过 props 获取路由参数
//routes.js
……
export default new VueRouter({
routes : [
{path:"/page/:id",props:true,component:Page}
]
})
//App.vue
<template>
<div id="app">
<router-link to="/page/aaa">aaa</router-link>
<router-link to="/page/bbb">bbb</router-link>
<hr/>
<router-view></router-view>
</div>
</template>
//components/Page.vue
<template>
<div>我是:{{id}}</div>
</template>
<script>
export default{
props:["id"]
}
</script>
PART04:路由嵌套
假设我们的某些页面带导航,而另一些页面不用导航。
我们又不想在每一处都写一遍,则可以使用嵌套的方式来解决。
//App.vue - 把导航搬走,只留个占位符
<template>
<div id="app">
<router-view></router-view>
</div>
</template>
//components/Inner.vue - 把带导航的页统一到一起
<template>
<div>
<router-link to="/inner/page1">page1</router-link>
<router-link to="/inner/page2">page2</router-link>
<router-link to="/inner/page3/aaa">aaa</router-link>
<hr/>
<router-view></router-view>
</div>
</template>
//routes.js - 把嵌套的路由,写在inner的children里
export default new VueRouter({
routes : [
{path:"/login",component:Login},
{
path:"/inner",
component:Inner,
children:[
{path:"page1",component:Page1},
{path:"page2",component:Page2},
{path:"page3/:id",props:true,component:Page3}
]
}
]
})
PART05:路由的生命周期
在实际项目中,我们可能需要对用户做 是否登录 、 是否有权访问 等判断,还有可能需要做 全局Loading 等优化。
这就需要我们知道,做这些操作的时机,这就是路由生命周期的意义。
用一个小例子理顺一下
- 把页面组件准备好
//App.vue
<template>
<div id="app">
<router-link to="/page1">页面1</router-link>
<router-link to="/page2/aaa">商品aaa</router-link>
<router-link to="/page2/bbb">商品bbb</router-link>
<hr/>
<router-view></router-view>
</div>
</template>
//components/Page1.vue
<template>
<p>我是页面1</p>
</template>
//components/Page2.vue
<template>
<p>我是商品:{{product}}</p>
</template>
<script>
export default{
props:["product"]
}
</script>
- 路由控制器里的生命周期
//routes.js
import VueRouter from "vue-router"
import Page1 from "./components/Page1"
import Page2 from "./components/Page2"
let routes = new VueRouter({
mode : "history",
routes : [
//在这里做一个首页的重定向
{path:"/",redirect:"/page1"},
{path:"/page1",component:Page1},
{path:"/page2/:product",props:true,component:Page2}
]
})
//beforeEach - 在所有路由跳转前执行
routes.beforeEach((to,from,next)=>{
console.log(beforeEach)
next()
})
//beforeResolve - 在所有路由内部enter执行完后
routes.beforeResolve((to,from,next)=>{
console.log(beforeResolve)
next()
})
//afterEach - 在所有路由跳转后执行
routes.afterEach((to,from)=>{
console.log(afterEach)
})
export default routes
- 修改一下Page2,感受一下组件内部生命周期
<script>
export default{
props : ["product"],
beforeRouteEnter(to,from,next){
console.log("page2路由进入前")
next()
},
beforeRouteUpdate(to,from,next){
console.log("page2路由没变,但路由参数变了")
next()
},
beforeRouteLeave(to,from,next){
console.log("page2路由离开前")
next()
}
}
</script>
- 测试一下
- 访问:/page1
- 打印:
beforeEach
beforeResolve
afterEach
- 跳转:/page2/aaa
- 打印:
beforeEach
beforeResolve
page2路由进入前
afterEach
- 跳转:/page2/bbb
- 打印:
beforeEach
beforeResolve
page2路由没变,但路由参数变了
afterEach
- 跳转:/page1
- 打印:
page2路由离开前
beforeEach
beforeResolve
afterEach
PART06:两个小技巧
nginx配置
我们一直是利用vue-cli脚手架写的项目,这里的路由监听是webpack做的。
项目发布后,就要去配置一下nginx,将所有的访问都映射到index。
这是因为我们的路由是前端控制的,如果nginx直接访问某个url,他会尝试获取这个url下的资源,会抛出404。
异步组件
我们前面加载组件的方法,都是同步的。
如果组件很多而且有些并不常用时,我们可以把它做成异步组件。
异步组件在打包的时候不会被打进去,访问的时候才会加载。
//routes.js
import VueRouter from "vue-router"
import Page1 from "./components/Page1"
export default new VueRouter({
routes : [
//同步组件
{path:"/page1",component:Page1}
//异步组件
{
path:"/page2",
component:()=>import "./components/Page2"
}
]
})
网友评论