Vue的生命周期
Vue 实例有⼀个完整的⽣命周期,也就是从开始创建、初始化数据、编译模版、挂载Dom -> 渲染、更新 -> 渲染、卸载 等⼀系列过程,称这是Vue的⽣命周期。
-
beforeCreate(创建前) :数据观测和初始化事件还未开始,此时 data 的响应式追踪、event/watcher 都还没有被设置,也就是说不能访问到data、computed、watch、methods上的方法和数据。
-
created(创建后) :实例创建完成,实例上配置的 options 包括 data、computed、watch、methods 等都配置完成,但是此时渲染得节点还未挂载到 DOM,所以不能访问到
$el
属性。 -
beforeMount(挂载前) :在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。此时还没有挂载html到页面上。
-
mounted(挂载后) :在el被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html 页面中。此过程中进行ajax交互。
-
beforeUpdate(更新前) :响应式数据更新时调用,此时虽然响应式数据更新了,但是对应的真实 DOM 还没有被渲染。
-
updated(更新后) :在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。此时 DOM 已经根据响应式数据的变化更新了。调用时,组件 DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
-
beforeDestroy(销毁前) :实例销毁之前调用。这一步,实例仍然完全可用,
this
仍能获取到实例。 -
destroyed(销毁后) :实例销毁后调用,调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务端渲染期间不被调用。
另外还有 keep-alive
独有的生命周期,分别为 activated
和 deactivated
。用 keep-alive
包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated
钩子函数,命中缓存渲染后会执行 activated
钩子函数。
Vue的组件之间的通信方式有哪些
父子组件通信
-
prop
-
event
-
style和class
-
attribute
-
natvie修饰符
-
$listeners
-
sync修饰符
-
ref
跨组件通信
-
Provide和Inject
-
router
-
vuex
-
store模式
-
eventbus
详情看官网文档 v2.cn.vuejs.org/v2/api
v-if和v-show的区别
-
v-if
是动态的添加或者删除DOM元素,v-show是通过设置DOM元素的display样式属性控制 -
v-if
有更高的切换消耗,v-show有更高的初始渲染消耗;
computed和methods有什么区别
-
在使用时,
computed
当做属性使用,而methods
则当做方法调用 -
computed
可以具有getter和setter,因此可以赋值,而methods
不行 -
computed
无法接收多个参数,而methods
可以 -
computed
具有缓存,而methods
没有
watch与computed的区别是什么
-
computed 计算属性 : 依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。
-
watch 侦听器 : 更多的是观察的作用,无缓存性,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作。
运用场景:
-
当需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时都要重新计算。
-
当需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许执行异步操作 ( 访问一个 API ),限制执行该操作的频率,并在得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
Vue组件的data为什么必须是函数
组件中的 data
写成一个函数,数据以函数返回值形式定义。这样每复用一次组件,就会返回一份新的data
,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份 data
,就会造成一个变了全都会变的结果。
nextTick的作用是什么?他的实现原理是什么?
作用:vue
更新 DOM
是异步更新的,数据变化,DOM
的更新不会马上完成,nextTick
的回调是在下次 DOM
更新循环结束之后执行的延迟回调。
实现原理:
-
nextTick
主要使用了宏任务和微任务。根据执行环境分别尝试采用 -
Promise
:可以将函数延迟到当前函数调用栈最末端 -
MutationObserver
:是H5
新加的一个功能,其功能是监听DOM
节点的变动,在所有DOM
变动完成后,执行回调函数 -
setImmediate
:用于中断长时间运行的操作,并在浏览器完成其他操作(如事件和显示更新)后立即运行回调函数 -
如果以上都不行则采用
setTimeout
把函数延迟到 DOM 更新之后再使用
原因是宏任务消耗大于微任务,优先使用微任务,最后使用消耗最大的宏任务。
Vue2.x双向数据绑定原理
Vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
Proxy 相比 defineProperty 的优势在哪里
原因在于 Object.defineProperty
本身存在的一些问题:
-
Object.defineProperty
只能劫持对象属性的getter
和setter
方法。 -
Object.definedProperty
不支持数组(可以监听数组,不过数组方法无法监听自己重写),更准确的说是不支持数组的各种API
(所以Vue
重写了数组方法)
而相比 Object.defineProperty
,Proxy
的优点在于:
-
Proxy
是直接代理劫持整个对象。 -
Proxy
可以直接监听对象和数组的变化,并且有多达13
种拦截方法。
目前,Object.definedProperty
唯一比 Proxy
好的一点就是兼容性,不过 Proxy
新标准也受到浏览器厂商重点持续的性能优化当中。
Vue中的Key 的作用是什么
key
的作用主要是为了高效的更新虚拟 DOM
。另外 vue
中在使用相同标签名元素的过渡切换时,也会使用到 key
属性,其目的也是为了让 vue
可以区分它们,否则 vue
只会替换其内部属性而不会触发过渡效果。
Vue2.x的diff算法的理解
Diff算法实现的是最小量更新虚拟DOM。 这句话虽然简短,但是涉及到了两个核心要素:
-
虚拟DOM、最小量更新。 虚拟DOM指的就是将真实的DOM树构造为js对象的形式,从而解决浏览器操作真实DOM的性能问题。 Diff的用途就是在新老虚拟DOM之间找到最小更新的部分,从而将该部分对应的DOM进行更新。
Vuex中action和mutation的区别
-
Mutation专注于修改State,理论上是修改State的唯一途径;Action业务代码、异步请求。
-
Mutation:必须同步执行;Action:可以异步,但不能直接操作State。
-
在视图更新时,先触发actions,actions再触发mutation
Vue3.x的效率提升主要是哪个方面
静态提升
预字符串化
当编译器遇到大量连续的静态内容,会直接将其编译为一个普通字符串节点
缓存事件处理函数
Block Tree
vue2在对比新旧树的时候,并不知道哪些节点是静态的,哪些是动态的,因此只能一层一层比较,这就浪费了大部分时间在比对静态节点上
vue3只对比动态的节点
PatchFlag
vue2在对比每一个节点时,并不知道这个节点哪些相关信息会发生变化,因此只能将所有信息依次比对
vue3仅对比元素内容
相比vue3.x对比vue2.x变化
-
源码组织方式变化:使用 TS 重写
-
支持
Composition API
:基于函数的API,更加灵活组织组件逻辑(vue2用的是options api
) -
响应式系统提升:Vue3中响应式数据原理改成
proxy
,可监听动态新增删除属性,以及数组变化 -
编译优化:vue2通过标记静态根节点优化diff,Vue3 标记和提升所有静态根节点,diff的时候只需要对比动态节点内容
-
打包体积优化:移除了一些不常用的api(inline-template、filter)
-
生命周期的变化:使用setup代替了之前的beforeCreate和created
-
Vue3 的 template 模板支持多个根标签
-
Vuex状态管理:创建实例的方式改变,Vue2为
new Stor
e , Vue3为createStore
-
Route 获取页面实例与路由信息:vue2通过this获取router实例,vue3通过使用 getCurrentInstance/ userRoute和userRouter方法获取当前组件实例
-
Props 的使用变化:vue2 通过 this 获取 props 里面的内容,vue3 直接通过 props
-
父子组件传值:vue3 在向父组件传回数据时,如使用的自定义名称,如 backData,则需要在 emits 中定义一下
Vue代码优化方面
执行代码优化
- 使用key
-
对于通过循环生成的列表,应给每个列表项一个稳定且唯一的key,这有利于在列表变动时,尽量少的删除、新增、改动元素
-
- 使用冻结对象
-
冻结对象不会被响应式
-
-
使用计算属性
-
保持对象引用稳定
-
合理的使用v-if和v-show
-
使用延迟装载(requestAnimationFrame)
-
keep-alive
-
长列表优化
Vuex的原理
核心流程中的主要功能:
-
Vue Components 是 vue 组件,组件会触发(dispatch)一些事件或动作,也就是图中的 Actions;
-
在组件中发出的动作,肯定是想获取或者改变数据的,但是在 vuex 中,数据是集中管理的,不能直接去更改数据,所以会把这个动作提交(Commit)到 Mutations 中;
-
然后 Mutations 就去改变(Mutate)State 中的数据;
-
当 State 中的数据被改变之后,就会重新渲染(Render)到 Vue Components 中去,组件展示更新后的数据,完成一个流程。
Vue与React对比?
相同点
-
都有组件化思想
-
都支持服务器端渲染
-
都有Virtual DOM(虚拟dom)
-
数据驱动视图
-
都有支持native的方案:
Vue
的weex
、React
的React native
-
都有自己的构建工具:
Vue
的vue-cli
、React
的Create React App
区别
-
数据流向的不同。
react
从诞生开始就推崇单向数据流,而Vue
是双向数据流 -
数据变化的实现原理不同。
react
使用的是不可变数据,而Vue
使用的是可变的数据 -
组件化通信的不同。
react
中我们通过使用回调函数来进行通信的,而Vue
中子组件向父组件传递消息有两种方式:事件和回调函数 -
diff算法不同。
react
主要使用diff队列保存需要更新哪些DOM,得到patch树,再统一操作批量更新DOM。Vue
使用双向指针,边对比,边更新DOM
vuex和redux之间的区别
从实现原理上来说,最大的区别是两点:
Redux
使用的是不可变数据,而Vuex
的数据是可变的。Redux
每次都是用新的state
替换旧的state
,而Vuex
是直接修改
Redux
在检测数据变化的时候,是通过diff
的方式比较差异的,而Vuex
其实和Vue的原理一样,是通过 getter/setter
来比较的(如果看Vuex
源码会知道,其实他内部直接创建一个Vue
实例用来跟踪数据变化)
最后:
如果你现在正在找工作,可以私信“web”或者直接添加小助理进群领取前端面试小册、简历优化修改、大厂内推以及更多阿里、字节大厂面试真题合集,和p8大佬一起交流。