【Vue】面试中有关于Vue的一些常问问题的解答

关于Vue的一些问题以及解答

1. 什么是MVVM?

参考文档:https://www.cnblogs.com/goloving/p/8520030.html

MVVM是Model-View-ViewModel的简写。它本质上就是 MVC 的改进版。

在MVVM架构下,View 和 Model 之间并没有直接的联系,而是通过ViewModel进行交互,Model 和 ViewModel 之间的交互是双向的, 因此 View 数据的变化会同步到Model中,而Model 数据的变化也会立即反应到View 上

Vue.js 是一个提供了 MVVM 风格的双向数据绑定的 Javascript 库,专注于View 层。它的核心是 MVVM 中的 VM,也就是 ViewModel。 ViewModel负责连接 View 和 Model,保证视图和数据的一致性,这种轻量级的架构让前端开发更加高效、便捷。

VM 是 View 与 Model 之间的桥梁,ViewModel可以实现数据和视图的完全分离。在视图模型中,绑定器在视图和数据绑定器之间进行通信。

● M(model):模型,代表真实情况的内容(一个面向对象的方法)、或表示内容(以数据为中心的方法)的数据访问层

● V(view):视图---用户界面(UI)

● Viewmodel:在vue中指vue实例对象,是一个公开公共属性和命令的抽象的view;是一个转值器,负责转换Model中的数据对象,来让对象变得更容易管理和使用。

MVVM好处:ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。

2. Vue 的生命周期?生命周期函数有哪些?

Vue å®ä¾çå½å¨æ

每个钩子函数能做什么:

https://blog.csdn.net/qq_15058285/article/details/89358885https://www.cnblogs.com/PrayLs/p/10372809.html

 Vue的生命周期与钩子函数:

1、 new Vue() 新建了一个新的 Vue 的实例对象,此时就会进入组件的创建过程

2、 Init Events & Lifecycle 初始化组件的事件和生命周期函数,当执行完这一步后,组件的生命周期函数就全部初始化好了,等待着依次去调用。

3、 beforeCreate 是组件的第一个生命周期函数,此时当前 Vue 实例的 data,el(页面DOM结构),methods,computed都还未初始化,所以此阶段什么都做不了。很少使用该生命周期函数。

钩子函数的作用:可以做loading。这个时候的vue实例还什么都没有,但是$route对象是存在的,可以根据路由信息进行重定向之类的操作。

4、 init injections & reactivity,这个阶段中正在初始化 data 和 methods 中的数据和方法【导入依赖项】

5、created 这个是组件创建阶段的第二个生命周期函数,此时组件的 data 和 methods 已经初始化完毕了。data和methods已经可以使用了, 但是页面(el)还没有渲染出来。

钩子函数的作用:在这个生命周期函数中,我们也会经常发起Ajax请求。

6、编译模版结构,把data上的数据拿到,并且解析执行模版结构中的指令。当所有的指令解析完毕,那么模版页面就被渲染到内存中了。当模版编译完成,我们的模版页面还没有挂载到页面上,只是存在于内存中,用户看不到页面。

6.1 判断,初始化 Vue 实例对象的时候是否含有 el 这个属性,如果有 el 属性,再判断是否有 template 属性,如果存在 el 且 指定了 template属性,就编译 template 所对应的模版结构。

6.2 判断,有 el 属性,但是没有指定 template 即编译 el 所对应的的HTML结构到模版.

6.3 判断,没有 el 属性,也没有 template 属性。Vue 实例创建完后等待手动指定el,vm.$mount(el),如未指定,则结束。

7、 beforeMount 当模版在内存中编译完成,会立即执行实例创建阶段的第三个生命周期函数,即 beforeMount,此时内存中的模版结构还没有真正地渲染到页面上去,此时页面上也看不到真实的数据。此时用户看到的只是一个模版的页面而已。

