Vue面试汇总

169 阅读14分钟

基础

1、v-if与v-show区别?

v-if:是正真的条件渲染,是惰性的,是通过直接销毁和重建DOM达到让元素显示和隐藏的效果

v-show:无论条件真假,都会渲染,只是去切换css的'display'属性来控制显示与隐藏

所以,v-if使用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show则适合于需要非常频繁切换条件的场景。

2、v-if和v-for为什么不建议一起使用

因为解析时先解析v-for再解析v-if ,如果遇到需要同时使用时可以时可以考虑写成计算属性的方式

3、computed和watch区别

1.computed:计算属性,存在缓存,只有它依赖的属性值改变时,下一次获取computed的值时才会重新计算computed的值。【不支持异步监听】

2.watch:更多是’观察‘的作用,无缓存,类似于某些数据的监听回调,每当监听的数据发生改变时,就会执行回调进行后续操作。【支持异步监听】

3.应用场景
当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;

当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。

4、组件之间的通信

1.父子组件通信
  1)父传子:v-bind动态绑定,props接收
  2)子传父:$emit发送,v-on监听
  3)$parent与$children
  4)$ref
  
2.非父子组件通信
  1)时间总线bus:
  var Event=new Vue(); // 创建一个空vue实例
  Event.$emit(事件名,数据)
  Event.$on(事件名,data()=>{})
  2VuexlocalStorage。sessionStorage

5、vue组件中data为什么必须是一个函数?

vue组件是用来复用的,当组件被用来创建多个实例,如果data是一个对象,则这些实例引用的是同一个data地址,它们之间会相互影响.而将data写成函数,那么每个实例会返回一份新的data,拥有自己的作用域,因此不存在引用对象的问题。

6、Vue中key值的作用?

当v-for正在更新已渲染过的元素列表时,它默认使用‘就地复用’策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用:主要是为了高效的更新虚拟DOM

7、谈谈Vue的生命周期

1.什么是vue生命周期?
Vue实例从创建到销毁的过程。也就是从开始创建、初始化数据、编译模板、挂载Dom--渲染,更新--渲染、卸载等一系列过程。

1)beforeCreate阶段:vue实例的挂载元素el和数据对象data都为undefined,还未初始化。
2)created阶段:组件实例已经完全创建,属性也绑定,但真实的dom还没有生成,$el还不可用。

3) beforeMount阶段:vue实例的$el和data都初始化了,但挂载的是虚拟dom节点
4)mounted阶段:真实的DOM挂载完毕,数据完成双向绑定,可以访问到DOM节点。

5)beforeUpdate阶段:组件数据更新之前调用,发生在虚拟DOM打补丁之前
6)update阶段:组件数据更新之后,当前阶段组件DOM已完成更新

7)activited阶段:keep-alive专属,组件被激活时调用
8)deactivated阶段:keep-alive专属,组件被销毁时调用

9beforeDestory:实例销毁之前调用,在这一步,实例任然完全可用
10)destroyed:Vue实例销毁后调用,调用后,vue实例指示的所有东西都被解除绑定,所有的时间监听器被移除,所有的子实力也被销毁

2.vue生命周期的作用是什么
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。

3.第一次加载页面会触发那几个钩子
beforeCreate,created,beforeMount,Mounted

4.DOM渲染在那个周期中就已经完成
DOM渲染在mounted中就已经完成

5、在那个生命周期内调用异步请求?
可以在钩子函数created、beforeMount、Mounted中进行调用,因为在这三个钩子函数中,data已经创建,可以将服务端返回的数据进行赋值,
推荐在created钩子函数中调用异步请求(能更快获取服务端数据,减少页面loading时间,ssr不支持beforeMount, mounted钩子函数)

8、组件中写name选项有什么作用?

1)项目使用keep-alive时,可搭配组件name进行缓存过滤
2DOM做递归组件时需要调用自身name
3)vue-devtools调试工具里显示的组件名称由vue中组件name决定

9、route与router的区别

route:‘路由信息对象(当前活跃的路由)’,包括path,params,hash,query,fullPath,matched,name等路由信息参数

router:'路由实例对象',包括路由的跳转方法(push,replace),钩子函数等

10、keep-alive的作用?

keep-alive是Vue内置的一个组件,可以使被包含的组件保留状态,避免重新渲染。

1.一般结合路由和动态组件一起使用,用于缓存组件。
2.它提供include和exclude,max属性,
  1)include表示只有名字匹配的组件才会被缓存,
  2)exclude表示任何名称匹配的组件都不会被缓存,其中exclude的优先级比include高
  3)max:最多可以缓存多少组件实例
  
3.对应两个钩子函数activated和deactivated,当组件被激活时,触发钩子函数activated,当组件被移除时,触发钩子函数activated。

11、v-model的原理

我们在Vue项目中主要使用v-model指令在表单input、textarea、select等元素上创建双向数据绑定,v-model内部为不同的输入元素使用不同的属性并抛出不同的事件:

1.text和textarea元素使用value属性 + input事件
2.checkbox和radio使用checked属性 + change事件
3.select字段使用value属性+  change事件

12、slot是什么?

  插槽slot是子组件的一个模板标签元素,而这一标签元素是否显示,以及怎么显示是由其父组件决定的,slot又分为三类:默认插槽、具名插槽、作用域插槽。
  
1.默认插槽:当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有一个匿名插槽

2.具名插槽:带有具体名字的插槽,也就是带有name属性的slot

3.作用域插槽:子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件传递过来的数据决定如何渲染该插槽。

13、过滤器filters

过滤器是来过滤数据的,不会修改数据。

过滤器是一个函数,它会把表达式中的值始终当作函数的第一个参数,过滤器用在插值表达式{{ }}和v-bind表达式中,然后放在操作符“|”后面进行指示。

<li>商品价格:{{item.price | filterPrice}}</li> 
filters: { 
  filterPrice (price) { 
      return price ? ('¥' + price) : '--'
    } 
}

14、vue-router有那些钩子函数?

全局前置守卫:router.beforeEach
全局解析守卫:router.beforeResolve
全局后置钩子:router.afterEach
路由独享的守卫:beforeEnter
组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave

15、vue初始化页面闪动问题

可以使用 v-cloak 指令设置样式,这些样式会在 Vue 实例编译结束时,从绑定的 HTML 元素上被移除。

提升

1、mvvm理解

MVVMModel-View-ViewModel的缩写。Model层代表数据模型,也可以在Model中定义数据修改和操作的业务逻辑,View代表UI组件,它负责将数据模型转化成UI展现出来,ViewModel是一个同步ViewModel的对象。

ViewModel之间没有直接的联系,而是通过ViewModel进行交互,ModelViewModel之间的交互是双向的,因此View数据变化会同步到Moudel中,Model也会同步到View中。

ViewModel之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由MVVM统一管理。

2、mvvm和mvc区别?

什么是mvc?
在Controller里面把Model的数据赋值给View

mvc和mvvm其实区别并不大。都是一种设计思想。主要是mvc中Controller演变成mvvm中的viewModel。mvvm主要解决了mvc中的大量的DOM操作使页面渲染性能降低,加载速度慢,影响用户体验的问题。

mvc:所有通信都是单向的
mvp:Presenter--各部分之间的通信,都是双向的,所有的逻辑都部署在presenter

3、双向数据绑定原理?

mvvm双向绑定,采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

1)需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter,这样的话,当给这个对象的某个值赋值,就会触发setter,那么就能监听到数据变化。

2)compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。

3Watcher订阅者是ObseverCompile之间通信的桥梁,主要做的事情是:实例化时往属性订阅器(dep)里面添加自己,本身必须有一个update()方法,待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调。

4、Vue2.0响应式数据的原理?

整体思想是数据劫持+观察者模式

对象内部通过defineReactive方法,使用Object.defineProperty将属性进行劫持,数组则通过重写数组方法来实现,当页面使用对应属性时,每个属性都拥有自己的dep属性,存放它所依赖的watcher(依赖收集),当属性变化后会通知自己对应的watcher去更新.

5、vue3.0与vue2.0区别

1.使用Object.definProperty()来进行数据劫持有什么缺点?
  在对一些属性进行操作时,使用这种方法无法拦截,比如通过下标方式修改数组或者给对象新增属性,这都不能触发组件的重新渲染.
  
Vue3.0通过使用Proxy对对象进行代理,从而实现数据劫持,使用Proxy的好处是它可以完美的监听到任何方式的数据改变,唯一的缺点是兼容性的问题。

6、虚拟dom实现原理

意义:不断的修改真实的DOM会引发回流和重绘,大大降低了页面的渲染能力,使用虚拟DOM替代真实DOM,最大的优势在于不断的去修改虚拟DOM后,才会一次性的与真实DOM的差异性做对比,然后只会去修改真实的DOM一次。

1)虚拟DOM本质是JavaScript对象,是对真实DOM的抽象
2)状态变更时,记录新树和旧树的差异
3)最后把差异更新到真正的dom

7、说一说Vue的单向数据流?

数据总是从父组件传到子组件中,子组件没有权利修改父组件传过来的数据,只能请求父组件对原始数据进行修改,这样可防止子组件意外改变父级组件的状态,从而导致你的应用的数据流难以理解.

如果子组件实在要改变父组件的prop值,可以再data里面定义一个变量,并用prop的值初始化之后用$emit通知父组件取修改

8、Vue的父子组件生命周期钩子函数执行顺序

1.加载渲染过程
父beforeCreate -> 父created -> 父beforeMount ->子beforeCreate -> 子created -> 子beforeMount -> 子Mounted -> 父Mounted

2.子组件更新过程
父beforeUpdate -> 子beforeUpdate -> 子updated -> 父updated

3.父组件更新过程
父beforeUpdate -> 父Update

4.销毁过程
父beforeDestroy -> 子beforeDestroy -> 子Destroyed -> 父Destroyed

9、Vuex?

1、vuex是什么?使用场景

Vuex是一个专为Vue.js应用程序开发的状态管理模式,每个Vuex应用的核心就是store(仓库),它的状态存储是相应式的,当Vue组件从store中读取状态的时候,若store中的状态发生改变,那么相应的组件也会相应的高效更新。

场景”单页应用中,组件之间的状态,音乐播放、登陆状态、加入购物车

2、vuex有哪几种属性

五种:StateGetterMutationActionModule

1.State:定义了应用状态的数据结构,可以在这里设置默认的初始状态;里面的数据是相应式的
2.Getters:可以对State进行计算操作,它就是Store的计算属性
3.Mutation:是唯一可更改store中状态的方法,且必须是同步函数
4.Action:用于提交Mutation,而不是直接变更状态,可以包含任意异步操作
5.Module:允许将单一的Store拆分为多个store且同时保存单一的状态树种。

3、从vuex获取到的数据不能直接修改,需要浅拷贝对象之后更改,否则报错

10、Vuex页面刷新数据丢失怎么解决

需要做vuex数据持久化,一般使用本地存储的方案来保存数据,可以自己设计存储方案,也可以使用第三方插件(例如:vuex-persist插件,不需要手动存取storage,而是直接将状态保持至cookie或者localStorage中)

11、vue-router动态路由是什么?

我们经常需要把某些模式匹配到所有路由,全部映射到同个组件.例如(我们有一个User组件,对于所有ID各不同的用户,都是用这个组件来渲染,那么,我们可以使用"动态路由参数:/id")

12、Vue-router的跳转方式?

1.router-link标签里的to属性
2.this.$router.push('路径'):跳转到指定url路径,histroy栈中有记录,点击后退会返回到上一个页面
3.this.$router.replace():跳转到指定url路径,但history栈中没有记录,即直接替换了当前页面
4.this.$router.go(n):向前或者向后跳转n个页面

13、路由参数params与query的区别

1.使用params传参只能用name来引入路由,如果写成path,接受参数的页面会是undefine
2.使用query传参使用path来引入路由
3.params是路由的一部分,必须要在路由后面添加参数名,query是拼接在url后面的参数,没有也没有关系
4.直白的来说query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数,而params相当于post请求,参数不会再地址栏中显示。

14、vue-router中hash模式和history模式区别

1.最直观的区别:在url中hash带了一个很丑的#,history没有,vue默认使用hash模式

2.hash虽然出现在URL中,但不会被包括在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面

3.history中有back,forword,go方法,新增了pushState()和replaceState()方法,提供对历史记录进行修改的功能,只是当他们执行修改时,虽然改变了当前的URL,但浏览器不会立即向后端发送请求。

4.对于刷新,hash模式下,修改的是#中的信息,浏览器请求时不会将#后面的数据发送给后台,所以没有问题,但在history模式下,可以自由修改path,如果服务器中没有相应的响应或者资源,则会返回404.

15、vue如何监听对象或者数组某个属性的变化

1.this.$set()
2.调用数组的方法(splice()、push()、pop())

16、vue性能优化

1.对象层级不要太深,否则性能就会差
2.不需要响应式的数据不要放在data中(可以用Object.freeze()冻结数据)
3.v-if和v-show区分使用场景
4.computed和watch区分使用场景
5.v-for遍历必须加key,key最好是id值,且避免同时使用v-if
6.大数据列表和表格性能优化-虚拟列表/虚拟表格
7.防止内存泄漏,组件销毁后把全局变量和事件销毁
8.图片懒加载
9.路由懒加载
10.第三方插件的按需引入
11.防抖,节流运用
12.服务端渲染SSR or 预渲染

17、vue异步加载的方式(路由懒加载)

1.vue异步组件:主要是使用resolve的异步机制,用require代替import实现按需加载
2.ES6import:其实也是通过promise的resolve机制
3.webpack的require.ensure()

18、SPA单页面与多页面理解

1.单页面
  SPA仅在Web页面初始化时加载相应的HTML,JavaScript和css,一旦页面加载完成,SPA不会因为用户的操作而进行页面的重新加载或跳转,取而代之的是利用路由机制实现HTML内容的变换,UI与用户的交互,避免页面的重新加载.

优点 : 
1.用户体验好,快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染
2.基于上面一点,SPA相对服务器压力小
3.前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理

缺点:
1.初次加载耗时多
2.前进后退路由管理: 由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能
3.SEO难度较大

二、多页面
  MPA:值多个独立页面的应用,每个页面必须重复加载js、css等相关资源,多页面跳转,需要整页资源刷新

19、服务端渲染SSR

SSR也就是服务端渲染,就是将Vue在客户端把标签渲染成HTML的工作放在服务端完成,然后再把html直接返回给客户端

优点
SSR有着更好的SEO,并且首屏加载速度更快

缺点
开发条件会收到限制,服务端渲染只支持beforeCreate和Created两个钩子,当我们需要一些外部括展
服务端会有更大的负载需求