最全的Vue⾯试题+详解答案
最全vue⾯试题+详解答案
1、MVC 和 MVVM 区别
MVC
MVC全名是 Model View Controller,时模型 - 视图 - 控制器的缩写,⼀种软件设计典范。
Model(模型):是⽤于处理应⽤程序数据逻辑部分。通常模型对象负责在数据库中存取数据。
View(视图):是应⽤程序中处理数据显⽰的本分。通常视图是依据模型数据创建的。
Controller(控制器):是应⽤程序处理⽤户交互的部分。通常控制器负责从视图读取数据,控制⽤户输⼊,并向模型发送数据。
MVC的思想:⼀句话描述就是Controller负责将Model的数据⽤View显⽰出来,换句话说就是在Controller⾥⾯把Model的数据赋值给View。MVVM
MVVM新增了VM类。
ViewModel层:做了两件事达到了数据的双向绑定,⼀是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页⾯。实现的⽅式时:数据绑定。⼆是将【视图】转化成【模型】,即将所看到的页⾯转换成后端的数据。实现的⽅式是:DOM事件监听。MVVM与MVC最⼤的区别就是:实现了View和Model的⾃动同步,也就是当Model的属性改变时,我们不⽤再⼿动操作Dom元素来改变View的显⽰。⽽是改变属性后该属性对应的View层显⽰会⾃动改变(对应Vue数据驱动的思想)
整体看来,MVVM⽐MVC精简很多,不仅简化了业务与界⾯的依赖,还解决了数据频繁更新的问题,不⽤再⽤选择器操作DOM元素。因为在MVVM中,View不知道Model的存在,Model和ViewModel也察觉不到View,这种低耦合模式提⾼代码的可重⽤性。
注意:Vue并没有完全遵循MVVM的思想,这⼀点官⽹⾃⼰也有声明。
那么问题来了,为什么官⽅要说Vue没有完全遵循MVVM思想呢?
严格的MVVVM要求View不能和Model直接通信,⽽Vue提供了$refs这个属性,让Model可以直接操作View,违反了这⼀规定,所以是Vue 没有完全遵循MVVM。
2、为什么data是⼀个函数
组件的data写成⼀个函数,数据以函数返回值形式定义,这样每复⽤⼀次组件,就会返回⼀分新的data,
类似于给每个组件实例创建⼀个私有的数据空间,让各个组件实例维护各⾃的数据。⽽单纯的写成对象形式,就使得所有组件实例共⽤了⼀份data,就会造成⼀个变了全都会变的结果。
3、Vue组件通讯有哪些⽅式?
1、props 和 $emit。⽗组件向⼦组件传递数据是通过props传递的,⼦组件传递给⽗组件是通过$emit触发事件来做到的。
2、$parent 和 $children 获取单签组件的⽗组件和当前组件的⼦组件。
3、$attrs 和 $listeners A -> B -> C。Vue2.4开始提供了$attrs和$listeners来解决这个问题。
4、⽗组件中通过 provide 来提供变量,然后在⼦组件中通过 inject 来注⼊变量。(官⽅不推荐在实际业务中适⽤,但是写组件库时很常⽤。)
5、$refs 获取组件实例。
6、envetBus 兄弟组件数据传递,这种情况下可以使⽤事件总线的⽅式。
7、vuex 状态管理。
4、Vue的⽣命周期⽅法有哪些?⼀般在哪⼀步发送请求?
beforeCreate 在实例初始化之后,数据观测(data observe)和 event/watcher 事件配置之前被调⽤。在当前阶段 data、methods、computed 以及 watch 上的数据和⽅法都不能被访问。
created 实例已经创建完成之后被调⽤。在这⼀步,实例已经完成以下的配置:数据观测(data observe ),属性和⽅法的运
算,watch/event 事件回调。这⾥没有 $el,如果⾮要想与 DOM 进⾏交互,可以通过vm.$nextTick 来访问 DOM。
beforeMount 在挂载开始之前被调⽤:相关的 render 函数⾸次被调⽤。
mounted 在挂载完成后发⽣,在当前阶段,真实的 Dom 挂载完毕,数据完成双向绑定,可以访问到 Dom节点。
beforeUpdate 数据更新时调⽤,发⽣在虚拟 DOM 重新渲染和打补丁(patch)之前。可以在这个钩⼦中进⼀步地更改状态,这不会触发附加的重渲染过程。
updated 发⽣在更新完成之后,当前阶段组件 Dom 已经完成更新。要注意的是避免在此期间更新数据,因为这个可能导致⽆限循环的更新,该钩⼦在服务器渲染期间不被调⽤。
beforeDestroy 实例销毁之前调⽤。在这⼀步,实⼒仍然完全可⽤。我们可以在这时进⾏善后收尾⼯作,⽐如清除定时器。
destroy Vue实例销毁后调⽤。调⽤后,Vue实例指⽰的东西都会解绑定,所有的事件会被移除,左右的⼦实例也会被销毁,该钩⼦在服务器端渲染不被调⽤。
activated keep-alive 专属,组件被激活时调⽤
deactivated keep-alive 专属,组件被销毁时调⽤
异步请求在哪⼀步发起?
可以在钩⼦函数 created、beforeMount、mounted 中进⾏异步请求,因为在这三个钩⼦函数中,data已经创建,可以将服务器端返回的数据进⾏赋值。
如果异步请求不需要依赖 DOM 推荐加载 created 钩⼦函数中调⽤异步请求,因为在 created 钩⼦函数中调⽤异步请求有以下优点:
能更快获取到服务端数据,减少页⾯loading时间;
ssr 不⽀持 beforeMount、mounted 钩⼦函数,所以放在 created 中有助于⼀致性。
5、v-if 和 v-show 的区别
v-if 在编译过程中会被转化成三元表达式,条件不满⾜时不渲染此节点。
v-show 会被编译成指令,条件不满⾜时控制样式将此节点隐藏(display:none)
使⽤场景
v-if 适⽤于在运⾏时很少改变条件,不需要频繁切换条件的场景。
v-show 适⽤于需要⾮常频繁切换条件的场景。
扩展补充:display:none 、 visibility:hidden 和 opacity:0 之间的区别?
三者公共点都是隐藏。不同点:
⼀、是否占据空间。
display:none,隐藏之后不占位置;visibility:hidden、opacity:0,隐藏后任然占据位置。
⼆、⼦元素是否继承。
display:none --- 不会被⼦元素继承,⽗元素都不存在了,⼦元素也不会显⽰出来。
visibility:hidden --- 会被⼦元素继承,通过设置⼦元素 visibility:visible 来显⽰⼦元素。
opacity:0 --- 会被⼦元素继承,但是不能设置⼦元素 opacity:0 来先重新显⽰。
三、事件绑定。
display:none 的元素都已经不存在了,因此⽆法触发他绑定的事件。
visibility:hidden 不会触发他上⾯绑定的事件。
opacity:0 元素上⾯绑定的事件时可以触发的。
四、过度动画。
transition对于display是⽆效的。
transition对于visibility是⽆效的。
transition对于opacity是有效的。
6、说说 vue 内置指令
v-once - 定义它的元素或组件只渲染⼀次,包括元素或组件的所有节点,⾸次渲染后,不再随数据的变化重新渲染,将被视为静态内容。
v-cloak - 这个指令保持在元素上直到关联实例结束编译 -- 解决初始化慢到页⾯闪动的最佳实践。
v-bind - 绑定属性,动态更新HTML元素上的属性。例如 v-bind:class。
v-on - ⽤于监听DOM事件。例如 v-on:click v-on:keyup
v-html - 赋值就是变量的innerHTML -- 注意防⽌xss攻击
v-text - 更新元素的textContent
v-model - 1、在普通标签。变成value和input的语法糖,并且会处理拼⾳输⼊法的问题。2、再组件上。也是处理value和input语法糖。
v-if / v-else / v-else-if。可以配合template使⽤;在render函数⾥⾯就是三元表达式。
v-show - 使⽤指令来实现 -- 最终会通过display来进⾏显⽰隐藏
v-for - 循环指令编译出来的结果是 -L 代表渲染列表。优先级⽐v-if⾼最好不要⼀起使⽤,尽量使⽤计算属性去解决。注意增加唯⼀key 值,不要使⽤index作为key。
v-pre - 跳过这个元素以及⼦元素的编译过程,以此来加快整个项⽬的编译速度。
7、怎样理解 Vue 的单项数据流
数据总是从⽗组件传到⼦组件,⼦组件没有权利修改⽗组件传过来的数据,只能请求⽗组件对原始数据进⾏修改。这样会防⽌从⼦组件意外改变⽗组件的状态,从⽽导致你的应⽤的数据流向难以理解。
注意:在⼦组件直接⽤ v-model 绑定⽗组件传过来的 props 这样是不规范的写法,开发环境会报警告。
如果实在要改变⽗组件的 props 值可以再data⾥⾯定义⼀个变量,并⽤ prop 的值初始化它,之后⽤$emit 通知⽗组件去修改。
8、computed 和 watch 的区别和运⽤的场景。
computed 是计算属性,依赖其它属性计算值,并且 computed 的值有缓存,职友集当计算值变化才会返回内容,他可以设置getter和setter。
watch 监听到值的变化就会执⾏回调,在回调中可以进⾏⼀系列的操作。
计算属性⼀般⽤在模板渲染中,某个值是依赖其它响应对象甚⾄是计算属性⽽来;⽽侦听属性适⽤于观测某个值的变化去完成⼀段复杂的业务逻辑。
9、v-if 和 v-for 为什么不建议⼀起使⽤
v-for和v-if不要在同⼀标签中使⽤,因为解析时先解析v-for在解析v-if。如果遇到需要同时使⽤时可以考虑写成计算属性的⽅式。
10、Vue 2.0 响应式数据的原理
整体思路是数据劫持 + 观察者模式
对象内部通过 defineReactive ⽅法,使⽤ Object.defineProperty 将属性进⾏劫持(只会劫持已存在的属性),数组则是通过重写数组来实现。当页⾯使⽤对应属性时,每个属性都拥有⾃⼰的 dep 属性,存在它所依赖的 watcher (依赖收集)get,当属性变化后会通知⾃⼰对应的 watcher 去更新(派发更新)set。
1、Object.defineProperty 数据劫持
2、使⽤ getter 收集依赖,setter 通知 watcher派发更新。
3、watcher 发布订阅模式。
11、Vue 如何检测数组变化
数组考虑性能原因没有⽤ defineProperty 对数组的每⼀项进⾏拦截,⽽是选择对7种数组(push,shift,pop,splice,unshift,sort,reverse)⽅法进⾏重写(AOP 切⽚思想)。
所以在 Vue 中修改数组的索引和长度⽆法监控到。需要通过以上7种变异⽅法修改数组才会触发数组对应的watcher进⾏更新。
12、Vue3.0 ⽤过吗?了解多少?
响应式原理的改变 Vue3.x 使⽤ Proxy 取代 Vue2.x 版本的 Object.defineProperty。
组件选项声明⽅式 Vue3.x 使⽤ Composition API setup是Vue3.x新增的⼀个选项,他是组件内使⽤Composition API 的⼊⼝。
模板语法变化 slot 具名插槽语法,⾃定义指令v-model升级。
其他⽅⾯的更改 Suspense⽀持Fragment(多个根节点)和 Protal(在dom其他部分渲染组件内容)组件,针对⼀些特殊的场景做了处理。基于 treeShaking 优化,提供了更多的内置功能。
13、Vue3.0 和 2.0 的响应式原理区别
Vue3.x 改⽤ Proxy 替代 Object.defineProperty。因为 Proxy 可以直接监听对象和数组的变化,并且有多达13种拦截⽅法。
Vue的⽗⼦组件⽣命周期钩⼦函数执⾏顺序
加载渲染过程
⽗beforeCreate -> ⽗created -> ⽗beforeMount -> ⼦beforeCreate -> ⼦created -> ⼦beforeMount -> ⼦mounted -> ⽗mounted
⼦组件更新过程
⽗beforeUpdate -> ⼦beforeUpdate -> ⼦updated -> ⽗updated
⽗组件更新过程
⽗beforeUpdate -> ⽗updated
销毁过程
⽗beforeDestroy -> ⼦beforeDestroy -> ⼦destroyed -> ⽗destroyed
15、虚拟DOM是什么?有什么优缺点?
由于在浏览器中操作DOM是很昂贵的。频繁操作DOM,会产⽣⼀定性能问题。这就是虚拟Dom的产⽣原因。Vue2的Virtual DOM 借鉴了开源库 snabbdom 的实现。Virtual DOM本质就是⽤⼀个原⽣的JS对象去描述⼀个DOM节点,是对真实DOM的⼀层抽象。
优点:
1、保证性能下限:框架的虚拟DOM需要适配任何上层API可能产⽣的操作,他的⼀些DOM操作的实现必须是普适的,所以它的性能并不是最优的;但是⽐起粗暴的DOM操作性能要好很多,因此框架的虚拟DOM⾄少可以保证在你不需要⼿动优化的情况下,依然可以提供还不错的性能,既保证性能的下限。
2、⽆需⼿动操作DOM:我们不需⼿动去操作DOM,只需要写好 View-Model的代码逻辑,框架会根据虚拟DOM和数据双向绑定,帮我们
以可预期的⽅式更新视图,极⼤提⾼我们的开发效率。
3、跨平台:虚拟DOM本质上是JavaScript对象,⽽DOM与平台强相关,相⽐之下虚拟DOM可以进⾏更⽅便地跨平台操作,例如服务器端渲染、weex开发等等。
缺点:
1、⽆法进⾏极致优化:虽然虚拟DOM + 合理的优化,⾜以应对⼤部分应⽤的性能需要,但在⼀些性能要求极⾼的应⽤中虚拟DOM⽆法进⾏针对性的极致优化。
2、⾸次渲染⼤量DOM时,由于多了⼀层DOM计算,会⽐innerHTML插⼊慢。
16、v-model 原理
v-model 只是语法糖⽽已。
v-model 在内部为不同的输⼊元素使⽤不同的 property 并抛出不同的事件。
text 和 textarea 元素使⽤ value property 和 input 事件;
checkbox 和 radio 使⽤ checked property 和 change事件;
select 字段将 value 作为 prop 并将 change 作为事件。
注意:对于需要使⽤输⼊法的语⾔,你会发现 v-model 不会在输⼊法组合⽂字过程中得到更新。
在普通元素上:
react面试题插件和组件的区别input v-model='sth'
input v-bind:value='sth' v-on:input='sth = $event.target.value'
17、v-for为什么要加key
如果不使⽤key,Vue会使⽤⼀种最⼤限度减少动态元素并且尽可能的尝试就地修改/复⽤相同类型元素的算法。key 是为Vue中Vnode的唯⼀标识,通过这个key,我们的diff操作可以更准确、更快速。
更准确:因为带key就不是就地复⽤了,在sameNode函数 a.key === b.key 对⽐中可以避免就地复⽤的情况。所以更加准确。
更快速:利⽤key的唯⼀性⽣成map对象来获取对应节点,⽐遍历⽅式块。
18、Vue事件绑定原理
原⽣事件绑定是通过 addEventListener 绑定给真实元素的,组件事件绑定是通过Vue⾃定义的$on实现的。如果要在组件上使⽤原⽣事件,需要加.native修饰符,这样就相当于在⽗组件中把⼦组件当做普通的HTML标签,然后加上原⽣事件。
$on、$emit 是基于发布订阅模式的,维护⼀个事件中⼼,on的时候将事件按名称存在事件中⼼⾥,称之为订阅者,然后emit将对应的事件进⾏发布,去执⾏事件中⼼⾥的对应的。
19、vue-router 路由钩⼦函数是什么?执⾏顺序是什么?
路由钩⼦的执⾏流程,钩⼦函数种类有:全局守卫、路由守卫、组件守卫。
完整的导航解析流程:
1、导航被触发。
2、在失活的组件⾥调⽤ beforeRouterLeave 守卫。
3、调⽤全局的 beforeEach 守卫。
4、在重⽤的组件调⽤ beforeRouterUpdate 守卫(2.2+)。
5、在路由配置⾥⾯ beforeEnter。
6、解析异步路由组件。
7、在被激活的组件⾥调⽤ beforeRouterEnter。
8、调⽤全局的 beforeResolve 守卫(2.5+)。
9、导航被确认。
10、调⽤全局的 afterEach 钩⼦。
11、触发 DOM 更新。
12、调⽤ beforeRouterEnter 守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传⼊。
20、vue-router 动态路由是什么?有什么问题。
我们经常需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有⼀个 User组件,对于所有 ID 各不相同的⽤户,都要使⽤这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使⽤“动态路径参数”(dynamic segment)来达到这个效果: const User = { template: "
User
", };
const router = new VueRouter({
routes: [
// 动态路径参数以冒号开头
{ path: "/user/:id", component: User },
],
});
问题:vue-router 组件复⽤导致路由参数失效怎么办?
解决⽅案:
1、通过watch监听路由参数再发请求
watch:{
"router":function(){
}
}
2、⽤ :key来阻⽌复⽤
router-view :key="$route.fullPath"
21、谈⼀下对 vuex 的个⼈理解
vuex 是专门为 vue 提供的全局状态管理系统,⽤于多个组件中数据共享、数据缓存等。(⽆法持久化、内部内⼼原理是通过创造⼀个全局实例 new Vue)
主要包括以下⼏个模块:
State:定义了应⽤状态的数据结构,可以在这⾥设置默认的初始化状态。
Getter:允许组件从Store中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
Mutation:是唯⼀更改 store 中状态的⽅法,且必须是同步函数。
Action:⽤于提交 mutation,⽽不是直接变更状态,可以包含任意异步请求。
Module:允许将单⼀的 Store 拆分更多个 store 且同时保存在单⼀的状态树中。
22、Vuex 页⾯刷新数据丢失怎么解决?
需要做 vuex 数据持久化,⼀般使⽤本地储存的⽅案来保存数据,可以⾃⼰设计存储⽅案,也可以使⽤第三⽅插件。
推荐使⽤ vuex-persist (脯⾁赛斯特)插件,它是为 Vuex 持久化储存⽽⽣的⼀个插件。不需要你⼿动存取 storage,⽽是直接将状态保存⾄cookie 或者 localStorage中。
23、Vuex 为什么要分模块并且加命名空间?
模块:由于使⽤单⼀状态树,应⽤的所有状态会集中到⼀个⽐较⼤的对象。当应⽤变得⾮常复杂时,store 对象就有可能会变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有⾃⼰的 state、mutation、action、getter、甚⾄是嵌套⼦模块。
命名空间:默认情况下,模块内部的 action、mutation、getter是注册在全局命名空间的 --- 这样使得多个模块能够对同⼀ mutation 或 action 做出响应。如果希望你的模块具有更⾼的封装度和复⽤性,你可以通过添加 namespaced:true 的⽅式使其成为带命名的模块。当模块被注册后,他所有 getter、action、及 mutation 都会⾃动根据模块注册的路径调整命名。
24、使⽤过 Vue SSR 吗?说说 SSR
SSR 也就是服务端渲染,也就是将 Vue 在客户端把标签渲染成 HTML 的⼯作放在服务端完成,然后再把 html 直接返回给客户端。
优点:
SSR 有着更好的 SEO、并且⾸屏加载速度更快。
缺点:
开发条件会受限制,服务器端渲染只⽀持 beforeCreate 和 created 两个钩⼦,当我们需要⼀些外部扩展库时需要特殊处理,服务端渲染应⽤程序也需要处于 Node.js 的运⾏环境。
服务器会有更⼤的负载需求。
25、vue 中使⽤了哪些设计模式?
1、⼯⼚模式 - 传⼊参数即可创建实例
虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode。
2、单例模式 - 整个程序有且仅有⼀个实例
vuex 和 vue-router 的插件注册⽅法 install 判断如果系统存在实例就直接返回掉。
3、发布-订阅模式。(vue 事件机制)
4、观察者模式。(响应式数据原理)
5、装饰器模式(@装饰器的⽤法)
6、策略模式,策略模式指对象有某个⾏为,但是在不同的场景中,该⾏为有不同的实现⽅案 - ⽐如选项的合并策略。
26、你都做过哪些 Vue 的性能优化?
这⾥只列举针对 Vue 的性能优化,整个项⽬的性能优化是⼀个⼤⼯程。
对象层级不要过深,否则性能就会差。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论