vue-router概述
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,可用于构建单页面应用(SPA),vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。与传统的页面应用相比可做到更新视图而不请求页面。
路由搭建(基于vue cli4)
1. 创建组件
首先需要创建出需要用到的组件,这里创建的是home和about组件
<!-- src/views/home.vue-->
<template>
<div class='home'>
<h1>首页</h1>
</div>
</template>
<script>
//导出组件
export default {
components: {
name:"home"
}
}
</script>
<!-- src/views/about.vue -->
<template>
<div class='about'>
<h2>关于页</h2>
</div>
</template>
<script>
//导出组件
export default {
components: {
name:"about"
}
}
</script>
2.创建路由与映射路由
- 要想在一个模块化工程中使用路由,必须要通过
Vue.use()明确地安装路由功能 - 在实现路由映射时组件有两种导入方式,使用懒加载的方式导入在项目打包后运行速度更快
- 创建路由实例中的mode参数有Hash模式和History模式,使用默认的hash模式URL会前面会带有'#',想要更好看的URL可以使用history模式
- hash 模式使用 URL 的 hash 来模拟一个完整的 URL,当 URL 改变时,页面不会重新加载,改变 hash 不会重新加载页面;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置,hash 模式的原理是 onhashchange 事件(监测hash值变化),可以在 window 对象上监听这个事件。
- history模式利用了html5 history interface 中新增的
pushState()和replaceState()方法,这两个方法应用于浏览器记录栈,在当前已有的 back、forward、go 基础之上,它们提供了对历史记录修改的功能。当它们执行修改时虽会改变当前的 URL ,但浏览器不会立即向后端发送请求。
/*-------src/router/index.js--------*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import home from '../views/home' //普通导入方式
Vue.use(VueRouter)
//在此实现路由映射
const routes = [{
path:'',
redirect: '/home' //redirect重定向实现默认页
},
{
path: '/home',
name: 'home',
component: home
},
{
path: '/about',
name: 'about',
component: () => import( '../views/about.vue') //懒加载导入方式
}
]
//创建路由实例
const router = new VueRouter({
mode: 'history', //使用history模式
base: process.env.BASE_URL,
routes
})
//导出router
export default router
3. router-link与router-view
<router-link>组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的a标签,可以通过配置 tag 属性生成别的标签.。另外,当目标路由成功激活时,链接元素自动设置一个表示激活的 CSS 类名。 关于router-link的具体属性可查阅:router.vuejs.org/zh/api/#rou…<router-view>组件是一个 functional 组件,渲染路径匹配到的视图组件。router-view 渲染的组件还可以内嵌自己的 router-view,根据嵌套路径,渲染嵌套组件。 关于router-view的具体属性可查阅:router.vuejs.org/zh/api/#rou…
<!--- src/App.vue --->
<template>
<div id="app">
<div id="nav">
<router-link to="/home">Home</router-link>
<router-link to="/about">About</router-link>
</div>
<router-view/>
</div>
</template>
/*--- src/main.js ---*/
import Vue from 'vue'
import App from './App.vue'
import router from './router' //导入router
Vue.config.productionTip = false
//创建vue实例
new Vue({
router,
render: h => h(App)
}).$mount('#app')
4. 执行过程
- vue-router首先会去查找
<router-link>的路由映射 - 然后根据路由映射找到匹配的组件
- 最后将组件渲染到
<router-view>标签
动态路由
此处以添加user页为例,user页面的URL地址将表现为/user/userName 实现步骤为创建user组件=>添加user路由映射=>App.vue页面定义user_id变量并进行渲染
<!-- src/views/user.vue -->
<template>
<div class="user">
<!--getUserId为计算属性-->
<h1>{{ getUserId }}</h1>
</div>
</template>
<script>
export default {
components: {
name: "user",
},
computed: {
getUserId() {
//此处为route,表示当前活跃路由
return this.$route.params.user_id;
},
},
};
</script>
/*-------src/router/index.js---------*/
import Vue from 'vue'
import VueRouter from 'vue-router'
import home from '../views/home'
Vue.use(VueRouter)
//实现路由映射
const routes = [{
path: '',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: home
},
{
path: '/about',
name: 'about',
component: () => import('../views/about')
},
//user路由映射
{
path: '/user/:user_id',
name: 'user',
component: () => import('../views/user')
}
]
//创建路由实例
const router = new VueRouter({
mode: 'history',
base: process.env.BASE_URL,
routes
})
//导出router
export default router
<!-- src/App.vue -->
<template>
<div id="app">
<div id="nav">
<router-link to="/home">首页</router-link>
<router-link to="/about">关于</router-link>
<router-link :to="'/user/' + user_id">用户</router-link>
<!--这里使用了v-bind,动态绑定user_id-->
</div>
<router-view />
</div>
</template>
<script>
export default {
name: "App",
data() {
return {
user_id: "xiehaopei",
};
},
};
</script>
嵌套路由
目前想在首页中再嵌套一个路由选择,可以在home页面通过路由渲染出message页面和news页面
<!-- src/views/home_message -->
<template>
<div class="">
<ul>
<li>消息1</li>
<li>消息2</li>
<li>消息3</li>
<li>消息4</li>
<li>消息5</li>
</ul>
</div>
</template>
<script>
export default {
components: {
name: "message"
}
};
</script>
<!-- src/views/home_news.vue -->
<template>
<div class="">
<ul>
<li>新闻1</li>
<li>新闻2</li>
<li>新闻3</li>
<li>新闻4</li>
<li>新闻5</li>
</ul>
</div>
</template>
<script>
export default {
components: {
name: "news"
}
};
</script>
<!-- src/views/home.vue -->
<template>
<div class="home">
<h1>
首页
</h1>
<router-link to="/home/news">新闻</router-link>
<router-link to="/home/message">消息</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "home",
};
</script>
/*-------src/router/index.js---------*/
/*---routes片段---*/
{
path: '/home',
name: 'home',
component: home,
children: [
{
path: "",
redirect: "news"
},
{
path: "news",
component: ()=>import('../views/home_news')
},
{
path: "message",
component: () => import('../views/home_message')
}
]
}
这样就可以实现在一个页面中通过路由调用不同组件的效果了
路由对象
$route
$route是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数。
- $route.path 字符串,等于当前路由对象的路径,会被解析为绝对路径,如 "/home/news" 。
- $route.params 对象,包含路由中的动态片段和全匹配片段的键值对
route.query.favorite == 'yes'` 。
- $route.router 路由规则所属的路由器(以及其所属的组件)。
- $route.matched 数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。
- $route.name 当前路径的名字,如果没有使用具名路径,则名字为空。
$router
$router 是“路由实例对象",即使用 new VueRouter创建的实例,包括了路由的跳转方法,钩子函数等。 跳转方法示例:
- $router.go(-1) 跳转到上一次浏览的页面
- $router.replace('url') 跳转到指定地址
- $router.push('/home') 通过push进行跳转
$router.push和$router.replace的区别:
- 使用push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。
- 使用replace方法不会向 history 添加新记录,而是替换掉当前的 history 记录,即当replace跳转到的网页后,‘后退’按钮不能查看之前的页面。
导航守卫
守卫方法参数
每个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象from: Route: 当前导航正要离开的路由next: Function: 一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数,next方法参数如下:next()方法会进行管道中的下一个钩子,如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。next('/')或者next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: 'home' 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。next(error): (vue router2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。 确保要调用 next 方法,否则钩子就不会被 resolved。
全局前置守卫
可以使用 router.beforeEach注册一个全局前置守卫,当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
router.beforeEach((to, from, next) => {})
全局后置钩子
也可以注册全局后置钩子,然而和守卫不同的是这些钩子不会接受 next 函数也不会改变导航本身
router.afterEach((to, from) => {})
路由独享守卫
可以在路由配置上直接定义 beforeEnter守卫,这些守卫与全局前置守卫的方法参数是一样的
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {}
}
]
组件内守卫
beforeRouteEnter在渲染该组件的对应路由被 confirm 前调用,不能获取组件实例this,因为当守卫执行前,组件实例还没被创建beforeRouteUpdate在当前路由改变,但是该组件被复用时调用。 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。可以访问组件实例 thisbeforeRouteLeave在导航离开该组件的对应路由时调用,可以访问组件实例 this
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {},
beforeRouteUpdate (to, from, next) {},
beforeRouteLeave (to, from, next) {}
}
导航流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫。 - 在路由配置里调用
beforeEnter。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter。 - 调用全局的
beforeResolve守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发 DOM 更新。
- 用创建好的实例调用
beforeRouteEnter守卫中传给next的回调函数。
设置404页面
当用户输错页面时会我们希望能够显示出404页面,通过以下配置可以得到一个自定义的404页面
/*-------src/router/index.js--------*/
//path:'*'表现为输入地址不匹配时,自动显示出Error.vue的文件内容
const routes = [{
path:'*',
component: () => import('../views/Error.vue')
}]
<!-- src/views/Error.vue-->
<template>
<div class='error'>
<h1>404</h1>
</div>
</template>
<script>
//导出组件
export default {
components: {
name:"Error"
}
}
</script>
<style>
</style>