[TOC]
要点:
- 路由的不同页面实质就是动态加载不同的组件
- 每一个xx.vue就是一个组件
- SPA(单页应用)单核心就是前端路由,单页应用不仅仅是在页面交互是无刷新的,连页面跳转都是无刷新的,为了实现单页应用,所以就有了前端路由。 类似于服务端路由,前端路由实现起来其实也很简单,就是匹配不同的 url 路径,进行解析,然后动态的渲染出区域 html 内容。
本文使用vue-cli搭建的应用
分类
前端路由分为两种:
- hash模式:利用url的hash,也就是锚点
#
,js需要通过hashChange事件来监听url的改变,ie7以下需要轮询 - history模式:另一种就是利用html5的history模式,像后端路由一样用
/
分割,但是页面并没有跳转
hash形式路由
- hash路由形式:
http://www.xxx.com/#/login
- url 的 hash 是以 # 开头,原本是用来作为锚点,从而定位到页面的特定区域。每次 hash 值的变化,还会触发hashchange 这个事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange来实现更新页面部分内容的操作:12345function matchAndUpdate () {// 匹配 hash 做 dom 更新操作}window.addEventListener('hashchange', matchAndUpdate)
history模式路由
- HTML5 规范中提供了
history.pushState
和history.replaceState
来进行路由控制。通过这两个方法,可以实现改变 url 且不向服务器发送请求。 - 使用这种模式需要服务端的支持,因为没有 # 号,所以当用户刷新页面之类的操作时,浏览器还是会给服务器发送请求。为了避免出现这种情况,所以这个实现需要服务器的支持,需要把所有路由都重定向到根页面。。
- 使用history模式需要在vue router的router/index.js中设置
mode: 'history'
,没写这个可能会不显示
vue-router使用
目录说明:在/src
目录下有个/router/
目录,路由设置一般在/router/
目录下文件中设置,一般/src/router/index.js
是路由入口(vue-cli)
1、在/src/router/index.js
中引入 import Router from 'vue-router'
;
2、使用插件:Vue.use(VueRouter);
3、创建路由规则,在routes
属性中创建路由规则
4、将其路由对象传递给Vue的实例,options中加入 router:router
5、在app.vue中留坑<router-view></router-view>
,路由切换时切换的是<router-view>
挂载的组件,其他内容不会改变
这里的 <router-view>
是最顶层的出口,渲染最高级路由匹配到的组件。同样地,一个被渲染组件同样可以包含自己的嵌套 <router-view>
|
|
routes的参数解析
path
:规定路由。
在配置文件里以冒号的形式设置参数可以用来传递参数123456{path:'/params/:newsId/:newsTitle',name: 'test',meta: 'hello',component:Params}
在目标页面中可以直接用$route.params.newsId
来获取参数
name
:命名路由,可以通过name值跳转到指定路由1<router-link :to="{ name: 'infoName', params: { userId: 123 }}">User</router-link>
或
跳转到name是infoName到命名路由
meta
:存一些其他信息component
:映射的组件
vue-router跳转
vue-router有两种跳转页面的方式:
- 使用内置的
<router-link>
组件 - 使用router实例方法,如
$route.push()
router-link
|
|
router-link
相当于a标签
router-link
的一些属性
to
指定要跳转的路径,也可以使用v-bind动态绑定,html5的history模式下会拦截点击tag
: 规定<router-link>
渲染成什么标签replace
:不会留下history记录,不能使用后退键active-class
:路由匹配成功时会自动给当前元素设置一个名为router-link-active的class
router实例的方法进行跳转
$router.push(locationObj, onCompleteCallback, onAbortCallback)
:类似于window.location.href
$router.replace(locationObj, onCompleteCallback, onAbortCallback)
:不会向history添加历史记录,而是替换掉当前的history$router.go(n)
:类似于window.history.go(),前进后退多少步
router.push(locationObj, onCompleteCallback, onAbortCallback)
:在 router.push 或 router.replace 中提供 onCompleteCallback 和 onAbortCallback 回调作为第二个和第三个参数。这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用。
Vue Router 的导航方法 (push、 replace、 go) 在各类路由模式 (history、 hash 和 abstract) 下表现一致
$router
与$route
$router
是VueRouter实例,代表路由器http://localhost:8080/info/3/?order=1234
$route
是当前路由的对象
下面是/info
路由的$router
打印出来的结果,有属性fullPath
、path
、name
、params
、query
等http://localhost:8080/info/3/?order=1234
嵌套路由
- 形式:
/user/foo/profile
、/user/foo/posts
- 要注意,以 / 开头的嵌套路径会被当作根路径。嵌套路由的path内路径不要以/开头
- 将嵌套的路由放在children数组中,嵌套路由的页面显示在它的父级组件的
<router-view>
中1234567891011121314151617181920const router = new VueRouter({routes: [{ path: '/user/:id', component: User,children: [{// 当 /user/:id/profile 匹配成功,// UserProfile 会被渲染在 User 的 <router-view> 中path: 'profile',component: UserProfile},{// 当 /user/:id/posts 匹配成功// UserPosts 会被渲染在 User 的 <router-view> 中path: 'posts',component: UserPosts}]}]})
命名视图
同时展示多个视图时用,比如侧导航和main内容区同时显示,这时可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default
重定向
可参考:vue-router重定向链接
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b
别名
别名就是访问别名到url和访问原本的url产生的效果是一样的
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样
路由组件传参
上面已经提到过路由通过url中/info/:id
这种传参方法,在目标页面用$route.params.id
获取参数,这样做法缺点是增加了代码耦合性
通过 props 可以实现解耦
如果 props 被设置为 true,route.params 将会被设置为组件属性
设置404页面
当所有路由规则都没有匹配到时显示
导航守卫
导航:表示路由正在发生变化的这个过程
在路由发生变化的过程中设置了几个钩子,在钩子中可以干一些事,比如路由改变前改变页面的title
钩子:
beforeEach
:全局前置钩子,路由即将改变前,设置页面标题可以在该钩子内完成- to:即将进入的目标的路由对象(目标的$route)
- from:即将离开的路由对象
- next:调用该方法后才能进入下一个钩子,一定要调用该方法来 resolve 这个钩子。执行效果依赖 next 方法的调用参数。
- next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
- next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
- next(‘/‘) 或者 next({ path: ‘/‘ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
- next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。12345const router = new VueRouter({ ... })router.beforeEach((to, from, next) => {// ...})
afterEach
:它是一个全局后置钩子,全局后置不会接受 next 函数也不会改变导航本身:123router.afterEach((to, from) => {// ...})
完整的导航解析流程:
导航被触发。
在失活的组件里调用离开守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
在路由配置里调用 beforeEnter。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
过度效果
<router-view>
是基本的动态组件,所以我们可以用 <transition>
组件给它添加一些过渡效果:
通过name属性还可以定义不同的动画效果
路由懒加载
|
|
把组件按组分块:
有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name。
比较好的文章:
vue-router 源码:前端路由
前端路由简介以及vue-router实现原理
vue-router详解
vue-router官方文档