vue路由面试题

1.mvvm 框架是什么?

定义:M:Model(服务器上的业务逻辑操作)  V:View(页面)VM:ViewModel(Model与View之间核心枢纽,比如Vue.js)

大体上:vm层(视图模型层)通过接口从后台m层(model层)请求数据,vm层继而和v(view层)实现数据的双向绑定。

三者关系Model与ViewModel之间的双向关系

Model通过Ajax通信,发送数据给ViewModel。

ViewModel也可以通过Ajax通信,发送请求给Model。

ViewModel与View之间的双向关系

ViewModel中的数据改变,可以同时改变View上的显示内容。

View上的内容改变(比如输入框中的内容),也可以同时改变ViewModel中对应的数据。

前端框架MVVM出现的最大意义是什么:

mvvm层实现了前后端更好的分离(前端需要的数据只需要请求后端的接口即可)

MVVM 的出现促进了 GUI 前端开发与后端业务逻辑的分离,极大地提高了前端开发效率。

MVVM用接口实现了前后端数据的通信,这样可以使前后端之间的业务逻辑没有什么关系。

MVVM在感觉上要比mvc模式前后端要分的更开

前端框架MVVM中的vm层是干嘛的

ViewModel 是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的 Model 数据进行转换处理,做二次封装,以生成符合 View 层使用预期的视图数据模型。需要注意的是 ViewModel 所封装出来的数据模型包括视图的状态和行为两部分,而 Model 层的数据模型是只包含状态的,比如页面的这一块展示什么,那一块展示什么这些都属于视图状态(展示),而页面加载进来时发生什么,点击这一块发生什么,这一块滚动时发生什么这些都属于视图行为(交互),视图状态和行为都封装在了 ViewModel 里。这样的封装使得 ViewModel 可以完整地去描述 View 层。由于实现了双向绑定,ViewModel 的内容会实时展现在 View 层,这是激动人心的,因为前端开发者再也不必低效又麻烦地通过操纵 DOM 去更新视图,MVVM 框架已经把最脏最累的一块做好了,我们开发者只需要处理和维护 ViewModel,更新数据视图就会自动得到相应更新,真正实现数据驱动开发。看到了吧,View 层展现的不是 Model 层的数据,而是 ViewModel 的数据,由 ViewModel 负责与 Model 层交互,这就完全解耦了 View 层和 Model 层,这个解耦是至关重要的,它是前后端分离方案实施的重要一环。


View一般就是我们平常说的HTML文本的Js模板,里面可以嵌入一些js模板的代码,比如Mustache,比如jstl类似的模板伪代码

ViewModule层里面就是我们对于这个视图区域的一切js可视业务逻辑,举个例子,比如图片走马灯特效,比如表单按钮点击提交,这些自定义事件的注册和处理逻辑都写在ViewModule里面了

Module就更简单了,就是对于纯数据的处理,比如增删改查,与后台CGI做交互


2.vue-router 是什么?它有哪些组件

路由就是SPA(单页应用)的路径管理器,适合用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。路由模块的本质 就是建立起url和页面之间的映射关系。

SPA(single page application):单一页面应用程序,只有一个完整的页面;它在加载页面时,不会加载整个页面,而是只更新某个指定的容器中内容。单页面应用(SPA)的核心之一是: 更新视图而不重新请求页面;vue-router在实现单页面前端路由时,提供了两种方式:Hash模式和History模式;根据mode参数来决定采用哪一种方式。

1、Hash模式:

vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。 hash(#)是URL 的锚点,代表的是网页中的一个位置,单单改变#后的部分,浏览器只会滚动到相应位置,不会重新加载网页,也就是说 #是用来指导浏览器动作的,对服务器端完全无用,HTTP请求中也不会不包括#;同时每一次改变#后的部分,都会在浏览器的访问历史中增加一个记录,使用”后退”按钮,就可以回到上一个位置;所以说Hash模式通过锚点值的改变,根据不同的值,渲染指定DOM位置的不同数据

2、History模式:

由于hash模式会在url中自带#,如果不想要很丑的 hash,我们可以用路由的 history 模式,只需要在配置路由规则时,加入"mode: 'history'",这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。

//main.js文件中const router = new VueRouter({ mode: 'history', routes: [...]})

要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。

exportconstroutes = [

{path:"/", name:"homeLink", component:Home}

{path:"/register", name:"registerLink", component: Register},

{path:"/login", name:"loginLink", component: Login},

{path:"*", redirect:"/"}]

此处就设置如果URL输入错误或者是URL 匹配不到任何静态资源,就自动跳到到Home页面

常用的形式:

//路由声明式跳转 ,active-class是标签被点击时的样式

                  //渲染路由的容器

                    //缓存组件


3.active-class 是哪个组件的属性?

active-class属于vue-router的样式方法 当routerlink标签被点击时将会应用这个样式 使用有两种方法routerLink标签内使用

首页

首页的active有时会有bug,会一直被应用

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

在router-link中写入exact

首页

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

可以通过query ,param两种方式

区别: query通过url传参,刷新页面还在    params刷新页面不在了

    params的类型:

配置路由格式:/router/:id

传递的方式:在path后面跟上对应的值

 传递后形成的路径:/router/123

//在APP.vue中

    用户   

//在index.js

     {

    path: '/user/:userid',

    component: User,

    },

跳转方法:

// 方法1:

按钮

// 方法2:

this.$router.push({name:'users',params:{uname:wade}})

// 方法3:

this.$router.push('/user/' + wade)

可以通过$route.params.userid 获取你说传递的值

   query的类类型

  配置路由格式:/router,也就是普通配置

  传递的方式:对象中使用query的key作为传递方式

  传递后形成的路径:/route?id=123

//01-直接在router-link 标签上以对象的形式

档案

/*

    02-或者写成按钮以点击事件形式

       

*/

//点击事件

profileClick(){

  this.$router.push({

        path: "/profile",

        query: {

          name: "kobi",

          age: "28",

          height: 198

        }

      });

}

跳转方法:

// 方法1:

按钮

// 方法2:

this.$router.push({ name: 'users', query:{ uname:james }})

// 方法3:

按钮

// 方法4:

this.$router.push({ path: '/user', query:{ uname:james }})

// 方法5:

this.$router.push('/user?uname=' + jsmes)

可以通过$route.query 获取你说传递的值


5.vue-router 有哪几种导航钩子?

1、全局守卫:router.beforeEach
使用router.beforeEach注册一个全局前置守卫:

constrouter=newVueRouter({...})  router.beforeEach((to,from, next) =>{// ...})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫resolve 完之前一直处于等待中。

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

to: Route: 即将要进入的目标 路由对象

from: Route: 当前导航正要离开的路由

next: Function: 一定要调用该方法来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()注册过的回调。

确保要调用next方法,否则钩子就不会被 resolved。

2、全局解析守卫:router.beforeResolve

你可以用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。

3、全局后置钩子:router.afterEach

你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:

router.afterEach((to,from) =>{// ...})

4、路由独享的守卫:beforeEnter

constrouter=newVueRouter({routes:[{path:'/foo',component: Foo,beforeEnter:(to,from, next) =>{// ...}}]})

这些守卫与全局前置守卫的方法参数是一样的。

5、组件内的守卫:beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave

const Foo={ template: `...`, 

beforeRouteEnter(to, from,next){

//在渲染该组件的对应路由被 confirm 前调用

//不!能!获取组件实例 `this`//因为当守卫执行前,组件实例还没被创建

},

//不过,你可以通过传一个回调给next来访问组件实例。

//在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。

 beforeRouteEnter(to, from,next){next(vm=>{//通过 `vm` 访问组件实例})}, 

beforeRouteUpdate(to, from,next){

//在当前路由改变,但是该组件被复用时调用//举例来说,对于一个带有动态参数的路径/foo/:id,在/foo/1和/foo/2之间跳转的时候,

//由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。

//可以访问组件实例 `this`}, 

 beforeRouteLeave(to, from,next){

//导航离开该组件的对应路由时调用

//可以访问组件实例 `this`}}

注意:beforeRouteEnter是支持给next 传递回调的唯一守卫。对于beforeRouteUpdate和beforeRouteLeave来说,this已经可用了,所以不支持传递回调,因为没有必要了:

beforeRouteUpdate(to,from, next){// just use `this`this.name= to.params.name

  next()}

离开守卫beforeRouteLeave:通常用来禁止用户在还未保存修改前突然离开。该导航可以通过next(false)来取消:

beforeRouteLeave(to, from,next){

constanswer= window.confirm('Do you really want to leave? you have unsaved changes!')

if(answer){next()}else{next(false)}}

6.route和router 的区别

1.router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,他包含了所有的路由包含了许多关键的对象和属性。

举例:history对象

$router.push({path:'home'});本质是向history栈中添加一个路由,在我们看来是 切换路由,但本质是在添加一个history记录

方法:

$router.replace({path:'home'});//替换路由,没有历史记录

2.route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等

$route.path

字符串,等于当前路由对象的路径,会被解析为绝对路径,如"/home/news"。

$route.params

对象,包含路由中的动态片段和全匹配片段的键值对

$route.query

对象,包含路由中查询参数的键值对。例如,对于/home/news/detail/01?favorite=yes,会得到$route.query.favorite == 'yes'。

$route.router

路由规则所属的路由器(以及其所属的组件)。

$route.matched

数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。

$route.name

当前路径的名字,如果没有使用具名路径,则名字为空。

$route.path, $route.params, $route.name, $route.query这几个属性很容易理解,主要用于接收路由传递的参数



7.vue-router响应路由参数的变化

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

注意:

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

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

可以使用router的组件内钩子函数

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变化了,就一定会重新创建这个组件。


8.vue-router实现路由懒加载( 动态加载路由 )

1. vue异步组件技术

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

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

举例如下:

{path:'/promisedemo',name:'PromiseDemo',component:resolve=>require(['../components/PromiseDemo'],resolve)}

ts文件下需要设置

2. es提案的import()

推荐使用这种方式(需要webpack > 2.4)

webpack官方文档:webpack中使用import()

vue官方文档:路由懒加载(使用import())

vue-router配置路由,代码如下:

// 下面2行代码,没有指定webpackChunkName,每个组件打包成一个js文件。

const ImportFuncDemo1 = () => import('../components/ImportFuncDemo1')

const ImportFuncDemo2 = () => import('../components/ImportFuncDemo2')

// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。

// const ImportFuncDemo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo')

// const ImportFuncDemo2 = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/ImportFuncDemo2')

export default new Router({

routes: [

        { path: '/importfuncdemo1', name: 'ImportFuncDemo1', component: ImportFuncDemo1 },

        { path: '/importfuncdemo2', name: 'ImportFuncDemo2', component: ImportFuncDemo2 } ]

})

3、webpack提供的require.ensure()

vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。

这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。

举例如下:

{path:'/promisedemo',name:'PromiseDemo',component:resolve=>require.ensure([],()=>resolve(require('../components/PromiseDemo')),'demo')},{path:'/hello',name:'Hello',// component: Hellocomponent:resolve=>require.ensure([],()=>resolve(require('../components/Hello')),'demo')

你可能感兴趣的:(vue路由面试题)