1.谈谈对Vue的理解

渐进式JavaScript框架,核心库+插件 动态创建用户界面(异步获取后台数据),数据驱动视图,只关心数据的变更,DOM变成了数据的映射。
MVVM模式,代码简洁体积小,运行效率高,只关注UI,可以轻松引入Vue插件和第三方库进行开发

2.MVVM

Model-View-ViewModel Model表示数据模型层,View表示视图层,ViewModel是View和Model层的桥梁,数据绑定到ViewModel自动渲染页面,视图变化通知ViewModel层更新数据,核心点在于binder,双向绑定。

3.Vue如何实现响应式数据的

vue2是通过Object.definProperty重新定义data中所有的属性,通过Object.defineProperty 的getter和setter对数据的获取和设置增加一层拦截,进行依赖收集,拦截属性的更新操作,进行通知(更新视图)
原理:”数据劫持” + 订阅发布模式实现
132184689-57b310ea1804f_articlex.png
Observer:劫持所有属性,遍历属性,调用defineReactive方法,为每个属性设置setter和getter,defineReactive内部维护一个Dep实例,Dep中包含了订阅者列表,添加订阅和通知的方法。每次属性有更新时会调用Dep.notify()
Watcher: Watcher订阅者作为Obersver和Compile之间通信的桥梁,主要做的事情:
1.自身实例化时往属性订阅器(dep)里添加自己
2.属性变动时,会调用dep.notify(),调用watcher的update方法,并触发Compile中绑定的回调
Compile:解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,初始化Watcher实例,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

4.Vue如何检测数组变化的

通过劫持数组上个别方法进行重写,具体重写的有:push、pop、shift、unshift、sort、reverse、splice
不是粗暴的重写了Array.prototype上的方法,而是通过原型链继承和函数劫持进行移花接木,并且只监听调用了defineReactive函数时传进来的数组。
具体实现思路:利用Object.create(Array.prototype)生成新的数组对象,该对象的proto指向Array.prototype,并在对象上创建push pop shift unshift reverse splice方法,利用函数劫持,在函数内部通过Array.prototype.push.call的方式调用原生的push方法,同时执行自己需要的代码(例如视图更新),最后将需要绑定的数组的proto由指向Array.prototype改向拥有重写方法的新数组对象。

5.Vue事件绑定原理

对于原生DOM,通过addEventListener实现绑定
对于组件自定义事件,通过$on绑定,组件内部通过$emit触发事件

6.v-model的实现原理及如何自定义v-model

v-model可以看作是 :value + input事件的语法糖,在自定义组件上使用v-model,需要在组件内部props定义value,在value值变化时通过$emit触发事件

7.vue为何采用异步渲染

vue是组件级更新,如果不采用异步渲染,每次更新数据都会对当前组件重新渲染,开销太大,因此,只要侦听到数据变化,vue将开启一个队列,缓冲同一事件循环中发生的所有数据变更。如果同一个watcher被多次触发,只会被推入到队列中一次。
原理:
->调用dep.notofy()通知watcher进行更新操作
->subs[i].update 依次调用watcher的update
->将watcher去重后放到queueWatcher队列中
->nextTick异步清空watcher队列

8.生命周期钩子

  1. beforCreate

data observer event/watcher事件配置之前被调用

  1. created

实例已完成data observer watcher/event等配置,挂载阶段未开始
3.beforMount
挂载开始之前被调用
4.mounted
实例被挂载后调用,el被新创建的vm.$el替换,mounted不保证所有子组件都被挂载,如果希望整个视图渲染完毕,则可以在mounted内部使用vm.$nextTick
5.beforUpdate
数据更新前调用,适合访问现有dom,比如手动移除事件监听器等
6.updated
避免在此期间更改状态,引起死循环,最好通过watch或计算属性取代,updated不保证所有子组件都被重绘,如果希望整个视图重绘完毕,可以在updated内部调用vm.$nextTick
7.beforDestroy

8.
destroyed**
实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
lifecycle.png

9. 父子组件生命周期调用顺序

渲染顺序:先父后子,完成顺序先子后父
更新顺序:先父后子,完成顺序先子后父
销毁顺序:先父后子,完成顺序先子后父

10. 组件通信

一:props/$emit
父组件->子组件:props传值
子组件->父组件:子组件$emit一个事件,父组件v-on绑定事件

二:eventBus
中央事件总线,main中初始化一个新的vue实例,methods中预先定义函数设置自定义事件,在需要监听的组件mounted钩子中eventBus.$on监听事件获取传值。

三:provider/inject
祖先组件中定义provider,后代组件中注入inject直接获取元素

四:ref/children/parent
vm.$refs.ref获取的子组件实例,可以直接拿实例上的属性值

五:$attrs
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind=”$attrs” 传入内部组件——在创建高级别的组件时非常有用。

六:vuex

七:父组件向子组件传递函数
_

11. .sync修饰符作用

某些情况下需要对子组件props属性做双向绑定,即子组件更改props后,$emit一个自定义事件,父组件$on监听获取同步更新的值,为了方便起见vue为这种模式提供了语法糖即.sync修饰符。

12.vuex工作原理

states统一状态管理
mutations 改变states状态 store.commit mutation
actions 可以包含异步操作,store.dispatch actions -> action commit mutation action并不直接更改state状态,通过提交mutation交给mutation处理

13. computed/watch/method

computed:如果被依赖项没有变化,则computed会执行缓存数组。只有被依赖数据改变时才会重新计算
watch: 更适用于数据改变时执行异步操作,如果在数据改变时需要做一些事情,可以使用watch
method: 每次调用都会执行函数,开销较大

14.v-if v-show的区别

v-if 初始渲染开销小,切换开销大,条件不成立不会渲染当前指令所在的DOM
v-show 初始渲染开销大,切换开销小,频繁切换选show 否则选if,v-show只是切换当前DOM的显示与隐藏(通过display:none来控制)

15. v-for v-if优先级

v-for优先级比v-if要高,因此同时使用会导致每次循环都调用v-if,内存开销较大,因此如果需要过滤部分列表数据,可以通过computed事先准备好数据,v-for渲染

16.组件渲染及更新过程

渲染组件时,通过vue.extend()构建子组件的构造函数,实例化,最终通过手动调用mount方法挂载。
更新组件时,会进行patchVnode流程,核心是diff算法。

17.组件中的data为什么必须是函数

为了保持每个组件实例数据独立性。

18.vue中相同逻辑如何抽离

通过vue.mixin混入

19.keep-alive理解

可以实现组件状态缓存,包含三个props和两个声明周期函数
includes:缓存白名单
excludes:缓存黑名单
max:最大缓存数量

声明周期函数:
activated:组件激活时触发
deactived:组件不激活时触发

**
_