vue-router相关面试题总结(全)

430 阅读5分钟

问:vue-router 是什么?它有哪些组件?

答:vue-router 是 Vue.js 官方的路由管理器,它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌。包含的功能有:

  • 嵌套的路由
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过度系统的视图过渡效果
  • 细颗粒度的导航控制
  • 带有自动激活的 CSS class 的连接
  • history模式或 hash 模式,在 IE9 中自动降级
  • 自定义的滚动条行为

vue-router 组件:

  • < router-link to=""> 路由的路径
  • < router-link :to="{name:’‘l路由名’}"> 命名路由
  • < router-view> 路由的显示

问:active-class 是哪个组件的属性?

答:active-class 属于vue-router的样式方法,当routerlink标签被点击时将会应用这个样式。

使用方法一:routerLink标签内使用

<router-link to='/' active-class="active" >首页</router-link>

使用方法二:在路由js文件,配置active-class

<script>
    const router = new VueRouter({
        routes,
        linkActiveClass: 'active'
    });
</script>
<script>
    const router = new VueRouter({
        routes,
        linkActiveClass: 'active'
    });
</script>

在使用时会有一个bug:首页的active会一直被应用

为了解决上面的问题,还需加入一个属性exact,也有两种方式。

方式一:在router-link中写入exact

<router-link to='/' active-class="active" exact>首页</router-link>

方式二:在路由js文件,配置active-class

<script>
    const router = new VueRouter({
        routes,
        linkExactActiveClass: 'active'
    });
</script>

问:怎么定义 vue-router 的动态路由? 怎么获取传过来的值?

可以通过query ,param两种方式,区别:query通过url传参,刷新页面参数还在,params刷新页面参数不在了。

param的类型:

  • 配置路由格式:/router/:id
  • 传递的方式:在path后面跟上对应的值
  • 传递后形成的路径:/router/123
<!-- 动态路由-params -->
 
//在APP.vue中
    <router-link :to="'/user/'+userId" replace>用户</router-link>    
 
//在index.js
     {
    path: '/user/:userid',
    component: User,
    },

跳转方法:

// 方法1:
<router-link :to="{ name: 'users', params: { uname: wade }}">按钮</router-link>
// 方法2:
this.$router.push({name:'users',params:{uname:wade}})
// 方法3:
this.$router.push('/user/' + wade)

通过$route.params.参数名 获取你所传递的值

query的类型:

  • 配置路由格式:/router,也就是普通配置
  • 传递的方式:对象中使用query的key作为传递方式
  • 传递后形成的路径:/route?id=123
<!--动态路由-query -->
//01-直接在router-link 标签上以对象的形式
<router-link :to="{path:'/profile',query:{name:'why',age:28,height:188}}">档案</router-link>
/*
    02-或者写成按钮以点击事件形式
    <button @click='profileClick'>我的</button>    
*/
 
 //点击事件
 profileClick(){
   this.$router.push({
        path: "/profile",
        query: {
          name: "kobi",
          age: "28",
          height: 198
        }
      });
 }

跳转方法:

// 方法1:
<router-link :to="{ name: 'users', query: { uname: james }}">按钮</router-link>
// 方法2:
this.$router.push({ name: 'users', query:{ uname:james }})
// 方法3:
<router-link :to="{ path: '/user', query: { uname:james }}">按钮</router-link>
// 方法4:
this.$router.push({ path: '/user', query:{ uname:james }})
// 方法5:
this.$router.push('/user?uname=' + jsmes)

通过$route.query 获取你所传递的值

问:vue-router 有哪几种导航钩子(导航守卫)?

答:第一种:全局导航钩子

1.前置钩子

//单独设置每个路由的属性:
meta: { may: true }
router.beforeEach((to, from, next) => {
    if (to.matched.some(item => item.meta.may)) {
        let id = window.localStorage.getItem("id")
        if (id) {
            next()
        } else {
            next({ name: "login" })
        }
    } else {
        next()
    }
})
注意:next 方法必须要调用,否则钩子函数无法 resolved

2.后置钩子

router.afterEach((to,from) => {
	if(to.meta && to.meta.title){
		document.title = to.meta.title
	}else{
		document.title = "666"
	}
})

第二种:单独路由独享钩子

{
    path: '/home',
    name: 'home',
    component: Home,
    beforeEnter(to, from, next) {
        if (window.localStorage.getItem("id")) {
            next()
        } else {
            next({ name: "login" })
        }
    }
}

第三种:组件内的钩子

beforeRouteEnter(to, from, next) {
    // do someting
    // 在渲染该组件的对应路由被 confirm 前调用
},
beforeRouteUpdate(to, from, next) {
    // do someting
    // 在当前路由改变,但是依然渲染该组件是调用
},
beforeRouteLeave(to, from ,next) {
    // do someting
    // 导航离开该组件的对应路由时被调用
}

全局解析守卫

router.beforeResolve 注册一个全局守卫,和 router.beforeEach 类似

可以在src目录下新建一个permission.js文件

import router from './router'
import store from './store'
import { Message } from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import { getToken } from '@/utils/auth'

NProgress.configure({ showSpinner: false })

const whiteList = ['/login', '/auth-redirect', '/bind', '/register']

