前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Vue 全家桶学习笔记:Vue-router

Vue 全家桶学习笔记:Vue-router

作者头像
Chor
发布2019-11-26 14:23:37
5760
发布2019-11-26 14:23:37
举报
文章被收录于专栏:前端之旅前端之旅
1. 前端路由的出现

在以前,前后端是不分离的,这个阶段通常是由服务端渲染好页面(SSR),再发送页面给前端去展示;接着到了前后端分离的阶段,前端向静态资源服务器拿资源,再通过 js 渲染页面,此时仍然是一个 url 对应一份 html+css+js。再后来出现了 SPA 单页面应用的概念,实际上它只有一个页面,但给我们的体验是多页面之间的切换。

SPA 是基于路由和组件的,其中路由可以看作是它的一个路径管理器,路由和组件之间互相映射,路由的切换就是组件的切换。Vue 的前端路由也就是 vue-router。

2. vue-router 的模式

vue-router 提供了 hash 和 history 两种模式。

  • hash 模式:url 中带有 hash(#),hash 的改变并不会触发刷新或者请求,同时每一次改变 hash 后的部分,都会在浏览器的访问历史中增加一个记录 ,这使得我们可以来回切换;而要监听切换可以依靠 onhashchange 事件;
  • history 模式:html5 提供了 window.history 的 API,url 的改变同样不会触发页面刷新,并且由于历史记录是在 history 栈压入或弹出的,这使得我们可以来回切换。

实例化 vue-router 时会传入一个对象,可以给对象一个 option,如 mode:'history',从而决定 vue-router 使用哪种模式。

3. 安装

在安装 vue-cli 的时候可以顺便安装 vue-router,或者之后我们通过 npm install 的方式手动安装。

4. 使用

如果是通过脚手架安装 vue-router,src 下会多出一个 router 文件夹,里面的 index.js 帮我们生成了配置的基础结构。

index.js 大致是这样的:

代码语言:javascript
复制
// 导入要使用到的组件
import VueRouter from 'vue-router';     
import Vue from 'vue';                
import Home from '../components/Home.vue';
import About from '../components/About.vue';

Vue.use(VueRouter);        // 安装 vue-router

const routers = [                  // 配置路由和组件的映射关系
    {
       path:'/',
       redirect: '/home'
    }
    {
       path:'/home',
       components:Home
    },
    {
       path:'/about',
       components:About
    }
]

const router = new VueRouter({         // 实例化 VueRouter 对象
  routers
})

export default router;                // 导出 router 对象

同时,main.js 文件中,导入 router 并在 Vue 实例下挂载:

代码语言:javascript
复制
// main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

new Vue({
  router,
  render: function (h) { return h(App) }
}).$mount('#app')

接下来通过 <router-link><router-view> 使用路由:

代码语言:javascript
复制
// App.vue

<div id="app">
    <router-link to="/home">首页</router-link>        
    <router-link to="/about">关于</router-link>
    <router-view></router-view>
</div>
5. 路由嵌套(二级路由)

假设 home 路由下嵌套着两个子路由 newsmessage,即 /home/news/home/message,那么首先创建两个对应的组件,之后在 index.js 下配置好映射关系:

代码语言:javascript
复制
import HomeNews from '../components/HomeNews.vue'
import HomeMessage from '../components/HomeMessage.vue'

const routes = [                  // 配置 url和组件的映射关系
    {
       path:'/',
       redirect: '/home'
    }
    {
       path:'/home',
       component:Home,
       children:[
        {
           path:'/',                 // 默认展示 news
           redirect: 'news'
        }
        {
           path: 'news',
           component: HomeNews
        },
        {
           path: 'message',
           component: HomeMessage
        }
    ]
    },
    {
       path:'/about',
       component:About
    }
]

Home.vue 中使用子路由:

代码语言:javascript
复制
// Home.vue

<div>
    <h1>我是Home</h1>
    <router-link to="/home/news">news</router-link>
    <router-link to="/home/messaage">message</router-link>
    <router-view></router-view>
</div>
5. 动态路由匹配

有的时候,path 并不是固定的。比方 /user/Tom/user/Jack,这些 path 根据用户不同而不同,但都是展示用户页面的,我们希望满足这种格式的 path 都映射 User 组件,怎么办呢?可以在 path 中使用动态路径参数。

代码语言:javascript
复制
import HomeMessage from '../components/User.vue'

const routes = {
    {
        path:'/user/:userId',
        component: User
    }
}

注意,这里我们不再是写 /user/,而是写 /user/:userId,这是因为路径 user 后面的东西是动态的。那么,对于下面的三种 <router-link>,最后都可以成功映射到 User 组件:

代码语言:javascript
复制
// App.vue

<router-link to="/user/Tom"></router-link>           // 路径:/user/Tom
<router-link to="/user/Jack"></router-link>          // 路径:/user/Jack
<router-link :to="`/user/${userId}`"></router-link>   // 路径:/user/Bake
<router-view></router-view>

export default{
    data(){
        return {
            userId:'Bake'
        }
    }
}

如果想要在具体的 User.vue 中展示用户名,可以通过 $route.params 去访问:

代码语言:javascript
复制
// User.vue

<div>我的用户名是:{{$route.params.userId}}</div>
<div>我的用户名是:{{id}}</div>

export default{
    computed:{
        id(){
            return this.$route.params.userId;
        }
    }
}
6. 路由传参
6.1 基于动态路由

实际上,上面讲的动态路由就可以用来传递参数。上面例子的 path 还可以根据需要添加更多动态路径参数,如 '/user/:userId/:userJob/:userEmail',首先在 App.vue 拿到数据,传给<router-link>to,接着就可以在 User.vue 中通过 $route.params 去访问了。

6.2 给 to 传入对象

首先要明白,to 除了接收字符串之外,也可以接受对象。以前面的动态路由为例:

代码语言:javascript
复制
<!--可以这样写(直接传字符串)-->
<router-link :to="`/user/${userId}`"></router-link>

<!--也可以这样写(传对象,直接用字符串表示完整路径)-->
<router-link :to="{path:'`/user/${userId}`'}"></router-link>

那么,我们会自然想到,对于一个普通的路由,要传参的话把参数放在给 to 传入的对象中不就可以了吗?

于是可能会这么写:

代码语言:javascript
复制
<router-link :to="{path:'/article',params:{date:2020-1-1,title:'A new year'}}"></router-link>

然而这是错误的用法,事实上我们应该将 path 改为 name。不过在这之前,我们还是先给路由一个 name吧:

代码语言:javascript
复制
import Article from '../components/Article.vue'

// 首先给路由一个名字(命名路由)
const routes = {
    {
        path:'/article',
        name:'article',
        component: Article
    }
}

接着使用路由:

代码语言:javascript
复制
<router-link :to="{name:'article',params:{date:2020-1-1,title:'A new year'}}"></router-link>

获取参数:

代码语言:javascript
复制
<!--Article.vue-->

<div>{{$route.params.date}}</div>
<div>{{$route.params.title}}</div>
6.3 使用 query

这和上面的是差不多的,不同的是我们不使用 params,而是使用 query。query 实际上就是 url 中的查询参数。

这种情况下,我们给 to 传入的对象可以使用 path,也可以使用 name

代码语言:javascript
复制
<router-link :to="{name:'article',query:{date:2020-1-1,title:'A new year'}}"></router-link>
<!--等价于-->
<router-link :to="{path:'/article',query:{date:2020-1-1,title:'A new year'}}"></router-link>

获取参数:

代码语言:javascript
复制
<!--Article.vue-->

<div>{{$route.query.date}}</div>
<div>{{$route.query.title}}</div>
7. 路由跳转:声明式 VS 编程式

前面介绍的路由跳转/导航是通过声明式<router-link :to='...'> 实现的,我们也可以使用编程式this.$router.push('...') 实现:

代码语言:javascript
复制
// App.vue

<div id="app">
    <router-link to='/home'>可以点击这里进入首页</router-link> 
    <!--
    or: <router-link :to="{path:'/home'}">    
    -->
    <button @click="change">也可以点击这里进入首页</button>
    <router-view></router-view>
</div>

<script>
    export default{
        name:'App',
        methods:{
            change(){
                this.$router.push('/home');
              //or: this.$router.push({path:'/home'}) 
            }
        }
    }
</script>    

<router-link :to='...'> 实质上也是在内部调用了 push 方法,从而向 history 栈压入新记录,由于是栈的数据结构,所以可以自由前进和后退。除了 push,还有 replace(注意是直接替换而不是采用入栈出栈方式),go,这些和 window.history 的 API 是类似的。

this.$router.push('...') 同样接受字符串参数或者对象参数。

8. $router$route 的区别
  • $router 是我们 new 出来的 VueRouter 实例,它提供了一些跳转方法( pushreplacego )和钩子函数(后面导航守卫部分会讲解);
  • $route路由信息对象,可以理解为是当前活跃的路由,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数。
9. 导航守卫

路由的导航守卫其实就是一些钩子函数,可以在路由跳转的流程中针对性地进行操作控制。

1. 全局守卫
  • 全局前置守卫:router.beforeEach((to,from,next) => {...})。可以在 index.js 或者路由组件中使用(通过 this.$router),next 必须调用。
  • 全局解析守卫: router.beforeResolve
  • 全局后置钩子:router.afterEach((to,from) => {...})。可以在 index.js 或者路由组件中使用(通过 this.$router),next 不需要调用。
2. 路由独享守卫

单个路由独享的守卫只有 beforeEnter 这一个,可以在配置路由时定义。

代码语言:javascript
复制
const router = new VueRouter({
  routes: [
    {
      path: '/home',
      component: Home,
      beforeEnter: (to, from, next) => {
        // ...
        next()  
      }
    }
  ]
})
3. 组件守卫

组件守卫只能在路由组件中定义:

  • beforeRouteEnter((to,from,next) => {...}): 进入路由前,此时实例还没创建,无法获取到 this
  • beforeRouteUpdate((to,from,next) => {...}) :路由复用同一个组件时触发,比如 /user/Tom/user/Jack
  • beforeRouteLeave((to,from,next) => {...}): 离开当前路由,此时可以用来保存数据,或数据初始化,或关闭定时器等等
4. 导航解析流程
10. 路由懒加载

懒加载也叫延迟加载,即在需要的时候进行加载,随用随载。在单页应用中,如果没有应用懒加载,运用webpack 打包后的文件将会异常的大,导致进入首页时,需要加载的内容过多,延时过长,不利于用户体验,而运用懒加载则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时

要使用路由懒加载,只需要替换掉原来的引用语句即可:

代码语言:javascript
复制
// import Home from '../components/Home.vue';
// import About from '../components/About.vue';

const Home = () => import('../components/Home');
const About = () => import('../components/About');
11. keep-alive

路由跳转的时候,比如 home -> about -> homehome 路由组件实际上是在不断地创建和销毁,我们可以用生命周期钩子函数证明这一点:

上图中,每次跳转的时候都会经历一次生命周期。但大部分时候,这种重新渲染是没有必要的,所以 Vue 提供了一个内置组件 keep-alive缓存组件内部状态,避免重新渲染

代码语言:javascript
复制
<keep-alive>
    <router-view></router-view>
</keep-alive>

keep-alive 包裹的路由/组件,状态会得到缓存。以上图为例,从 home 跳转到 about,home 不会被销毁,同样的,从 about 跳转到 home,about 不会被销毁,home 也不会被重新创建,而是用之前缓存好的组件。

  • keep-alive 提供了 activateddeactivated 两个钩子函数(在路由组件中定义),前者在当前路由组件激活时调用,后者在当前路由组件失活时调用。
  • keep-alive 提供了 3 个属性定义具体的缓存情况:
    • include 包含的组件(可以为字符串,数组,以及正则表达式,只有匹配的组件会被缓存)
    • exclude 排除的组件(以为字符串,数组,以及正则表达式,任何匹配的组件都不会被缓存)
    • max 缓存组件的最大值(类型为字符或者数字,可以控制缓存组件的个数)

参考:

从头开始学习vue-router

可能比文档还详细–VueRouter完全指北

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-11-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 前端路由的出现
  • 2. vue-router 的模式
  • 3. 安装
  • 4. 使用
  • 5. 路由嵌套(二级路由)
  • 5. 动态路由匹配
  • 6. 路由传参
    • 6.1 基于动态路由
      • 6.2 给 to 传入对象
        • 6.3 使用 query
        • 7. 路由跳转:声明式 VS 编程式
        • 8. $router 和 $route 的区别
        • 9. 导航守卫
          • 1. 全局守卫
            • 2. 路由独享守卫
              • 3. 组件守卫
                • 4. 导航解析流程
                • 10. 路由懒加载
                • 11. keep-alive
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档