vue2/3面试题

持续更新中....

v-show和v-if指令的共同点和不同点

相同点:v-show和v-if都能控制元素的显示和隐藏

不同点:手段:v-if是动态的向DOM树内添加或者删除DOM元素;
v-show是通过设置DOM元素的display样式属性控制显隐;
编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;
v-show只是简单的基于css切换;编译条件:v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译;
v-show是在任何条件下,无论首次条件是否为真,都被编译,然后被缓存,而且DOM元素保留;性能消耗:v-if有更高的切换消耗;
v-show有更高的初始渲染消耗;使用场景:v-if适合运营条件不大可能改变;v-show适合频繁切换。

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

Vue组件可能存在多个实例,如果使用对象形式定义data,则会导致它们共用一个data对象,那么状态变更将会影响所有组件实例,这是不合理的;采用函数形式定义,在initData时会将其作为工厂函数返回全新data对象,有效规避多实例之间状态污染问题。而在Vue根实例创建过程中则不存在该限制,也是因为根实例只能有一个,不需要担心这种情况。

$nextTick的使用

用法:将回调延迟到下次DOM更新循环之后执行。在修改数据之后立即使用它,然后等待DOM更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。

$nextTick() 的应用场景

    在vue的生命周期 created() 钩子函数中进行 dom 操作,一定要放在 $nextTick() 函数中执行。在 created() 钩子函数执行的时候 DOM 其实并未进行任何渲染,而此时进行 DOM 操作无异于徒劳,所以此处一定要将 DOM 操作的代码放进 nextTick() 的回调函数中。

    mounted() 钩子函数,因为该钩子函数执行时,所有的 DOM 挂载和 渲染都已完成,此时在该钩子函数中进行任何 DOM 操作都不会有问题

在数据变化后要执行某个操作,而这个操作需要随数据改变而改变DOM结构时,这个操作都是需要放置 $nextTick() 的回调函数中。

Vue中双向数据绑定是如何实现的

Vue 数据双向绑定主要是指:数据变化更新视图,视图变化更新数据

实现原理:采用数据监听、解析结合订阅者模式的方式,通过Object.defineProperty()来监听各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。从而实现数据的双向绑定

主要分为以下几个步骤:

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

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

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

MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

vue中v-if和v-for优先级在vue2和vue3中的区别

实践中不管是vue2或者vue3都不应该把v-if和v-for放在一起使用。

在 vue 2.x 中,在一个元素上同时使用 v-if 和 v-for 时, v-for 会优先作用。

在 vue 3.x 中, v-if 总是优先于 v-for 生效。

vue2中v-for的优先级是高于v-if的,放在一起,会先执行循环在判断条件,并且如果值渲染列表中一小部分元素,也得再每次重渲染的时候遍历整个列表,比较浪费资源。

vue3中v-if的优先级是高于v-for的,所以v-if执行时,它调用相应的变量如果不存在,就会导致异常

vue常用的修饰符

.stop:等同于 JavaScript 中的 event.stopPropagation() ,防止事件冒泡;