router.beforeEach((to, from, next) => {
  NProgress.start()
  if (getToken()) {
    /* has token*/
    if (to.path === '/login') {
      next({ path: '/' })
      NProgress.done()
    } else {
      if (store.getters.roles.length === 0) {
        // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(res => {
          // 拉取user_info
          const roles = res.roles
          store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
          // 测试 默认静态页面
          // store.dispatch('permission/generateRoutes', { roles }).then(accessRoutes => {
            // 根据roles权限生成可访问的路由表
            router.addRoutes(accessRoutes) // 动态添加可访问路由表
            next({ ...to, replace: true }) // hack方法 确保addRoutes已完成
          })
        })
          .catch(err => {
            store.dispatch('FedLogOut').then(() => {
              Message.error(err)
              next({ path: '/' })
            })
          })
      } else {
        next()
        // 没有动态改变权限的需求可直接next() 删除下方权限判断 ↓
        // if (hasPermission(store.getters.roles, to.meta.roles)) {
        //   next()
        // } else {
        //   next({ path: '/401', replace: true, query: { noGoBack: true }})
        // }
        // 可删 ↑
      }
    }
  } else {
    // 没有token
    if (whiteList.indexOf(to.path) !== -1) {
      // 在免登录白名单,直接进入
      next()
    } else {
      next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
      NProgress.done()
    }
  }
})

router.afterEach(() => {
  NProgress.done()
})

nprogress是页面跳转时出现在浏览器顶部的进度条

问:route和router 的区别

答:route对象:route对象:route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等。

  1. route.path字符串,对应当前路由的路径,总是解析为绝对路径,如"/foo/bar"2.route.path 字符串,对应当前路由的路径,总是解析为绝对路径,如"/foo/bar"。 2. route.params 一个 key/value 对象,包含了 动态片段 和 全匹配片段, 如果没有路由参数,就是一个空对象。 3. route.query一个key/value对象,表示URL查询参数。例如,对于路径/foo?user=1,则有route.query 一个 key/value 对象,表示 URL 查询参数。 例如,对于路径 /foo?user=1,则有route.query.user == 1, 如果没有查询参数,则是个空对象。 4. route.hash 当前路由的hash值 (不带#) ,如果没有 hash 值,则为空字符串。锚点* 5. route.fullPath 完成解析后的 URL,包含查询参数和hash的完整路径。 6. route.matched数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。7.route.matched 数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。 7. route.name 当前路径名字 8. $route.meta 路由元信息

router对象:router对象:router对象是全局路由的实例,是router构造方法的实例。

实例方法:

1、push 1.字符串this.router.push(home)2.对象this.router.push('home') 2. 对象this.router.push({path:'home'}) 3. 命名的路由this.router.push(name:user,params:userId:123)4.带查询参数,变成/register?plan=123this.router.push({name:'user',params:{userId:123}}) 4.带查询参数,变成 /register?plan=123this.router.push({path:'register',query:{plan:'123'}}) push方法其实和是等同的。 注意:push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。 2、go 页面路由跳转 前进或者后退this.$router.go(-1) // 后退 3、replace push方法会向 history 栈添加一个新的记录,而replace方法是替换当前的页面, 不会向 history 栈添加一个新的记录

问:vue-router响应路由参数的变化?

答:当使用路由参数时,例如从 /user/aside导航到 /user/foo,原来的组件实例会被复用。因为两个路由都渲染同个组件,比起销毁再创建,复用则更加高效。不过,这也意味着组件的生命周期钩子不会再被调用。

注意:

(1)从同一个组件跳转到同一个组件。

(2)生命周期钩子created和mounted都不会调用。

beforeRouteUpdate(to,from,next){
//在这个钩子函数中:to表示将要跳转的路由对象,from表示从哪个路由跳转过来,next多数就是需要调用
//created和mounted不调用,无法拿到需要的动态值,就通过to.path,to.params等
//可以在这个函数中打印to,具体看to对象有什么可以使用的属性
}

添加watch监听

watch: {
 // 方法1 //监听路由是否变化
  '$route' (to, from) {
   if(to.query.id !== from.query.id){
            this.id = to.query.id;
            this.init();//重新加载数据
        }
  }
}
//方法 2  设置路径变化时的处理函数
watch: {
'$route': {
    handler: 'init',
    immediate: true
  }
}

为了实现这样的效果可以给router-view添加一个不同的key,这样即使是公用组件,只要url变化了,就一定会重新创建这个组件。

<router-view :key="$route.fullpath"></router-view>

问:vue项目实现路由按需加载(路由懒加载)的3种方式

vue异步组件技术 ==== 异步加载

vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 .

但是,这种情况下一个组件生成一个js文件

/* vue异步组件技术 */
{
  path: '/home',
  name: 'home',
  component: resolve => require(['@/components/home'],resolve)
},{
  path: '/index',
  name: 'Index',
  component: resolve => require(['@/components/index'],resolve)
},{
  path: '/about',
  name: 'about',
  component: resolve => require(['@/components/about'],resolve)
} 

路由懒加载(使用import)

// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。
/* const Home = () => import('@/components/home')
const Index = () => import('@/components/index')
const About = () => import('@/components/about') */
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。 把组件按组分块
const Home =  () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
const Index = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/index')
const About = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/about')
{
  path: '/about',
  component: About
}, {
  path: '/index',
  component: Index
}, {
  path: '/home',
  component: Home
}

webpack提供的require.ensure() vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。 这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。

/* 组件懒加载方案三: webpack提供的require.ensure() */
{
  path: '/home',
  name: 'home',
  component: r => require.ensure([], () => r(require('@/components/home')), 'demo')
}, {
  path: '/index',
  name: 'Index',
  component: r => require.ensure([], () => r(require('@/components/index')), 'demo')
}, {
  path: '/about',
  name: 'about',
  component: r => require.ensure([], () => r(require('@/components/about')), 'demo-01')
}