Vue 常见面试题总结MVVM模型?
MVVM,是Model-View-的简写,其本质是MVC模型的升级版。其中Model代表数据模型,View代表看到的页面,是View和Model
之间的桥梁,数据会绑定到层并自动将数据渲染到页面中,视图变化的时候会通知层更新数据。以前是通过操作DOM来更新视图,现在是数据驱动视图。
Vue的生命周期
Vue 的生命周期可以分为8个阶段:创建前后、挂载前后、更新前后、销毁前后,以及一些特殊场景的生命周期。Vue 3 中还新增了是3个用于调试和服务端渲染的场景。
Vue 2中的生命周期钩子Vue 3选项式API的生命周期选项Vue 3 组合API中生命周期钩子描述
setup()
创建前,此时data和的数据都还没有初始化
setup()
创建后,data中有值,尚未挂载,可以进行一些Ajax请求
挂载前,会找到虚拟DOM,编译成
挂载后,DOM已创建,可用于获取访问数据和DOM元素
更新前,可用于获取更新前各种状态
更新后,所有状态已是最新
销毁前,可用于一些定时器或订阅的取消
销毁后,可用于一些定时器或订阅的取消
keep-alive缓存的组件激活时
keep-alive缓存的组件停用时
捕获一个来自子孙组件的错误时调用
—
调试钩子,响应式依赖被收集时调用
—
调试钩子,响应式依赖被触发时调用
—
组件实例在服务器上被渲染前调用
「父子组件的生命周期:」
Vue.$
「在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。」
是 Vue 提供的一个全局 API,由于 Vue 的异步更新策略,导致我们对数据修改后不会直接体现在 DOM 上,此时如果想要立即获取更新后的 DOM 状态,就需要借助该方法。
Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue 将开启一个异步更新队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个被多次触发,只会被推入队列一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。方法会在队列中加入一个回调函数,确保该函数在前面的 DOM 操作完成后才调用。
使用场景:
如果想要在修改数据后立刻得到更新后的DOM结构,可以使用Vue.()
在生命周期中进行DOM操作
Vue 实例挂载过程中发生了什么?
挂载过程指的是app.mount()过程,这是一个初始化过程,整体上做了两件事情:初始化和建立更新机制。
初始化会创建组件实例、初始化组件状态、创建各种响应式数据。
建立更新机制这一步会立即执行一次组件的更新函数,这会首次执行组件渲染函数并执行patch将vnode转换为dom;同时首次执行渲染函数会创建它内部响应式数据和组件更新函数之间的依赖关系,这使得以后数据发生变化时会执行对应的更新函数。
Vue 的模版编译原理
Vue 中有个独特的编译器模块,称为,它的主要作用是将用户编写的编译为js中可执行的函数。
在Vue 中,编译器会先对进行解析,这一步称为parse,结束之后得到一个JS对象,称之为抽象语法树AST;然后是对AST进行深加工的转换过程,这一步称为,最后将前面得到的AST生成JS代码,也就是函数。
Vue 的响应式原理
Vue 2 中的数据响应式会根据数据类型做不同的处理。如果是对象,则通过.(obj,key,)拦截对象属性访问,当数据被访问或改变时,感知并作出反应;如果是数组,则通过覆盖数组原型的方法,扩展它的7个变更方法(push、pop、shift、、、sort、),使这些方法可以额外的做更新通知,从而做出响应。
缺点:
Vue 3 中利用ES6的Proxy机制代理需要响应化的数据。可以同时支持对象和数组,动态属性增、删都可以拦截,新增数据结构均支持,对象嵌套属性运行时递归,用到时才代理,也不需要维护特别多的依赖关系,性能取得很大进步。
虚拟DOM
概念:
虚拟DOM,顾名思义就是虚拟的DOM对象,它本身就是一个JS对象,只不过是通过不同的属性去描述一个视图结构。
虚拟DOM的好处:
(1) 性能提升
直接操作DOM是有限制的,一个真实元素上有很多属性,如果直接对其进行操作,同时会对很多额外的属性内容进行了操作,这是没有必要的。如果将这些操作转移到JS对象上,就会简单很多。另外,操作DOM的代价是比较昂贵的,频繁的操作DOM容易引起页面的重绘和回流。如果通过抽象VNode进行中间处理,可以有效减少直接操作DOM次数,从而减少页面的重绘和回流。
(2) 方便跨平台实现
同一VNode节点可以渲染成不同平台上对应的内容,比如:渲染在浏览器是DOM元素节点,渲染在(iOS、)变为对应的控件。Vue 3 中允许开发者基于VNode实现自定义渲染器(),以便于针对不同平台进行渲染。
结构:
没有统一的标准,一般包括tag、props、三项。
tag:必选。就是标签,也可以是组件,或者函数。
props:非必选。就是这个标签上的属性和方法。
:非必选。就是这个标签的内容或者子节点。如果是文本节点就是字符串;如果有子节点就是数组。换句话说,如果判断是字符串的话,就表示一定是文本节点,这个节点肯定没有子元素。
diff 算法
概念:
diff算法是一种对比算法,通过对比旧的虚拟DOM和新的虚拟DOM,得出是哪个虚拟节点发生了改变,找出这个虚拟节点并只更新这个虚拟节点所对应的真实节点,而不用更新其他未发生改变的节点,实现精准地更新真实DOM,进而提高效率。
对比方式:
diff算法的整体策略是:深度优先,同层比较。比较只会在同层级进行, 不会跨层级比较;比较的过程中,循环从两边向中间收拢。
Vue中key的作用?
key的作用主要是为了更加高效的更新虚拟 DOM。
Vue 判断两个节点是否相同时,主要是判断两者的key和元素类型tag。因此,如果不设置key,它的值就是 ,则可能永远认为这是两个相同的节点,只能去做更新操作,将造成大量的 DOM 更新操作。
为什么组件中的 data 是一个函数?
在 new Vue() 中,可以是函数也可以是对象,因为根实例只有一个,不会产生数据污染。
在组件中,data 必须为函数,目的是为了防止多个组件实例对象之间共用一个 data,产生数据污染;而采用函数的形式, 时会将其作为工厂函数都会返回全新的 data 对象。
Vue 中组件间的通信方式?
父子组件通信:
父向子传递数据是通过props,子向父是通过$emit触发事件;
通过父链/子链也可以通信($/$);
ref也可以访问组件实例;/;$attrs/$。
兄弟组件通信:
全局事件总线、Vuex。
跨层级组件通信:
全局事件总线、Vuex、/。
v-show 和 v-if 的区别?
控制手段不同。v-show是通过给元素添加 css 属性: none,但元素仍然存在;而v-if控制元素显示或隐藏是将元素整个添加或删除。
编译过程不同。v-if切换有一个局部编译/卸载的过程,切换过程中合适的销毁和重建内部的事件监听和子组件;v-show只是简单的基于 css 切换。
编译条件不同。v-if是真正的条件渲染,它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建,渲染条件为假时,并不做操作,直到为真才渲染。
触发生命周期不同。v-show由 false 变为 true 的时候不会触发组件的生命周期;v-if由 false 变为 true 的时候,触发组件的、、、钩子,由 true 变为 false 的时候触发组件的、钩子。
性能消耗不同。v-if有更高的切换消耗;v-show有更高的初始渲染消耗。
使用场景:
如果需要非常频繁地切换,则使用v-show较好,如:手风琴菜单vue.set()用法,tab 页签等;如果在运行时条件很少改变,则使用v-if较好,如:用户登录之后,根据权限不同来显示不同的内容。
和 watch 的区别?
运用场景:
计算属性一般用在模板渲染中,某个值是依赖其它响应对象甚至是计算属性而来;而侦听属性适用于观测某个值的变化去完成一段复杂的业务逻辑。
v-if 和 v-for 为什么不建议放在一起使用?
Vue 2 中,v-for的优先级比v-if高,这意味着v-if将分别重复运行于每一个v-for循环中。如果要遍历的数组很大,而真正要展示的数据很少时,将造成很大的性能浪费。
Vue 3 中,则完全相反,v-if的优先级高于v-for,所以v-if执行时,它调用的变量还不存在,会导致异常。
通常有两种情况导致要这样做:
Vue 2中的set方法?
set是Vue 2中的一个全局API。可手动添加响应式数据,解决数据变化视图未更新问题。当在项目中直接设置数组的某一项的值,或者直接设置对象的某个属性值,会发现页面并没有更新。这是因为.()的限制,监听不到数据变化,可通过this.$set(数组或对象,数组下标或对象的属性名,更新后的值)解决。
keep-alive 是什么?
设置了keep-alive缓存的组件,会多出两个生命周期钩子:、。
首次进入组件时: --> --> --> --> --> --> -->
再次进入组件时: --> --> -->
mixin
mixin(混入), 它提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。
使用场景:不同组件中经常会用到一些相同或相似的代码,这些代码的功能相对独立。可以通过mixin 将相同或相似的代码提出来。
缺点:
变量来源不明确
多 mixin 可能会造成命名冲突(解决方式:Vue 3的组合API)
mixin 和组件出现多对多的关系,使项目复杂度变高。
插槽
slot插槽,一般在组件内部使用,封装组件时,在组件内部不确定该位置是以何种形式的元素展示时,可以通过slot占据这个位置,该位置的元素需要父组件以内容形式传递过来。slot分为:
Vue 中的修饰符有哪些?
在Vue 中,修饰符处理了许多 DOM 事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理。Vue中修饰符分为以下几种:
表单修饰符
lazy填完信息,光标离开标签的时候,才会将值赋予给value,也就是在事件之后再进行信息同步。
自动将用户输入值转化为数值类型,但如果这个值无法被解析,则会返回原来的值。
trim自动过滤用户输入的首尾空格,而中间的空格不会被过滤。
事件修饰符
stop阻止了事件冒泡,相当于调用了event.方法。
阻止了事件的默认行为,相当于调用了event.方法。
self只当在event.是当前元素自身时触发处理函数。
once绑定了事件以后只能触发一次,第二次就不会触发。
使用事件捕获模式,即元素自身触发的事件先在此处处理,然后才交由内部元素进行处理。
告诉浏览器你不想阻止事件的默认行为。
让组件变成像html内置标签那样监听根元素的原生事件,否则组件上使用v-on只会监听自定义事件。
鼠标按键修饰符
left左键点击。
right右键点击。
中键点击。
键值修饰符
键盘修饰符是用来修饰键盘事件(,)的,有如下:存在很多,但vue为我们提供了别名,分为以下两种:
对 SPA 的理解?
概念:
SPA(-page )vue.set()用法,即单页面应用,它是一种网络应用程序或网站的模型,通过动态重写当前页面来与用户交互,这种方法避免了页面之间切换时打断用户体验。在SPA中,所有必要的代码(HTML、 和 CSS)都通过单个页面的加载而检索,或者根据需要(通常是响应用户操作)动态装载适当的资源并添加到页面。页面在任何时间点都不会重新加载,也不会将控制转移到其他页面。举个例子,就像一个杯子,上午装的是牛奶,中午装的是咖啡,下午装的是茶,变得始终是内容,杯子始终不变。
SPA与MPA的区别:
MPA(Muti-page ),即多页面应用。在MPA中,每个页面都是一个主页面,都是独立的,每当访问一个页面时,都需要重新加载 Html、CSS、JS 文件,公共文件则根据需求按需加载。
组成
一个主页面和多个页面片段
多个主页面
url模式
hash模式
模式
SEO搜索引擎优化
难实现,可使用SSR方式改善
容易实现
数据传递
容易
通过url、、等传递
页面切换
速度快,用户体验良好
切换加载资源,速度慢,用户体验差
维护成本
相对容易
相对复杂
3.SPA的优缺点:
不利于搜索引擎的抓取
首次渲染速度相对较慢
具有桌面应用的即时性、网站的可移植性和可访问性
用户体验好、快,内容的改变不需要重新加载整个页面
良好的前后端分离,分工更明确
双向绑定?
概念:
Vue 中双向绑定是一个指令v-model,可以绑定一个响应式数据到视图,同时视图的变化能改变该值。v-model是语法糖,默认情况下相当于:value和@input,使用v-model可以减少大量繁琐的事件处理代码,提高开发效率。
使用:
通常在表单项上使用v-model,还可以在自定义组件上使用,表示某个值的输入和输出控制。
原理:
v-model是一个指令,双向绑定实际上是Vue 的编译器完成的,通过输出包含v-model模版的组件渲染函数,实际上还是value属性的绑定及input事件监听,事件回调函数中会做相应变量的更新操作。
子组件是否可以直接改变父组件的数据?
所有的prop都遵循着单项绑定原则,props因父组件的更新而变化,自然地将新状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。
另外,每次父组件更新后,所有的子组件中的props都会被更新为最新值,这就意味着不应该子组件中去修改一个prop,若这么做了,Vue 会在控制台上抛出警告。
实际开发过程中通常有两个场景导致要修改prop:
实践中,如果确实要更改父组件属性,应emit一个事件让父组件变更。当对象或数组作为props被传入时,虽然子组件无法更改props绑定,但仍然「可以」更改对象或数组内部的值。这是因为JS的对象和数组是按引用传递,而对于 Vue 来说,禁止这样的改动虽然可能,但是有很大的性能损耗,比较得不偿失。
Vue 中的常用路由模式和原理?
hash 模式:
模式:
利用 HTML5 中新增的()和()方法。
这两个方法应用于浏览器的历史记录栈,在当前已有的back、、go的基础上,他们提供了对历史记录进行修改的功能。
这两个方法有个共同点:当调用他们修改浏览器历史记录栈后,虽然当前url改变了,但浏览器不会刷新页面,这就为单页面应用前端路由“更新视图但不重新请求页面”提供了基础
特点:虽然美观,但是刷新会出现 404 需要后端进行配置。
动态路由?
很多时候,我们需要将给定匹配模式的路由映射到同一个组件,这种情况就需要定义动态路由。例如,我们有一个 User组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue- 的路由路径中使用动态路径参数( )来达到这个效果:{path: '/user/:id', : User},其中:id就是动态路径参数。
对Vuex的理解?
概念:
Vuex 是 Vue 专用的状态管理库,它以全局方式集中管理应用的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
解决的问题:
Vuex 主要解决的问题是多组件之间状态共享。利用各种通信方式,虽然也能够实现状态共享,但是往往需要在多个组件之间保持状态的一致性,这种模式很容易出问题,也会使程序逻辑变得复杂。Vuex 通过把组件的共享状态抽取出来,以全局单例模式管理,这样任何组件都能用一致的方式获取和修改状态,响应式的数据也能够保证简洁的单向流动,使代码变得更具结构化且易于维护。
什么时候用:
Vuex 并非是必须的,它能够管理状态,但同时也带来更多的概念和框架。如果我们不打算开发大型单页应用或应用里没有大量全局的状态需要维护,完全没有使用Vuex的必要,一个简单的 store 模式就够了。反之,Vuex将是自然而然的选择。
用法:
Vuex 将全局状态放入state对象中,它本身是一颗状态树,组件中使用store实例的state访问这些状态;然后用配套的方法修改这些状态,并且只能用修改状态,在组件中调用方法提交;如果应用中有异步操作或复杂逻辑组合,需要编写,执行结束如果有状态修改仍需提交,组件中通过派发。最后是模块化,通过选项组织拆分出去的各个子模块,在访问状态(state)时需注意添加子模块的名称,如果子模块有设置,那么提交和派发时还需要额外的命名空间前缀。
页面刷新后Vuex 状态丢失怎么解决?
Vuex 只是在内存中保存状态,刷新后就会丢失,如果要持久化就需要保存起来。
就很合适,提交的时候同时存入,在store中把值取出来作为state的初始值即可。
也可以使用第三方插件,推荐使用vuex-插件,它是为 Vuex 持久化储存而生的一个插件,不需要你手动存取,而是直接将状态保存至或者中。
关于 Vue SSR 的理解?
SSR即服务端渲染( Side ),就是将 Vue 在客户端把标签渲染成 html 的工作放在服务端完成,然后再把 html 直接返回给客户端。
了解哪些 Vue 的性能优化方法?
欢迎长按图片加刷碗智为好友,定时分享 Vue React Ts 等。
最后: