生命周期
生命周期钩子是如何实现的
生命周期钩子就是回调函数而已,当创建组件实例的过程中会调用的钩子方法
补充:
内部主要是使用callhook方法来调用对应的方法,核心是一个发布订阅模式,将钩子订阅好(内部采用数组的方式存储),在对应阶段进行发布
1. 什么是生命周期
vue实例从创建到销毁的一个过程。就是开始创建、初始化数据编译模板,挂载DOM渲染、更新、卸载等一系列的过程
2. 生命周期的作用
生命周期中会有很多的事件钩子,可以让我们更好的控制vue的实例化过程,从而形成更好的逻辑
3. 生命周期有几个阶段
八个阶段。初始化前/后、载入前/后、更新前/后、销毁前/后
beforeCreate、created、beforeMount、mounted、beforeUpdate、updated、beforeDestroy、destroyed
4. 第一次加载会触发哪几个钩子
beforecreate、created、beforemount、mounted
5. DOM渲染在哪个周期完成
mounted 中就已经完成
v-show 与 vi-if 的区别
v-show 是css的切换 频繁切换用vshow
v-if是dom的创建与销毁
开发中常用的指令
v-if、v-show、v-on、v-model、v-for
组件之间的通信
1. 父组件给子组件传值
父组件可以使用props像子组件传值
2. 子组件给父组件通信
子组件通过$emit触发事件,回调给父组件
3. 非父子、兄弟组件之间通信
可以通过引入bus作为媒介,然后分别通过调用bus事件触发和监听来实现通信和参数的传递
EventBus
这种方法通过一个空的 Vue 实例作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
还可以使用ref与 $parent / $children 访问
ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
vuex也可以用来组件之间的通信
组件中写name选项有哪些好处及作用
- 可以通过名字找到对应的组件(递归组件)
- 可以通过name属性实现缓存功能(keep-alive)
- 可以通过name来识别组件(跨组件通信时非常重要)
keep-alive平时在哪里使用?原理
keep-alive主要时组件缓存,采用的时LRU算法。最近最久未使用法。
常用的两个属性include/exclude,允许组件有条件的进行缓存。
两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态。
abstract: true, // 抽象组件
Vue.minxin的使用场景和原理?
Vue.mixin的作用就是抽离公共的业务逻辑,原理类似“对象的继承”,当组件初始化时会调用 mergeOptions方法进行合并,采用策略模式针对不同的属性进行合并,如果混入的数据和本身组件中的数据冲突,会采用“就近原则”以组件的数据为准。
补充回答:
mixin中有很多缺陷“命名冲突问题”,“依赖问题”,“数据来源问题”,这里强调一下mixin的数据是不会被共享的。
MVVM
就是一个设计模式 数据与视图的一个双向绑定、可以通过数据改变视图、也可以通过视图改变数据
M model 代表 数据模型
V view 代表UI组件
VM viewmodel 监听模型数据的改变和控制视图的对象
key
key 是vue中vnode标记的唯一id 可以通过这个key,使diff操作更快、更准确
准确
如果不加key,那么vue会选着复用节点(vue的就地更新策略)导致之前节点的状态被保留下来,会产生一系列的bug
快速
key的唯一性可以被map数据结构充分利用
组件中的data为什么是函数?
因为组件是用来复用的,js里的对象是引用关系,这样作用域就没有被隔离,会影响所有的实例。为了保证组件不同实例之间的data不冲突,data必须是一个函数。而new vue 的实例是不会被复用的,因此不存在引用对象的问题
v-model 的原理
vue中主要使用v-model的指令在表单input、select、textarea等元素上创建双向数据绑定,v-model本质上是vue的语法糖。v-model内部为输入不同的元素使用不同的属性并抛出不同的事件
js
1. 防抖节流 应用场景
防抖就是多次执行变为一次执行 联想搜索
节流就是多次执行变为每隔一段时间执行 监听滚动事件、比如是否滑倒底部加载更多
2. 什么是闭包
闭包就是能够读取其他函数内部变量的函数
「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包
3. 什么是深拷贝、浅拷贝,有哪些实现方式
promise和async await区别
- Promise和async都是异步的一个请求方式,且都是非阻塞的
- Async是基于promise去实现的 async是一个修饰符 被修饰的函数是一个异步函数 且await只能在async修饰的函数中使用
- Promise的书写方法是链式的 容易造成代码的堆叠 不易维护,而async的书写方法比较简洁 更像是同步代码比较好理解和维护
- Promise的返回时一个对象 需要用then catch去处理返回的数据和抛出的异常 而async使用的try catch去处理数据和异常
- Promise的返回可能在请求还没结束时就先执行了外面的操作
而async的话是遇到await就会等待返回结果再执行后面的操作
$emit的底层
$emit有两个参数,第一个参数是字符串类型,就是需要回调事件的名称,第二个参数是需要传递的数据
$emit第一步会把第一个参数 字符串转换成小写并检查名称是否符合语法标准,然后会去事件列表中找对应的回调函数,如果没有找到会直接返回,如果找到了会进行一次判断,判断回调函数是否大于一,如果大于一就转换成数组。
这时候第一个参数就不重要了,emit会舍弃第一个参数。然后把第二个参数数据转换成数组,传递给一个带try,catch的invokeWithErrorHandling()方法,在其中使用apply()或call()来调用回调函数
css
1. 怎么实现元素的水平垂直居中
2. 什么是盒子模型
3. 什么是BFC模式
4. css提高性能的方法
- 异步加载css
- 资源压缩
- 合理使用选择器
- 不要使用@import
- 减少使用昂贵的属性
数据类型有哪几种?ES新增的数据类型
基础数据类型有 string Boolean number undefined null
引用类型 object array function
es6 新增的数据类型 symbol se10新增 bigint
项目中用过哪些ES6?
const let ()=> foreach …
v-if和v-for一起使用的弊端以及解决办法
因为v-for比v-if优先级高,如果遍历的数组元素个数比较多,但是满足v-if条件比较少的情况下,会浪费性能,建议不要使用。
而且,每次刷新页面时,都会执行这样性能不高的代码。
如果需要相应的逻辑, 可以用计算属性computed解决,通过数组方法filter过滤数组,v-for直接循环计算属性的结果,就不需要使用v-if了。
而且computed是有缓存的,就是在它的依赖没有变化时,不会再执行对应计算属性的函数,就提高了性能。
如果v-if在v-for外层的话,可以使用template标签。
vue性能优化
尽量使用v-if代替v-show
减少data中的数据,因为data中的数据是双向绑定,会为每一个数据增加getter和setter
保证key的唯一性
图片懒加载
第三方模块按需导入
路由使用懒加载、异步组件
vue双向绑定的原理?vue3做了哪些优化?怎么进行DIFF算法的?
通过数据劫持结合发布者-订阅者模式的方式,通过“Object.defineProperty()”放来来劫持各个属性的 getter、setter,在消息变动时发布给相应的订阅者来触发回调
vue3中是使用了proxy方法来劫持数据
proxy的优点是
- 可以直接监听对象而非属性
- 可以直接监听数据的变化,而vue2中监听数组时是重写了数组的方法,splice、push、pop、shift、unshift、等7个方法
- 有更多的拦截方式
- proxy返回的是一个新的对象,我们只要操作新的对象就可以达到目的,而Object.defineProperty 只能去遍历对象的属性进行修改
nextTick在哪里使用?原理是?
核心答案:
nextTick的回调是在下次DOM更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。nextTick主要使用了宏任务和微任务。原理就是异步方法(promise, mutationObserver, setImmediate, setTimeout)经常与事件循环一起来问。
补充回答:
vue多次更新数据,最终会进行批处理更新。内部调用的就是nextTick实现了延迟更新,用户自定义的nextTick中的回调会被延迟到更新完成后调用,从而可以获取更新后的DOM。
Vue 为什么需要虚拟DOM? 虚拟DOM的优劣如何?
核心答案:
Virtual DOM 就是用js对象来描述真实DOM,是对真实DOM的抽象,由于直接操作DOM性能低但是js层的操作效率高,可以将DOM操作转化成对象操作,最终通过diff算法比对差异进行更新DOM (减少了对真实DOM的操作)。虚拟DOM不依赖真实平台环境从而也可以实现跨平台。
补充回答:
虚拟DOM的实现就是普通对象包含tag、data、children等属性对真实节点的描述。(本质上就是在JS和DOM之间的一个缓存)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Vue 中的diff原理
核心答案:
vue的diff算法是平级比较,不考虑跨级比较的情况。内部采用深度递归的方式 + 双指针的方式进行比较。
补充回答:
-
先比较是否是相同节点
-
相同节点比较属性,并复用老节点
-
比较儿子节点,考虑老节点和新节点儿子的情况
-
优化比较:头头、尾尾、头尾、尾头
-
比对查找进行复用
Vue2 与 Vue3.x 的diff算法:
Vue2的核心Diff算法采用了双端比较的算法,同时从新旧children的两端开始进行比较,借助key值找到可复用的节点,再进行相关操作。
Vue3.x借鉴了ivi算法和 inferno算法,该算法中还运用了动态规划的思想求解最长递归子序列。(实际的实现可以结合Vue3.x源码看。)
computed 和 watch 的区别和运用的场景?
核心答案:
computed: 计算属性。依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
watch: 监听数据的变化。更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
运用场景:
1)当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
2)当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
Vue性能优化
1、你都做过哪些Vue的性能优化?( 统计后的结果 )
1)编码阶段
尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher;
如果需要使用v-for给每项元素绑定事件时使用事件代理;
SPA 页面采用keep-alive缓存组件;
在更多的情况下,使用v-if替代v-show;
key保证唯一;
使用路由懒加载、异步组件;
防抖、节流;
第三方模块按需导入;
长列表滚动到可视区域动态加载;
图片懒加载;
2)用户体验:
骨架屏;
PWA;
还可以使用缓存(客户端缓存、服务端缓存)优化、服务端开启gzip压缩等。
3)SEO优化
预渲染;
服务端渲染SSR;
4)打包优化
压缩代码;
Tree Shaking/Scope Hoisting;
使用cdn加载第三方模块;
多线程打包happypack;
splitChunks抽离公共文件;
sourceMap优化;