# Vue
# 1. vue数据劫持(中级)
数据劫持: vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()
来劫持各个属性的setter
,getter
,在数据变动时发布消息给订阅者,触发相应的监听回调。
# 2. 阐述一下你所理解的MVVM响应式原理(中级)
vue 是采用数据劫持配合发布者-订阅者的模式的方式,通过Object.defineProperty()
来劫持各个属性的 getter 和 setter,在数据变动时,发布消息给依赖收集器( dep 中的subs),去通知(notify)观察者,做出对应的回调函数,去更新视图。
MVVM 作为绑定的入口,整合 Observer,Compile 和 Watcher 三者,通过 Observer 来监听 model 数据变化,通过 Compile 来解析编译模板指令,最终利用Watcher 搭起 Observer,Compile 之间的通信桥路,达到数据变化=>视图更新;视图交互变化=>数据 model 变更的双向绑定效果。
# 3. 说说vue的生命周期(中级)
beforeCreate
- 创建之前,此时还没有 data 和 Method。
Created
创建完成,此时 data 和 Method 可以使用了。
在 Created 之后 beforeMount 之前如果没有el选项的话那么此时生命周期结束,停止编译,如果有则继续。
beforeMount
- 在渲染之前。
mounted
- 页面已经渲染完成,并且
vm
实例中已经添加完$el
了,已经替换掉那些 DOM 元素了(双括号中的变量),这个时候可以操作 DOM 了(但是是获取不了元素的高度等属性的,如果想要获取,需要使用nextTick()
)。
- 页面已经渲染完成,并且
beforeUpdate
data
改变后,对应的组件重新渲染之前。
updated
data
改变后,对应的组件重新渲染完成。
beforeDestory
- 在实例销毁之前,此时实例仍然可以使用。
destoryed
- 实例销毁后。
# 4. vue 中父子组件的生命周期(中级)
父子组件的生命周期是一个嵌套的过程。
渲染的过程。
- 父
beforeCreate
->父created
->父beforeMount
->子beforeCreate
->子created
->子beforeMount
->子mounted
->父mounted
- 父
子组件更新过程。
- 父
beforeUpdate
->子beforeUpdate
->子updated
->父updated
- 父
父组件更新过程。
- 父
beforeUpdate
->父updated
- 父
销毁过程。
- 父
beforeDestroy
->子beforeDestroy
->子destroyed
->父destroyed
- 父
# 5. Vue 中的nextTick
(中级)
- nextTick
- 解释。
nextTick
:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。
- 应用。
- 想要在 Vue 生命周期函数中的
created()
操作 DOM 可以使用Vue.nextTick()
回调函数。 - 在数据改变后要执行的操作,而这个操作需要等数据改变后而改变 DOM 结构的时候才进行操作,需要用到
nextTick
。
- 想要在 Vue 生命周期函数中的
- 解释。
# 6. computed 和 watch 的区别(中级)
computed
- 计算属性,依赖其他属性,当其他属性改变的时候下一次获取computed值时也会改变,
computed
的值会有缓存。
- 计算属性,依赖其他属性,当其他属性改变的时候下一次获取computed值时也会改变,
watch
- 类似于数据改变后的回调。
- 如果想深度监听的话,后面加一个
deep:true
。 - 如果想监听完立马运行的话,后面加一个
immediate:true
。
# 7. Vue 优化方式(中级)
v-if 和v-show。
使用
Object.freeze()
方式冻结data中的属性,从而阻止数据劫持。组件销毁的时候会断开所有与实例联系,但是除了
addEventListener
,所以当一个组件销毁的时候需要手动去removeEventListener
图片懒加载。
路由懒加载。
为减少重新渲染和创建 dom 节点的时间,采用虚拟 dom。
# 8. Vue-router 的模式(中级)
- hash模式。
- 利用 onhashchange 事件实现前端路由,利用 url 中的 hash 来模拟一个 hash,以保证 url 改变时,页面不会重新加载。
- history模式。
- 利用 pushstate 和 replacestate 来将 url 替换但不刷新,但是有一个致命点就是,一旦刷新的话,就会可能404,因为没有当前的真正路径,要想解决这一问题需要后端配合,将不存在的路径重定向到入口文件。
# 9. MVC 与 MVVM 有什么区别(中级)
MVC
Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。
View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。
Controller(控制器)是应用程序中
处理用户交互的部分
- 通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
# 10. diff 算法(中级)
diff 算法是指对新旧虚拟节点进行对比,并返回一个 patch 对象,用来存储两个节点不同的地方,最后利用 patch 记录的消息局部更新 DOM。
# 11. 虚拟 DOM 的优缺点(中级)
缺点
- 首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,会比 innerHTML 插入慢。
优点
减少了 DOM 操作,减少了回流与重绘。
保证性能的下限,虽说性能不是最佳,但是它具备局部更新的能力,所以大部分时候还是比正常的 DOM 性能高很多的。
# 12. Vue 的 Key 的作用(中级)
key
- key 主要用在虚拟 Dom 算法中,每个虚拟节点 VNode 有一个唯一标识 Key,通过对比新旧节点的 key 来判断节点是否改变,用 key 就可以大大提高渲染效率,这个 key 类似于缓存中的 etag。
# 13. Vue 组件之间的通信方式(中级)
子组件设置props + 父组件设置
v-bind:
/:
。- 父传子
子组件的$emit + 父组件设置
v-on
/@
。- 子传父
任意组件通信,新建一个空的全局Vue对象,利用 e m i t 发 送 , emit发送, emit发送,on接收。
传说中的$bus
任意组件
Vue.prototype.Event=new Vue(); Event.$emit(事件名,数据); Event.$on(事件名,data => {});
Vuex
里面的属性有:
state
- 存储数据的。
- 获取数据最好推荐使用 getters。
- 硬要使用的话可以用 MapState, 先引用,放在 compute 中
...mapState(['方法名','方法名'])
。
getters
- 获取数据的。
- this.$store.getters.xxx。
- 也可使用mapGetters 先引用,放在compute中,
...mapGetters(['方法名','方法名'])
。
mutations
- 同步操作数据的。
- this.$store.commit(“方法名”,数据)。
- 也可使用mapMutations ,使用方法和以上一样。
actions
- 异步操作数据的。
- this.$store.dispatch(“方法名”,数据)。
- 也可使用mapActions ,使用方法和以上一样。
modules
- 板块,里面可以放多个vuex。
父组件通过
v-bind:
/:
传值,子组件通过this.$attrs
获取。父传子
当子组件没有设置props的时候可以使用
this.$attrs
获取到的是一个对象(所有父组件传过来的集合)
祖先组件使用provide提供数据,子孙组件通过inject注入数据。
p a r e n t / parent/ parent/children。
refs—$ref。
还有一个,这个网上没有,我自己认为的,我觉得挺对的,slot-scope,本身父组件使用slot插槽是无法获取子组件的数据的,但是使用了 slot-scope 就可以获取到子组件的数据(拥有了子组件的作用域)。
# 14. Vue router有哪几种钩子函数?(中级)
- beforeEach
- 参数有:
- to(Route路由对象)
- from(Route路由对象)
- next(function函数) 一定要调用才能进行下一步
- 参数有:
- afterEach
- beforeRouterLeave
# 15. Vue3 的设计目标
结论:大体上可以概括为:更小、更快、更友好。
在 vue3 之前,我们大致会面临以下几个问题:
1、随着功能的增长,复杂组件的代码变得越来越难以维护
2、缺少一种比较干净的在多个组件之间提取和复用逻辑的机制
3、类型推断不是很友好
4、bundle的时间太久
在 Vue3 中,加入
TypeScript
支持,提升了 API 设计的一致性、提高了自身的可维护性、开放更多底层功能。
分析:
更小:
1、Vue3 移除一些不常用的 API.
2、引入 tree-shaking,可以将无用模块“剪辑”,仅打包需要的,使打包的整体体积变小了。
更快:
主要体现在编译方面:
1、diff 算法优化
2、静态提升
3、事件监听缓存
4、SSR 优化
更友好
1、vue3 在兼顾 vue2 的
options API
的同时还推出了composition API
,大大增加了代码的逻辑组织和代码复用能力。2、基于
TypeScript
编写,可以享受自动的类型定义提示。
# 16. Vue3 做了哪些优化
大体上可分为三个方面:源码、性能、语法 API.
源码:
1、源码管理
通过
monorepo
方式对源码进行维护,根据功能,将不同的模块进行拆分,放到对应的package
目录下面的子目录中。这样使得模块拆分更细化,职责划分更明确,模块之间的依赖关系也更加明确,开发人员也更容易阅读、理解和更改所有模块源码,提高代码的可维护性。2、TypeScript
Vue3 是基于
TypeScript
编写的,提供了更好的类型检查,能支持复杂的类型推导。性能:
主要通过体积优化、编译优化、数据劫持优化。
在 vue2 中,数据劫持是通过 Object.defineProperty,这个 API 有一些缺陷,并不能检测对象属性的添加和删除。在面对嵌套层级比较深的情况下,存在性能问题。
相比之下,vue3 是通过 proxy 监听整个对象,那么对于删除还是监听当然也能监听到。
同时 Proxy 并不能监听到内部深层次的对象变化,而 Vue3 的处理方式是在 getter 中去递归响应式,这样的好处是真正访问到的内部对象才会变成响应式,而不是无脑递归。
语法 API:
Vue3 中提供了
Composition API
,优化逻辑组织和逻辑复用。在 vue2 中,我们是通过mixin实现功能混合,如果多个 mixin 混合,会存在两个非常明显的问题:命名冲突和数据来源不清晰。
而通过
Composition API
这种形式,可以将一些复用的代码抽离出来作为一个函数,只要的使用的地方直接进行调用即可。
# 17. Vue3 性能提升主要是通过哪几方面体现的
编译阶段
1、diff 算法优化
vue3 在 diff 算法中相比 vue2 增加了静态标记
关于这个静态标记,其作用是在会发生变化的地方添加一个flag 标记,下次发生变化的时候直接找该地方进行比较。
2、静态提升
Vue3 中对不参与更新的元素,会做静态提升,只会被创建一次,在渲染时直接复用。
这样就免去了重复的创建节点,大型应用会受益于这个改动,免去了重复的创建操作,优化了运行时候的内存占用。
3、事件监听缓存
默认情况下绑定事件行为会被视为动态绑定,所以每次都会去追踪它的变化,开启了缓存后,将失去静态标记。也就是说下次 diff 算法的时候直接使用。
4、SSR 优化
当静态内容大到一定量级时候,会用
createStaticVNode
方法在客户端去生成一个static node,这些静态 node,会被直接 innerHtml,就不需要创建对象,然后根据对象渲染。源码体积
相比 Vue2,Vue3 整体体积变小了,除了移除一些不常用的 API,再重要的是
Tree shanking
.任何一个函数,如 ref、reavtived、computed 等,仅仅在用到的时候才打包,没用到的模块都被摇掉,打包的整体体积变小。
响应式系统
vue2 中采用
defineProperty
来劫持整个对象,然后进行深度遍历所有属性,给每个属性添加 getter 和 setter,实现响应式。vue3 采用
proxy
重写了响应式系统,因为 proxy 可以对整个对象进行监听,所以不需要深度遍历。
# 18. Vue3 所采用的 Composition Api 与 Vue2 使用的 Options Api 有什么不同?
Options API
Options API,即大家常说的选项 API,即以 vue 为后缀的文件,通过定义 methods,computed,watch,data 等属性与方法,共同处理页面逻辑。
当组件变得复杂,导致对应属性的列表也会增长,这可能会导致组件难以阅读和理解。
Composition Api
在 Vue3 Composition API 中,组件根据逻辑功能来组织的,一个功能所定义的所有 API 会放在一起(更加的高内聚,低耦合)。
即使项目很大,功能很多,我们都能快速的定位到这个功能所用到的所有 API。
对比
1、逻辑组织
Options API 中,假设一个组件是一个大型组件,其内部有很多处理逻辑关注点。选项的分离掩盖了潜在的逻辑问题。此外,在处理单个逻辑关注点时,我们必须不断地跳转相关代码的选项块。
Composition API 中,逻辑关注点相关的代码全都放在一个函数里,这样当需要修改一个功能时,就不再需要在文件中跳来跳去。
2、逻辑复用
在 Vue2 中,我们是用过 mixin 去复用相同的逻辑,使用单个 mixin 似乎问题不大,但是当我们一个组件混入大量不同的 mixins 的时候,会存在两个非常明显的问题:命名冲突、数据来源不清晰。
Composition API 中,可将逻辑抽离出去,整个数据来源清晰,即使去编写更多的 hook 函数,也不会出现命名冲突的问题。
总结
1、在逻辑组织和逻辑复用方面,
Composition API
是优于Options API
。2、因为
Composition API
几乎是函数,会有更好的类型推断。3、
Composition API
对tree-shaking
友好,代码也更容易压缩。4、
Composition API
中见不到this
的使用,减少了 this 指向不明的情况。5、如果是小型组件,可以继续使用
Options API
,也是十分友好的。