1.1.Vue路由基础

Vue属于单页应用(SPA),即整个应用程序中只有一个html页面。
在单页应用中(SPA),由于只是更改DOM来模拟多页面,所以页面浏览历史记录的功能就丧失了。此时,就需要前端路由来实现浏览历史记录的功能。

  1. <div id="app">
  2. <p>
  3. <!-- 使用 router-link 组件来导航. to属性指定导航地址-->
  4. <router-link to="/home">home</router-link>
  5. <router-link to="/news">news</router-link>
  6. </p>
  7. <!-- 路由出口(路由匹配到的组件将渲染在这里) -->
  8. <router-view></router-view>
  9. </div>
  10. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  11. <script src="https://cdn.jsdelivr.net/npm/vue-router/dist/vue-router.js"></script>
  12. <script type="text/javascript">
  13. // 1. 定义(路由)组件。
  14. const Home = {
  15. template: '<div>首页</div>'
  16. }
  17. const News = {
  18. template: '<div>新闻</div>'
  19. }
  20. // 2. 定义路由规则对象(每个路由应该映射一个组件)
  21. const routes = [
  22. {
  23. path: '/home',
  24. component: Home
  25. },{
  26. path: '/news',
  27. component: News
  28. }
  29. ]
  30. // 3. 创建 router 实例,然后传 `routes` 配置
  31. const router = new VueRouter({
  32. //如果路由规则对象名也为routes,那么就可以简写为 routes
  33. routes:routes
  34. })
  35. // 4. 将路由对象挂载到Vue实例上
  36. // 通过 router 配置参数注入路由,从而让整个应用都有路由功能
  37. var vm = new Vue({
  38. el: '#app',
  39. data: {},
  40. // 将路由添加到Vue中
  41. router
  42. })
  43. </script>

注意: 上面代码中,router-link标签默认会被渲染成一个a标签 05.Vue路由 - 图1

路由重定向:上面代码中,我们应该设置打开浏览器就默认调整到 “首页”,所以需要把根路由/重定向到/home。 修改路由配置:

  1. // 2. 定义路由规则对象(每个路由应该映射一个组件)
  2. const routes = [
  3. {
  4. path: '/', //根路由
  5. redirect: '/home' //把根路由重定向到home
  6. },{
  7. path: '/home',
  8. component: Home
  9. },{
  10. path: '/news',
  11. component: News
  12. }
  13. ]

1.2.嵌套路由

实际应用界面,通常由多层嵌套的组件组合而成。 比如,我们 “首页”组件中,还嵌套着 “登录”和 “注册”组件,那么URL对应就是/home/login和/home/reg。

  1. <div id="app">
  2. <p>
  3. <!-- 使用 router-link 组件来导航. to属性指定导航地址-->
  4. <router-link to="/home">home</router-link>
  5. <router-link to="/news">news</router-link>
  6. </p>
  7. <!-- 路由出口(路由匹配到的组件将渲染在这里) -->
  8. <router-view></router-view>
  9. </div>
  10. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  11. <script src="https://cdn.jsdelivr.net/npm/vue-router/dist/vue-router.js"></script>
  12. <script type="text/javascript">
  13. // 1. 定义(路由)组件。
  14. const Home = {
  15. template: `<div>
  16. <h2>首页</h2>
  17. <router-link to="/home/login">登录</router-link>
  18. <router-link to="/home/reg">注册</router-link>
  19. <router-view></router-view>
  20. </div>`
  21. }
  22. const News = {
  23. template: '<div>新闻</div>'
  24. }
  25. const Login = {
  26. template: '<div>登陆</div>'
  27. }
  28. const Reg = {
  29. template: '<div>注册</div>'
  30. }
  31. // 2. 定义路由规则对象(每个路由应该映射一个组件)
  32. const routes = [
  33. {
  34. path: '/', //根路由
  35. redirect: '/home' //把根路由重定向到home
  36. },{
  37. path: '/home',
  38. component: Home,
  39. children: [ //配置子路由
  40. {
  41. path: '/home',
  42. redirect: '/home/login'
  43. },{
  44. path: '/home/login',
  45. component: Login
  46. },{
  47. path: '/home/reg',
  48. component: Reg
  49. }
  50. ]
  51. }, {
  52. path: '/news',
  53. component: News
  54. },
  55. ]
  56. // 3. 创建 router 实例,然后传 `routes` 配置
  57. const router = new VueRouter({
  58. //如果路由规则对象名也为routes,那么就可以简写为 routes
  59. routes: routes
  60. })
  61. // 4. 将路由对象挂载到Vue实例上
  62. // 通过 router 配置参数注入路由,从而让整个应用都有路由功能
  63. var vm = new Vue({
  64. el: '#app',
  65. data: {},
  66. // 将路由添加到Vue中
  67. router
  68. })
  69. </script>

1.3.路由传参

路由传参有多种方式,这里我们学习两种:params与query。