.prevent :等同于 JavaScript 中的 event.preventDefault() ,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);作用是阻止默认事件(例如a标签的跳转

.capture :与事件冒泡的方向相反,事件捕获由外到内;

.self :只会触发自己范围内的事件,不包含子元素;

.once :只会触发一次。

.trim修饰符的作用是把v-model绑定的值的首尾空格给去掉。在实际开发中我们一般用于搜索框的内容修饰,过滤掉用户多输入前后空格导致内容查不出来的情况。

.left,.right,.middle这三个修饰符是鼠标的左中右按键触发的事件.

自定义指令详解

为什么需要自定义指令:因为vue是MVVM模式,只需要关注于数据和业务逻辑,不需要关注DOM的操作,但是有时候面对一些特殊的业务需求时,需要进行DOM的操作,这个时候就需要进行自定义指令。

自定义局部指令:在options api选项中的directives中设置。局部自定义指令是一个对象,对象的属性是自定义指令的名称,对象中属性的值是自定义指令的钩子函数对象

自定义全局指令:在app的directive方法。参数一(name):自定义指令的名称。参数二(hooks):自定义指令的钩子函数对象

slot是什么?有什么作用?原理是什么?

slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot又分三类,默认插槽,具名插槽和作用域插槽。

默认插槽:又名匿名插槽,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。

具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。

作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。

实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.$slot中,默认插槽为vm.$slot.default,具名插槽为vm.$slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用$slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。

vue初始化页面闪动问题

在简单项目中,使用 v-cloak 指令是解决屏幕闪动的好方法。但在大型、工程化的项目中(webpack、vue-router)只有一个空的 div 元素,元素中的内容是通过路由挂载来实现的,这时我们就不需要用到 v-cloak 指令了。

vue更新数组时触发视图更新的方法

Vue.set 响应式新增与修改数据

可以设置对象或数组的值,通过key或数组索引,可以触发视图更新

Vue.delete:删除对象或数组中元素,通过key或数组索引,可以触发视图更新

  push() 向数组的末尾添加一个或多个元素,并返回新的长度。

  pop() 删除最后一个元素,把数组长度减 1,并且返回它删除的元素的值。

  shift() 把数组的第一个元素从其中删除,并返回第一个元素的值。

  unshift() 向数组的开头添加一个或更多元素,并返回新的长度。

  splice() 向/从数组中添加/删除项目,然后返回被删除的项目。 该方法会改变原始数组。

  sort() 对数组的元素进行排序。

  reverse() 颠倒数组中元素的顺序。

filter()、concat()、 slice()  这些方法不会改变被操作的数组,返回一个新的数组;

Vue2.0 和 Vue3.0 有什么区别?

双向绑定更新

vue2 的双向数据绑定是利⽤ES5 的⼀个 API ,Object.defineProperty()对数据进⾏劫持 结合 发布订阅模式的⽅式来实现的。

vue3 中使⽤了 ES6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。

    这⾥是相⽐于vue2版本,使⽤proxy的优势如下

    1.defineProperty只能监听某个属性,不能对全对象监听 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)

    2.可以监听数组,不⽤再去单独的对数组做特异性操作,通过Proxy可以直接拦截所有对象类型数据的操作,完美⽀持对数组的监听。

获取props

vue2在script代码块可以直接获取props,vue3通过setup指令传递

API不同

Vue2使⽤的是选项类型API(Options API),Vue3使⽤的是合成型API(Composition API)

建立数据data

vue2是把数据放入data中,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造得时候触发。

生命周期不同

vue2     -------- vue3

beforeCreate   -> setup() 开始创建组件之前,创建的是data和method

created        -> setup()

beforeMount    -> onBeforeMount 组件挂载到节点上之前执行的函数。

mounted       -> onMounted 组件挂载完成后执行的函数

beforeUpdate   -> onBeforeUpdate 组件更新之前执行的函数。

updated        -> onUpdated 组件更新完成之后执行的函数。

beforeDestroy   -> onBeforeUnmount 组件挂载到节点上之前执行的函数。

destroyed      -> onUnmounted 组件卸载之前执行的函数。dszhuoyi

activated       -> onActivated 组件卸载完成后执行的函数

deactivated     -> onDeactivated

关于v-if和v-for的优先级:

vue2 在一个元素上同时使用 v-if 和 v-for  v-for会优先执行

    vue3 v-if 总会优先于  v-for生效

vue2和vue3的diff算法

vue2

    vue2 diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点 不同的地方,最后用patch记录的消息去局部更新Dom。

    vue2 diff算法会比较每一个vnode,而对于一些不参与更新的元素,进行比较是有 点消耗性能的。

vue3

    vue3 diff算法在初始化的时候会给每个虚拟节点添加一个patchFlags,patchFlags 就是优化的标识。

    只会比较patchFlags发生变化的vnode,进行更新视图,对于没有变化的元素做静 态标记,在渲染的时候直接复用。

Vue3带来了什么改变?

Vue3.0在性能方面比Vue2.x快了1.2~2倍。

重写虚拟DOM的实现

