2022vue面试题+答案面试题视频讲解(高效学习):学习v-show和v-if有什么区别?v-if是真正的条件渲染,因为它将确保条件块内的事件侦听器和子组件在切换期间被适当地销毁和重建;也很懒惰:如果在初始渲染时条件为假,什么也不做-条件块不会开始渲染,直到条件第一次变为真。v-show更简单-无论初始条件如何,元素始终呈现,并且根据CSS“显示”属性简单地切换。因此,v-if适用于运行时很少改变条件,不需要频繁切换条件的场景;v-show适用于需要非常频繁切换条件的场景。computed和watch的区别和应用场景是什么?computed:是一个computed属性,依赖于其他属性值,computed的值被缓存起来,只有当它所依赖的属性的值发生变化时,下次获取computed的值时才会重新计算computed的值;watch:更多的“观察”功能,类似于一些数据的监听回调。每当监控到的数据发生变化时,都会执行回调,进行后续操作;应用场景:当我们需要进行数值计算,依赖其他数据时,应该使用computed,因为它可以利用computed的缓存特性,避免每次取到值都重新计算;当我们需要在数据更改时执行异步或昂贵的操作时,我们应该使用watch,使用watch选项允许我们执行异步操作(访问API),限制我们执行此操作的频率,并设置中间状态直到我们得到最终结果。这些是计算属性不能做的事情。Vue组件通信方式有哪些?props和$emit父组件通过props向子组件传输数据,子组件通过$emit触发事件向父组件传输数据。$parent,$children获取当前组件的父组件和当前组件的子组件$attrs和$listenersA->B->C。Vue2.4开始提供$attrs和$listeners来解决这个问题。在父组件中提供变量,然后通过inject在子组件中注入变量。(官方在实际业务中不推荐使用,但是写组件库的时候很常用)$refs获取组件实例envetBus兄弟组件数据传递这种情况可以使用事件总线的方式vuex状态管理生命周期有哪些Vue的方法一般在实例初始化之后,数据观察者和event/watcher事件配置之前调用beforeCreate的哪一步发送请求。当前阶段,data、methods、computed、watch上的数据和方法都无法访问。创建的实例在创建后被调用。在这一步中,实例完成了以下配置:数据观察者、属性和方法的操作、watch/event事件回调。这里没有$el。如果你想与Dom交互,你可以通过vm.$nextTick访问它。DombeforeMount在挂载开始前被调用:第一次调用相关的渲染函数。mounted在挂载完成后发生。现阶段挂载真正的Dom,双向绑定数据,可以访问Dom节点。beforeUpdate在数据更新时调用,它发生在虚拟DOM重新渲染和修补之前。可以在这个钩子中进一步改变状态,这不会触发额外的重新渲染过程。updated发生在更新完成后,当前stage的组件Dom已经更新完毕。注意避免在这段时间更改数据,因为这可能会导致更新的无限循环,在服务器端渲染期间不会调用此钩子。beforeDestroy在销毁实例之前调用。在这一步,实例仍然完全可用。我们可以在这一点上做一些收尾工作,比如清除计时器。destroyed在Vue实例被销毁后调用。调用后,Vue实例指向的所有东西都将被解除绑定,所有事件监听器将被移除,所有子实例将被销毁。服务器端渲染期间不会调用此挂钩。activatedkeep-aliveexclusive,组件激活时调用deactivatedkeep-aliveexclusive,组件销毁时调用异步请求在哪一步发起?异步请求可以在created、beforeMount、mounted这三个钩子函数中进行,因为在这三个钩子函数中,已经创建了数据,可以赋值服务端返回的数据。如果异步请求不需要依赖Dom,建议在创建的钩子函数中调用异步请求,因为在创建的钩子函数中调用异步请求有以下好处:可以更快的获取服务器数据,减少页面加载时间;ssr不支持beforeMount、mountedHook函数,放在created中有助于一致性;Vue3.0和2.0的响应式原理的区别在于Vue3.x使用Proxy而不是Object.defineProperty。因为Proxy可以直接监听对象和数组的变化,拦截方式多达13种。相关代码如下import{mutableHandlers}from"./baseHandlers";//代理相关逻辑import{isObject}from"./util";//工具方法exportfunctionreactive(target){//根据不同的参数创建不同的响应objectreturncreateReactiveObject(target,mutableHandlers);}functioncreateReactiveObject(target,baseHandler){if(!isObject(target)){}constobserved=newProxy(target,baseHandler);返回观察;}constget=createGetter();constset=createSetter();functioncreateGetter(){returnfunctionget(target,key,receiver){//辐射得到的值constres=Reflect.get(target,key,receiver);安慰。log("财产收购",key);if(isObject(res)){//如果获取的值是对象类型,则返回当前对象的代理对象returnreactive(res);}返回资源;};}functioncreateSetter(){returnfunctionset(target,key,value,receiver){constoldValue=target[key];常量hadKey=hasOwn(target,key);constresult=Reflect.set(target,key,value,receiver);if(!hadKey){console.log("添加新属性",key,value);}elseif(hasChanged(value,oldValue)){console.log("属性值已修改",key,value);}返回结果;};}exportconstmutableHandlers={get,//获取属性集时调用此方法,//修改属性时调用此方法};Vue3.0和2.0响应式原理的区别Vue3.x使用Proxy代替Object.defineProperty,因为Proxy可以直接监听对象和数组的变化,拦截方式多达13种。相关代码如下import{mutableHandlers}from"./baseHandlers";//代理相关逻辑import{isObject}from"./util";//工具方法exportfunctionreactive(target){//根据不同的参数创建不同的响应objectreturncreateReactiveObject(target,mutableHandlers);}functioncreateReactiveObject(target,baseHandler){if(!isObject(target)){}constobserved=newProxy(target,baseHandler);返回观察;}constget=createGetter();constset=createSetter();functioncreateGetter(){returnfunctionget(target,key,receiver){//辐射得到的值constres=Reflect.get(target,key,receiver);安慰。log("财产收购",key);if(isObject(res)){//如果获取的值是对象类型,则返回当前对象的代理对象returnreactive(res);}返回资源;};}functioncreateSetter(){returnfunctionset(target,key,value,receiver){constoldValue=target[key];常量hadKey=hasOwn(target,key);constresult=Reflect.set(target,key,value,receiver);if(!hadKey){console.log("添加新属性",key,value);}elseif(hasChanged(value,oldValue)){console.log("属性值已修改",key,value);}返回结果;};}exportconstmutableHandlers={get,//获取属性集时调用此方法,//修改属性时调用此方法};为什么在Vue3.0中使用了Proxy而放弃了Object.defineProperty?Object.defineProperty本身有一定的监听数组下标变化的能力,但是在Vue中,考虑到性能/体验性价比,有大放弃了这个特性(为什么Vue不能检测到数组变化)为了解决这个问题,之后vue内部处理,可以使用如下方法监听数组push();pop();shift();unshift();splice();sort();reverse();copy代码只是针对上面的7个,这个方法被hack了,所以其他数组的属性也是检测不到的,还是有一定的局限性的。Object.defineProperty只能劫持对象属性,所以我们需要遍历每个对象的每个属性。在Vue2.x中,数据监控是通过递归+遍历数据对象来实现的。如果属性值也是一个对象,那么就需要深度遍历。显然,劫持一个完整的对象是更好的选择。Proxy可以劫持整个对象并返回一个新的对象。Proxy不仅可以代理对象,还可以代理数组。也可以代理动态增加的属性。Computed实现原理Computed本质上是一个惰性求值观察者。Computed内部实现了一个lazywatcher,即computedwatcher。Computedwatcher不会立即求值,同时持有一个dep实例。它在内部标记计算属性是否需要通过this.dirty属性重新计算。当计算出的依赖状态发生变化时,它会通知惰性观察者。computedwatcher通过this.dep.subs.length判断是否有订阅者。如果是,它将重新计算,然后比较旧值和新值。如果它发生变化,将重新渲染。(Vue不仅要保证计算属性依赖的值发生变化,还要保证当计算属性最终计算出的值发生变化时,会触发渲染观察者重新渲染,这本质上是一种优化。)如果没有,就把这个。脏=真。(当一个计算属性依赖于其他数据时,该属性不会立即重新计算,只有在后面需要在别处读取该属性时才会真正计算,即具有lazy(惰性计算)特性。)关键在Vue中到底有什么用?关键是每个vnode的唯一ID。依靠key,我们的diff操作可以更准确更快(diff节点对于简单的列表页面渲染也更快,但是会有一些隐藏的副作用,比如可能没有Transition效果,或者当某些节点有绑定数据时(form)state,会出现state错位。)diff算法过程中,会先对新旧节点进行端到端的交叉比较,当使用新节点的key时没有匹配到,与老节点比较,找到对应的老节点。更准确的说:因为key不是就地复用,所以在sameNode函数a.key===b.key比较中可以避免就地复用。所以它会更准确。如果不加key,会保留前一个节点的状态,会出现一系列的bug。更快:键的唯一性可以被Map数据结构充分利用。与遍历搜索的时间复杂度O(n)相比,Map的时间复杂度仅为O(1)。源码如下:functioncreateKeyToOldIdx(children,beginIdx,endIdx){leti,key;常量地图={};对于(i=beginIdx;i<=endIdx;++i){key=children[i].key;如果(isDef(键))地图[键]=我;}returnmap;}v-model的原理?在vue项目中,我们主要使用v-model指令对forminput、textarea、select等元素创建双向数据绑定。我们知道v-model本质上只是语法糖,v-model内部针对不同的input元素使用不同的属性并抛出不同的事件:text和textarea元素使用value属性和input事件;checkbox和radio使用checked属性和change事件;select字段使用value作为prop并将change作为event。以输入表单元素为例: {{message}}