8、Create vm.$el and replace "el" with it 这一步,正在把内存中渲染好的模版结构,替换到页面上去。

9、 mounted 是组件创建阶段最后一个生命周期函数,此时,页面已经真正地渲染好了,用户已经可以看到真实的页面数据了。当这个生命周期函数执行完,组件就离开了创建阶段,进入到了运行中的阶段。

钩子函数的作用:如果大家用到了一些第三方的UI插件,而且这些插件需要被初始化,必须在mounted中来初始化插件,因为此时真实的页面才被渲染好。此时DOM元素已经渲染完成了,依赖于DOM的代码就放在这里执行,比如监听DOM事件。

10、组件运行中的生命周期函数有两个,一个是 beforeUpdate (组件更新前)一个是 updated(组件更新后),触发的条件是data数据发生了改变。组件运行中的生命周期函数会根据data数据的变化有选择性地触发0次或n次。

当数据变化,页面更新时,首先要拿到最新的 data 数据,然后根据最新的 data 数据在内存中重新渲染一颗新的 DOM 树,把旧的页面移除,同时把新的DOM树渲染出来。

当执行beforeUpdate 运行中的生命周期函数的时候,内存中的数据是最新的,但是页面上呈现的数据还是旧的。此时可以修改vm实例中的data.

Virtual DOM re-render and patch 正在根据最新的 data 数据,重新渲染内存中的模版结构,并把渲染好的数据结构,替换到页面上。

当执行updated的时候,此时 data 数据是最新的,同时页面上的数据也是最新的。

11、beforeDestroy,当执行beforeDestroy的时候,组件即将被销毁,但是还没有真正地被销毁,此时组件还是正常可用的。data、methods等数据或方法依然可以被正常访问。

作用:销毁之前还可以访问到DOM结构 ,以及相关的数据(data)。在这个生命周期函数中我们可以将绑定的事件进行移除。

解除监听器、绑定的事件、移除子控件。

12、destroyed,组件已经完成了销毁,此时组件的data和methods都不可用了。

 

3. Vue响应式原理、双向数据绑定的原理?

参考文档:https://segmentfault.com/a/1190000015427628

数据双向绑定

所谓的双向绑定,就是view的变化能反映到ViewModel上,ViewModel的变化能同步到view上。

数据驱动

Vue.js 一个核心思想是数据驱动。所谓数据驱动是指视图是由数据驱动生成的,对视图的修改,不会直接操作 DOM,而是通过修改数据。相比传统的前端开发,如使用 jQuery 等前端库直接修改 DOM,大大简化了代码量,特别是当交互复杂的时候,只关心数据的修改会让代码的逻辑变的非常清晰,因为 DOM 变成了数据的映射,我们所有的逻辑都是对数据的修改,而不用碰触 DOM,这样的代码非常利于维护。

vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的settergetter方法,在数据变动时发布消息给订阅者,触发相应监听回调。

Vue 的响应式,核心机制是 观察者模式

大致上是使用数据劫持和订阅发布实现双向绑定。通过实例化一个Vue对象的时候,对其数据属性遍历,通过Object.defineProperty()给数据对象添加setter  getter,并对模板做编译生成指令对象,每个指令对象绑定一个watcher对象,然后对数据赋值的时候就会触发setter,这时候相应的watcher对其再次求值,如果值确实发生变化了,就会通知相应的指令,调用指令的update方法,由于指令是对DOM的封装,这时候会调用DOM的原生方法对DOM做更新,这就实现了数据驱动DOM的变化。同时vue还会对DOM做事件监听,如果DOM发生变化,vue监听到,就会修改相应的data。

实现代码与原理:https://segmentfault.com/a/1190000006599500?utm_source=tag-newest

面试的时原理解释,必要时辅以伪代码进行说明:

核心:Vue 中双向数据绑定的原理的核心机制是观察者模式和发布订阅者模式。

1.观察者模式就是对 VM 实例中的 data 属性中的数据进行劫持并且监听数据的变化,具体指修改与获取,这里实现观察者模式利用了 Object.defineProperty 方法对 data 属性的数据进行了劫持。

2.发布和订阅模式:发布和订阅模式就是把观察者模式中劫持的数据进行统一的管理和状态更新。VM 实例 data 属性中的每一个数据都会生成一个 Dep 就是订阅器,该订阅器负责订阅者的管理。

订阅器有两个功能,第一个是添加新的订阅者,用一个数据来维护。第二是把最新变动的数据通知给每一个订阅该数据的订阅者,让订阅者进行更新。

订阅者:阅者指的是与该数据绑定的页面中的DOM元素或者,{{ 变量 }}模板中的变量,也就是需要与该数据同步的对象。订阅者由解析器生成,生成的同时主动添加到对应的订阅器中去。并且有一个 update 方法,来更新视图数据。

3. 解析器,解析器对VM实例中的 el 属性对应的模板信息进行逐个解析,主要负责生成订阅者和进行相应的属性绑定。

å¾çæè¿°

对数组的监控:https://segmentfault.com/a/1190000015483195?utm_source=tag-newest

Object.defineProperty 方法对数组进行监控的时候,实际上监控的是数组的地址,而不是数组值的变化,如果对数组元素进行增删,由于数组地址没有发生变化,实际上data属性被劫持的set方法不会被触发。解决方法:覆写数组对象中的方法或者使用Proxy进行拦截。

4. Vue组件化的理解、组件间通信?

参考文章:https://www.cnblogs.com/amunamuna/p/8872979.html

Vue组件就是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el这样根实例特有的选项。

父组件向子组件传值

在 Vue 中,父组件可以使用属性绑定的方式  (v-bind)

向子组件传递数据。

父组件通过向在子组件的标签上使用 v-bind 即 <子组件标签名 :logo="logoMsg"></子组件标签名>向子组件传递数据

子组件通过在实例中使用 props 属性(一个数组):['logo'] 来接收属性值。

总结一下:

  • 子组件在props中创建一个属性,用以接收父组件传过来的值
  • 父组件中注册子组件
  • 在子组件标签中添加子组件props中创建的属性
  • 把需要传给子组件的值赋给该属性,通过属性传值

子组件向父组件传值

子组件主要通过事件机制传递数据给父组件。

例如在子组件的一个按钮中绑定一个事件<button v-on:click="sendParentMsg">传值给父组件</button>

并在子组件的methods方法中定义

methods:{
    sendParentMsg(){
        this.$emit('parentEvent','msgFromChild')
    }
}

子组件在响应该点击事件的函数中使用$emit来触发一个自定义事件parentEvent,这个事件应该在父组件中定义好,并可以传递多个参数,例如'msgFromChild' 给父组件。

在父组件中的子标签中监听该自定义事件并添加一个响应该事件的处理方法。

总结一下:

  • 子组件中需要以某种方式例如点击事件的方法来触发一个自定义事件
  • 将需要传的值作为$emit的第二个参数,该值将作为实参传给响应自定义事件的方法
  • 在父组件中注册子组件并在子组件标签上绑定对自定义事件的监听

兄弟组件之间传值

1.子组件传值给父组件,父组件再传值给兄弟组件。

2.非父子组件之间传值,需要定义个公共的公共实例文件bus.js,作为中间仓库来传值,不然路由组件之间达不到传值的效果。

 实例参考:https://blog.csdn.net/lander_xiong/article/details/79018737

状态管理工具

为了便于开发,Vue 推出了一个状态管理工具 Vuex,可以很方便实现组件之间的参数传递。

1.state

vuex中的数据源,我们需要保存的数据就保存在这里,可以在页面通过 this.$store.state来获取我们定义的数据。

2.getters

Getter相当于vue中的computed计算属性,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算,这里我们可以通过定义vuex的Getter来获取,Getters 可以用于监听、state中的值的变化,返回计算后的结果。

3.Mutations

数据我们在页面是获取到了,但是如果我们需要修改count值怎么办?如果需要修改store中的值唯一的方法就是提交mutation来修改。

5.v-bind、v-on、v-model

v- 前缀作为一种视觉提示,用来识别模板中 Vue 特定的特性。当你在使用 Vue.js 为现有标签添加动态行为 (dynamic behavior) 时,v- 前缀很有帮助,然而,对于一些频繁用到的指令来说,就会感到使用繁琐。同时,在构建由 Vue 管理所有模板的单页面应用程序 (SPA - single page application)时,v- 前缀也变得没那么重要了。因此,Vue 为 v-bind 和 v-on 这两个最常用的指令,提供了特定简写:

v-bind 缩写

v-bind指令:用于给html标签设置属性。

<!-- 完整语法 -->
<a v-bind:href="url">...</a>

<!-- 缩写 -->
<a :href="url">...</a>

v-on 缩写

v-on指令:用来绑定事件的。

<!-- 完整语法 -->
<a v-on:click="doSomething">...</a>

<!-- 缩写 -->
<a @click="doSomething">...</a>

v-on中的事件修饰符:

(1).stop  :阻止事件冒泡

<div @click.stop="test">

(2).prevent : .prevent修饰符,其作用就是阻止组件本来应该发生的事件,转而去执行自己定义的事件

<a href="http://xxx.com" @click.prevent="test">跳转</a>

阻止a链接的跳转事件,转而执行 test 事件。

(3).caption

使用.capture修饰符时,网页就会按照捕获的方式触发函数,也就是从外向内执行,默认是冒泡

(4).once

加上此修饰符之后相应的函数只能触发一次,无论你点击多少下,函数就只触发一次。

(5).self

当前元素自身时触发处理函数时才会触发函数,原理:是根据event.target确定是否当前元素本身,来决定是否触发的事件/函数

v-model 

v-model是一个指令,限制在<input>、<select>、<textarea>、components中使用,取代 input 监听 change 事件。它是一个语法糖,功能是监听 change 事件的同时绑定表单元素的 value 属性。它能轻松实现表单输入和应用状态之间的双向绑定(改变其中一个值,另一个值也一起同步更新)。

6. watch与computed属性?

computed和watch属性:https://blog.csdn.net/joseydon/article/details/81157867

computed属性实现原理:https://blog.csdn.net/w18478272407/article/details/85079746

computed:对变量有复杂逻辑操作的模版使用计算属性,computed 属性会基于它所依赖的数据进行缓存,只有在它所依赖的数据发生变化时,才会重新取值

watch:监听属性变化,属性发生变化才执行监听的函数。

7. v-show 和 v-if 的区别

共同点:在 Vue 中,v-show 和 v-if 都是控制元素显示和隐藏的属性。v-show、v-if = true 元素显示,v-show、v-if = false 元素隐藏。

不同点:

v-show 是直接控制元素的 display 属性,v-show = false的时候,元素的 display:none,无论为何值,v-show控制的元素都会编译到模板中。v-show本质上是在控制元素的css属性。

v-if 是动态的向DOM树内添加或者删除DOM元素。如果v-if初始值为false,该元素则不会编译到模板里。

总结: 

v-show 有更高的首次渲染开销,而 v-if 的首次渲染开销要小的多;

v-if 有更高的切换开销,v-show 切换开销小,如果元素在运行中需要经常切换显示和隐藏使用v-show开销比较小。

8. Vue-Router 原理

更新视图但不重新请求页面。

https://juejin.im/post/5bc6eb875188255c9c755df2

9. Vue虚拟DOM和diff算法

只进行同层比较

https://www.cnblogs.com/gxp69/p/11325381.html

https://www.cnblogs.com/wind-lanyan/p/9061684.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值