运行时编译

静态提升与事件侦听器缓存

SSR 速度提高

Vue3.x采用TypeScript重写,开发者使用Vue3.x时可以充分体验TS给编码带来的便利。

Composition API:vue2中,我们一般会采用mixin来复用逻辑代码,用倒是挺好用的,不过也存在一些问题:例如代码来源不清晰、方法属性等冲突。基于此在vue3中引入了Composition API(组合API),使用纯函数分隔复用代码。和React中的hooks的概念很相似

reactive与ref的区别?

Vue3 中的 ref 和 reactive 是 Vue3 中用于数据管理的两种不同的响应式 API。

ref 用于创建一个包装简单值的响应式引用,例如一个数字、字符串或对象。当 ref 创建一个响应式引用时,它返回一个对象,该对象具有一个 value 属性,该属性指向实际值。当 ref 返回的对象中的 value 属性更改时,组件将自动重新渲染。

reactive 用于创建一个响应式对象,该对象可以包含多个属性和嵌套属性。当使用 reactive 创建响应式对象时,返回的对象是一个代理对象,该对象具有与原始对象相同的属性,并且任何对代理对象属性的更改都将触发组件的重新渲染。

综上所述,如果需要对简单值进行响应式处理,则使用 ref,如果需要对对象或嵌套对象进行响应式处理,则使用 reactive。

计算属性和watch以及methods的区别?

对于Computed:它支持缓存,只有依赖的数据发生了变化,才会重新计算

不支持异步,当Computed中有异步操作时,无法监听数据的变化

computed的值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data声明过,或者父组件传递过来的props中的数据进行计算的。

如果一个属性是由其他属性计算而来的,这个属性依赖其他的属性,一般会使用computed

如果computed属性的属性值是函数,那么默认使用get方法,函数的返回值就是属性的属性值;在computed中,属性有一个get方法和一个set方法,当数据发生变化时,会调用set方法。

对于Watch:它不支持缓存,数据变化时,它就会触发相应的操作

支持异步监听

监听的函数接收两个参数,第一个参数是最新的值,第二个是变化之前的值

当一个属性发生变化时,就需要执行相应的操作监听数据必须是data中声明的或者父组件传递过来的props中的数据,当发生变化时,会触发其他操作,函数

有两个的参数:immediate:组件加载立即触发回调函数  deep:深度监听,发现数据内部的变化,在复杂数据类型中使用,例如数组中的对象发生变化。需要注意的是,deep无法监听到数组和对象内部的变化。

当想要执行异步或者昂贵的操作以响应不断的变化时,就需要使用watch。

$route 和 $router 的区别?

$route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数

$router 是“路由实例”想要导航到不同URL 对象包括了路由的跳转方法,钩子函数等。

v-model的使用?

v-model实现双向绑定的语法糖,常用于表单与组件之间的数据双向绑定.

V-model的原理:

    v-bind绑定一个value属性

    v-on指令给当前元素绑定input事件

可看出v-model绑定在表单上时,v-model其实就是v-bind绑定value和v-on监听input事件的结合体

组件上的双向绑定(原理)

v-model绑定在组件上的时候做了以下步骤

    在父组件内给子组件标签添加 v-model ,其实就是给子组件绑定了 value 属性

    子组件内使用 prop 创建 创建 value 属性可以拿到父组件传递下来的值,名字必须是 value。

    子组件内部更改 value 的时候,必须通过 $emit 派发一个 input 事件,并携最新的值

    v-model 会自动监听 input 事件,把接收到的最新的值同步赋值到 v-model 绑定的变量上

v-on可以监听多个方法吗?

可以一个元素绑定多个事件的两种写法,一个事件绑定多个函数的两种写法,修饰符的使用。

doSomething

在method方法里面分别写两个事件;

vue中过滤器有什么作用及详解?

根据过滤器的名称,过滤器是用来过滤数据的,在Vue中使用filters来过滤数据,filters不会修改数据,而是过滤数据,改变用户看到的输出(计算属性 computed ,方法 methods 都是通过修改数据来处理数据格式的输出显示)。