1.3.1.params形式传参

  1. <div id="app">
  2. <p>
  3. <router-link :to="{name:'Home',params:{msg:'hello world!'}}">home</router-link>
  4. <router-link :to="{name:'News',params:{id:id,name:name}}">news</router-link>
  5. </p>
  6. <router-view></router-view>
  7. </div>
  8. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  9. <script src="https://cdn.jsdelivr.net/npm/vue-router/dist/vue-router.js"></script>
  10. <script type="text/javascript">
  11. const Home = {
  12. template: '<div>{{$route.params.msg}},首页</div>'
  13. }
  14. const News = {
  15. template: `<div>新闻;
  16. 参数1:{{$route.params.id}}
  17. 参数2:{{$route.params.name}}
  18. </div>`
  19. }
  20. const routes = [{
  21. path: '/home',
  22. name:'Home', //每个路由规则中必须要有一个name属性
  23. component: Home
  24. }, {
  25. path: '/news',
  26. name:'News',
  27. component: News
  28. }]
  29. const router = new VueRouter({
  30. routes
  31. })
  32. var vm = new Vue({
  33. el: '#app',
  34. data: {
  35. id:1,
  36. name:'zhangsan'
  37. },
  38. router
  39. })
  40. </script>

注意:

  1. 使用v-bind绑定to属性。
  2. to属性的值是一个json对象,此对象有两个属性:name属性和params属性。
  3. name属性就是要路由的对象。所以,在路由规则列表中,每一个路由规则都应用有一个name值。
  4. params属性就是要传递的参数。也是一个json对象。
  5. 组件接收参数时,使用 this.$route.params.参数名 的形式。

1.3.2.query形式传参

  1. <div id="app">
  2. <p>
  3. <router-link :to="{path:'/home',query:{msg:'hello world!'}}">home</router-link>
  4. <router-link :to="{path:'/news',query:{id:id,name:name}}">news</router-link>
  5. </p>
  6. <router-view></router-view>
  7. </div>
  8. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  9. <script src="https://cdn.jsdelivr.net/npm/vue-router/dist/vue-router.js"></script>
  10. <script type="text/javascript">
  11. const Home = {
  12. template: '<div>{{$route.query.msg}},首页</div>'
  13. }
  14. const News = {
  15. template: `<div>新闻;
  16. 参数1:{{$route.query.id}}
  17. 参数2:{{$route.query.name}}
  18. </div>`
  19. }
  20. const routes = [{
  21. path: '/home',
  22. component: Home
  23. }, {
  24. path: '/news',
  25. component: News
  26. }]
  27. const router = new VueRouter({
  28. routes
  29. })
  30. var vm = new Vue({
  31. el: '#app',
  32. data: {
  33. id:1,
  34. name:'zhangsan'
  35. },
  36. router
  37. })
  38. </script>

注意:

  1. to属性的值仍然是一个josn对象,但是两个属性变了,一个是path,一个是query。
  2. path属性就是路由地址,对应路由规则中的path值。
  3. query属性就是要传递的参数。也是一个json对象。
  4. 组件接收参数时,使用 this.$route.query.参数名 的形式。

1.3.3.params方式与query方式的区别

query方式传值:
05.Vue路由 - 图2

params方式传值:
05.Vue路由 - 图3

总结:params方式与query方式的区别:

  1. query方式:
    类似于get方式,参数会在路由中显示,可以用做刷新后仍然存在的参数。
    利用路由规则中的path跳转。
  2. params方式:
    类似于post方式,参数不会在路由中显示,页面刷新后参数将不存在。
    利用路由规则中的name跳转。

2.编程式路由

2.1.利用JS实现路由跳转

router-link标签可以实现页面超链接形式的路由跳转。但是实际开发中,在很多情况下,需要通过某些逻辑判断来确定如何进行路由跳转。也就是说:需要在js代码中进行路由跳转。此时可以使用编程式路由。

  1. 使用this.$router.push方法可以实现路由跳转,方法的第一个参数可为string类型的路径,或者可以通过对象将相应参数传入。
  2. 通过this.$router.go(n)方法可以实现路由的前进后退,n表示跳转的个数,正数表示前进,负数表示后退。
  3. 如果只想实现前进后退可以使用this.$router.forward()(前进一页),以及this.$router.back()(后退一页)。

    1. <div id="app">
    2. <p>
    3. <button @click="toHome">首页</button>
    4. <button @click="toNews">新闻</button>
    5. <button @click="toLogin">登陆</button>
    6. <button @click="doForward1">前进</button>
    7. <button @click="doForward2">前进</button>
    8. <button @click="doBack1">后退</button>
    9. <button @click="doBack2">后退</button>
    10. </p>
    11. <router-view></router-view>
    12. </div>
    13. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    14. <script src="https://cdn.jsdelivr.net/npm/vue-router/dist/vue-router.js"></script>
    15. <script type="text/javascript">
    16. const Home = {
    17. template: '<div>首页</div>'
    18. }
    19. const News = {
    20. template: '<div>新闻:{{$route.query.name}}</div>'
    21. }
    22. const Login = {
    23. template: '<div>登陆</div>'
    24. }
    25. const routes = [{
    26. path: '/',
    27. component: Home
    28. }, {
    29. path: '/home',
    30. component: Home
    31. }, {
    32. path: '/news',
    33. component: News
    34. }, {
    35. path: '/login',
    36. component: Login
    37. }]
    38. const router = new VueRouter({
    39. routes
    40. })
    41. var vm = new Vue({
    42. el: '#app',
    43. data: {},
    44. router,
    45. methods:{
    46. toHome(){
    47. //无参数时,push方法中直接写路由地址
    48. this.$router.push('/home');
    49. },
    50. toNews(){
    51. //有参数时,push方法中写一个json对象
    52. this.$router.push({path:'/news',query:{name:'zhangsan'}});
    53. },
    54. toLogin(){
    55. this.$router.push('/login');
    56. },
    57. doForward1(){
    58. this.$router.forward();
    59. },
    60. doForward2(){
    61. this.$router.go(1);
    62. },
    63. doBack1(){
    64. this.$router.back();
    65. },
    66. doBack2(){
    67. this.$router.go(-1);
    68. }
    69. }
    70. })
    71. </script>

    2.2.通过watch实现路由监听

    通过watch属性设置监听$route变化,达到监听路由跳转的目的。
    在上面代码中添加watch监听:

    1. watch: {
    2. // 监听路由跳转。
    3. $route(newRoute, oldRoute) {
    4. console.log('watch', newRoute, oldRoute)
    5. }
    6. }

    2.3.导航守卫

    路由跳转前做一些验证,比如登录验证,是网站中的普遍需求。 对此,vue-route 提供了实现导航守卫(navigation-guards)的功能。
    你可以使用 router.beforeEach 注册一个全局前置守卫:

    1. const router = new VueRouter({ ... })
    2. router.beforeEach((to, from, next) => {
    3. // ...
    4. })

    每个守卫方法接收三个参数:

  4. to:即将要进入的目标路由对象(去哪里),可以使用 to.path 获取即将要进入路由地址。

  5. from:当前导航正要离开的路由对象(从哪来),可以使用 from.path 获取正要离开的路由地址。
  6. next:一个函数,表示继续执行下一个路由。(如果没有next,将不会进入到下一个路由)

下面例子中实现了如下功能:

  1. 列举需要判断登录状态的 “路由集合”,当跳转至集合中的路由时,如果“未登录状态”,则跳转到登录页面
  2. 当直接进入登录页面LoginPage时,如果“已登录状态”,则跳转到首页HomePage;
    1. <div id="box">
    2. <p>
    3. <router-link to="/home">home</router-link>
    4. <router-link to="/news">news</router-link>
    5. <router-link to="/music">music</router-link>
    6. <router-link to="/login">login</router-link>
    7. </p>
    8. <router-view></router-view>
    9. </div>
    10. <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    11. <script src="https://cdn.jsdelivr.net/npm/vue-router/dist/vue-router.js"></script>
    12. <script type="text/javascript">
    13. const Home = {
    14. template: '<div>首页</div>'
    15. }
    16. const News = {
    17. template: '<div>新闻</div>'
    18. }
    19. const Music = {
    20. template: '<div>音乐</div>'
    21. }
    22. const Login = {
    23. template: '<div>登录</div>'
    24. }
    25. const routes = [{
    26. path: '/',
    27. component: Home
    28. }, {
    29. path: '/home',
    30. component: Home
    31. }, {
    32. path: '/news',
    33. component: News
    34. }, {
    35. path: '/music',
    36. component: Music
    37. }, {
    38. path: '/login',
    39. component: Login
    40. }]
    41. const router = new VueRouter({
    42. routes // (缩写)相当于 routes: routes
    43. })
    44. var vm = new Vue({
    45. el: '#box',
    46. data: {},
    47. router
    48. })
    49. // 添加全局路由守卫
    50. router.beforeEach((to, from, next) => {
    51. //创建守卫规则集合(这里表示'/news'与'/music'路径是需要权限验证的)
    52. const nextRoute = ['/news', '/music'];
    53. // 使用isLogin来模拟是否登录
    54. let isLogin = false;
    55. // 判断to.path(要跳转的路径)是否是需要权限验证的
    56. if (nextRoute.indexOf(to.path) >= 0) {
    57. if (!isLogin) {
    58. router.push({
    59. path: '/login'
    60. })
    61. location.reload(); //必须要有
    62. }
    63. }
    64. // 已登录状态;当路由到login时,跳转至home
    65. if (to.path === '/login') {
    66. if (isLogin) {
    67. router.push({
    68. path: '/home'
    69. });
    70. location.reload();
    71. }
    72. }
    73. next(); //必须要有
    74. });
    75. </script>