使用场景:需要格式化数据的情况,比如需要处理时间、价格等数据格式的输出 / 显示。比如后端返回一个 年月日的日期字符串,前端需要展示为 多少天前 的数据格式,此时就可以用fliters过滤器来处理数据。

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

EventBus注册在全局上时,路由切换时会重复触发事件,如何解决呢?

添加Bus.$off来关闭

beforeDestroy () {

bus.$off('get', this.myhandle)

}

如果想要用bus 来进行页面组件之间的数据传递,需要注意亮点,组件$emit事件应在beforeDestory生命周期内。其次,组件B内的$on记得要销毁。

vuex有哪几种属性?

vuex 是 Vue 配套的 公共数据管理工具,它可以把一些共享的数据,保存到 vuex 中,方便整个程序中的任何组件直接获取或修改我们的公共数据。

有五种,分别是 State、 Getter、Mutation 、Action、 Module

vuex 是 Vue 配套的 公共数据管理工具,它可以把一些共享的数据,保存到 vuex 中,方便整个程序中的任何组件直接获取或修改我们的公共数据。

有五种,分别是 State、 Getter、Mutation 、Action、 Module

state:用来存放多个组件会用到的公共属性

mutations:改变state的规范途径,并且只能同步操作,可以在vue-devtools 追踪到修改记录

getters:作用和computed相似,对state里面的多个属性计算时使用

actions:一些对state的异步操作可以放在actions中,并通过在action提交到mutaions进行状态的修改

modules:当store对象过于庞大时,可以根据具体的业务需求分为多个module

21.请详细说下你对vue生命周期的理解?

Vue的生命周期就是vue实例从创建到销毁的全过程,也就是new Vue() 开始就是vue生命周期的开始。Vue 实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载 等⼀系列过程,称这是Vue的⽣命周期。

有八个阶段创建前/后,载入前/后,更新前/后,销毁前/后

创建前/后: 在beforeCreate阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el还没有

载入前/后:在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。

更新前/后:当data变化时,会触发beforeUpdate和updated方法

销毁前/后:在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在

22.vue优点?

轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 kb ;

简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;

双向数据绑定:保留了 angular 的特点,在数据操作方面更为简单;

组件化:保留了 react 的优点,实现了 html 的封装和重用,在构建单页面应用方面有着独特的优势;

视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;

虚拟DOM:dom 操作是非常耗费性能的,不再使用原生的 dom 操作节点,极大解放 dom 操作,但具体操作的还是 dom 不过是换了另一种方式;

运行速度更快:相比较于 react 而言,同样是操作虚拟 dom,就性能而言, vue 存在很大的优势

23.单页面应用和多页面应用区别及优缺点?

单页面(Sing Page Application——SPA):顾名思义,只有一个页面。一般是一个主页和多个路由页面组成。

优点

    公共资源不重新加载,局部加载,服务器压力小

    切换速度快,用户体验好

    前后端分离

 缺点

    不利于SEO(可以优化:比如路由懒加载等)

    初次加载时耗时多

    开发难度较大(相对多页面)

多页面(Multi Page Application——MPA):有多个HTML页面,跳转的时候是从一个html页面跳到另一个页面。

优点

    利于SEO。

    更容易扩展。

    更易数据分析。

缺点

    开发成本高。

    服务器压力大。

    用户体验相对较差。

24.vue路由跳转传参的方式有哪些?

params传参(显示参数)

在url中会显示出传参的值,刷新页面不会失去拿到的参数,使用该方式传值的时候,需要子路由提前配置好参数

params传参(不显示参数)

在url中不会显示出传参的值,但刷新页面会失去拿到的参数,使用该方式 传值 的时候,需要子路由提前配置好name参数

query 传参

query 传过去的参数会拼接在地址栏中(?name=xx),刷新页面数据不会丢失,使用path和name都可以

VUE几种路由跳转几种方式的区别

this.$router.push:跳转到指定url路径,并想history栈中添加一个记录,点击后退会返回到上一个页面

this.$router.replace:跳转到指定url路径,但是history栈中不会有记录,点击返回会跳转到上上个页面 (就是直接替换了当前页面)

this.$router.go(n):向前或者向后跳转n个页面,n可为正整数或负整数

25.vue遇到的坑,如何解决的?

用webpack打包后访问index.html出现资源加载404问题,解决:开发环境的static文件夹是基于根目录的,所以直接用‘/’ 。

vue中,假如,你引入某个样式,然后这个样式里面有引用到图片,如果你的文件中没有这个图片,这时候,即使你没有引用这个图片对应的类名,但是只要你有引入这个css文件,他找不到相应路径图片也会报错!!!

用for循环出来的列表,在设置列表中的元素的动态属性时,需要加bind属性“:”,不然动态属性设置不出来

在vue中的html中的img中的src不可以直接设置为变量,在data里面直接引路径,只能通过import的形式引入,值得注意的是,引用这个方式的时候src是变量需要加“:”,不然会报错!!!!!

在中使用v-for="(item ,index) in list"进行循环时,需要注意加::key=“index”,不然会出现警告!

父组件ajax异步更新数据,子组件props获取不到

应用场景

当父组件  axjos  获取数据,子组件使用  props  接收数据时,执行  mounted  的时候  axjos  还没有返回数据,而且  mounted 只执行一次,这时   props  中接收的数据为空

解决方案:在对应组件中判断数据的长度

26.vue封装通用组件方法思路?

封装组件需要注意三点:1. props参数2. slot定制插槽3. event自定义事件

首先,使用Vue.extend()创建一个组件

然后,使用Vue.component()方法注册组件

接着,如果子组件需要数据,可以在props中接受定义

最后,子组件修改好数据之后,想把数据传递给父组件,可以使用emit()方法

父子组件间的数据传递

    父组件通过 prop 将数据传递给子组件

    子组件通过 emit 事件将子组件数据传递给父组件

    子组件不能直接修改 prop 中传给父组件的值

27.Vue.js中ajax请求代码应该写在组件的methods中还是vuex的actions中?

如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。

如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用,并包装成promise返回,在调用处用async await处理返回的数据。如果不要复用这个请求,那么直接写在vue文件里很方便。

28.Vuex中如何异步修改状态?

actions类似于mutations,不同在于:Action提交的是mutation,而不是直接变更状态;

Action可以包含任意异步操作,Action函数接受一个与store实例具有相同方法和属性的 context对象,因此你可以调用context.commit提交一个mutation,或者通过context.state 和context.getters来获取state和getters。

Action 通过store.dispatch方法触发:store.dispatch('increment')

29.刷新浏览器后,Vuex的数据是否存在?如何解决?

原因:因为 store 里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值初始化。

localStorage 或者就是sessionStorage

下载持久化存储插件。比如使用:vuex-along 的实质也是将 vuex 中的数据存放到 localStorage 或者 sessionStroage 中,只不过这个存取过程组件会帮我们完成,我们只需要用vuex的读取数据方式操作就可以了

30.vuex中的辅助函数怎么使用?

vuex的辅助函数有4个

mapState 函数返回的是一个对象。通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给 computed 属性。

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性,因此你可以这样来使用他

mapMutations 辅助函数将组件中的 methods 映射为 store.commit,其原理就是将this.montify 映射为this.$store.commit(‘montify’)

mapActions在组件中使用 this.$store.dispatch('prodect') 分发 action,或者使用 mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用

31.vue插槽的理解?

Vue插槽是Vue中常见的一种组件间的相互通信方式,作用是让父组件可以向子组件指定位置插入html结构,适用于父组件===>子组件,在要接收数据的组件页面通过标签来表示,简单来说,就是通过此标签来起到占位的作用,而要插入的内容也会对应到标签所在的位置。

默认插槽是插槽最基本的方式
首先在父组件App.Vue中引入子组件,并在引入的子组件标签内插入需要的html元素,在子组件中把需要用插槽的地方用标签替代

具名插槽就是有名字的插槽

使用:首先在要插入html的部分需要用一个