1、v-for和v-if哪个优先级更高
v-for和v-if同时出现时,打印app.$options.render函数,可以看到_l函数(vue的循环函数)先执行,循环过程中再判断v-if,所以v-for优先级高于v-if
这样很浪费性能,每次都会先循环再判断是否渲染。解决方案,用一个template包裹写上v-if,里面再使用v-for,先判断是否渲染,这样就可以避免无谓的遍历了。
2、vue组件中data要函数形式
为啥组件的data要是函数,根组件可以是对象。
因为组件可能要创建多次,初始化的时候,都会引用data的指针,修改一个实例,其他组件都会改变。是函数的话,每次都会返回一个新的对象引用,这样就规避了污染。
根实例只创建一次,不会出现这个问题,而且创建根实例的时候不会检查data类型。
3、vue中key的作用
有三胞胎,原来是从小到大排着,后台老大跑到最后面去了,怎么区分呢,给他们带个牌子就能很快认出来了。
key可以帮助精确判断两个新旧VNode,提高patch过程的效率。
4、diff算法
diff不止在vue中使用,在react里面也会用到。vue使用了虚拟dom,数据发生改变后,会产生新的虚拟dom。vue会对比新旧vnode,这个patch过程就需要用到diff算法来精确找到发生变化的地方。
diff采用了 深度优先、同层比较的策略。两个节点比较,会先根据是否有子节点还是文本节点做不同操作。子节点判断是重点,diff会假设头尾节点相同做四次对比,如果没找到相同节点才会按照普通遍历方式进行对比,查找结束后再处理剩下的节点;借助key可以精确找出相同节点,提高patch效率。
5、组件化
vue中,定义组件的方法。全局与局部。
Vue.component是一个继承于Vue的类。vue组件实例化的时候,局部注册的components和全局注册的components的选项会合并,所以vue组件可以直接用全局components,局部组件只能在注册的地方使用。
优点:
(1)独立功能(高内聚、低耦合),可以复用,少写重复代码。
(2)组件更容易定位,找bug进行维护。
(3)将页面切割为不同功能的组件,更利于分工合作。
(4)将经常发生变化的部分切割为一个组件,减少新旧vnode的对比量,降低pacth过程耗时(项目管理预算组件)。
(5)vue中组件常用技术:prop传参、自定义事件、插槽。父子组件之间是数据单向流。
6、vue的(设计)理解
1、渐进式(灵活性)
应用小的话,只用核心特性就行。大型项目还可以引进vue-router、vue-cli、vuex等库和工具
2、易用性,简单易上手
数据式响应、声明式模板(只需要写一些对象属性)
3、高效性
vue中的虚拟dom和diff算法使应用具有高效能,在vue3中,引入Proxy使性能进一步提升
7、mvc、mvp、mvvn
三者都是框架模式,都是为了降低view层和model层的耦合。
(1)mvc最早应用在后端,后来前端也借鉴这个模式,比如backbone.js。有点是分层清晰,但是数据流混乱。
(2)mvp是mvc的进化形式,presenter层负责mv之间的通信,用来降低两者耦合度。但是p层可能会很臃肿。
(3)mvvm解决了mv之间的耦合问题,还提开发者做了很多两者之间映射的繁杂代码和dom更新操作,在提高开发效率和可读性的同时,保持了优越的性能表现。
8、vue组件间通信
一、父子
(1)父组件给子组件传数据:props传参、子组件给父组件传值:自定义事件处理函数$emit。
(2)$parent和$children获取父子组件的方法和data
(3)provide、inject。父组件provide数据后,不管子组件嵌套多深,都可以通过inject获取数据。
(4)refs,通过refs获取节点属性和方法。
二、兄弟
三、跨层
(1)多组件用到的数据,用vuex,如登录状态、角色选择等。
(2)事件总线、eventbus:创建一个vue实例,在一个vue组件中引入,调用bus.$emit()触发事件;在另一个vue组件mounted钩子函数调用bus.$on监听并处理事件,通过js函数传参。
8、vue开发中性能优化
(1)创建路由时使用懒加载
引入组件的时候,使用箭头函数返回import方法执行。
(2)使用keep-alive实现页面缓存
(3)避免同时使用v-for和v-if,这样会有不必要的遍历执行。
(4)纯展示列表,把数据直接冻结(Object.freeze),这样就不会进行响应式处理了。
(5)利用插件,只渲染滚动区域的节点(vue-virtual-scroller)
(6)定时器销毁,在beforeDestroy钩子中销毁定时器。
(7)图片懒加载(vue-lazyload库)
(8)ui框架组件按需引入
(9)无状态组件使用函数式组件(template标签 加一个functional,这个组件依然可以用props接受数据)
(10)组件分割,让组件自己负责自己部分的更新,减少patch范围。
(11)变量本地化,将要重复访问的实例属性保存为一个变量,let base = this.base.这样就会减少访问this上的属性,而是访问一个固定的值。
9、vue3新特性
(1)更快:重写了虚拟dom,静态属性提升、基于proxy的响应系统。
响应式实现方式。es6带来的新语法,proxy,可以直接代理对象对访问和操作进行拦截从而实现响应式,不用像vue2那样循环遍历调用Object.defineProperty一个一个添加属性来实现的。
(2)更小:通过摇树优化核心库体积
(3)composition Api
set up是入口,返回的对象的属性和方法会合并到render函数执行上下文,所以template可以直接使用setup里面的数据。如果要将数据设置为响应式,可以引入vue中的reactive、ref和toRefs函数处理,再将返回值返回。
setup中不要结构props,解构出来的数据会失去响应式。
自定义hooks,将vue2中分开的数据方法聚合在一起了,引用的时候更灵活(引用某些数据与方法),还可以再这基础上进行拓展。更贴近模块化编程。
10、watch和computed比较
watch监听数据变化,然后触发事件。
computed用于返回基于某些数据计算得到的结果,比如资金、合计数据、前端分页等。
watch适用于监听数据,然后进行前后端交互。
computed有缓存策略,依赖数据发生变化后,才会重新计算。
11、vue生命周期
创建前后、挂载前后、更新前后、销毁前后,是自动执行的函数。
beforeCreate界面还未初始化,也可以进行一些操作,比如vuex在此钩子给每个vue实例混入store
created 已经可以用到this的属性和方法了
beforeMount此时模板已经渲染后,还没有挂载。
mounted,此时模板挂载完成,dom已经生成。echarts可以在此时使用,echarts的初始化必须要用到原生dom。:
beforeUpdate和updated
beforeDestroy 此时可以消除定时器,避免内存泄漏
destroyed 销毁实例上的方法和属性。
activated 被keep-alive缓存的组件激活时调用 keep-alive可以用于tab切换,缓存组件。
deactivated 被keep-alive缓存的组件停用时调用。
12、js中同步任务和异步任务
同步任务进入主线程执行,异步任务进eventtable 进行回调注册。主线程任务执行完以后,将异步任务放进主线程执行。
异步任务也有区分:
(1)宏任务:setTimeout、setInterval、script代码块、ajax请求
(2)微任务:promise的回调、async/await(promise的excutor是同步任务)
微任务执行优先级高于宏任务,setTimeout就算等待时间到了,主线程里还有任务执行,就需要等待。就算没有,也不是立马执行,至少是4微秒。
13、vuex基本实现
vuex是一个vue插件,vue插件需要提供一个install方法,此方法会得到vue构造函数。此外vuex提供了store类用于生成store实例。
vuex需要导出包含install和store方法的对象。
install方法中使用Vue.beforeCreate钩子,使用Vue.mixin为全局混入store:先判断实例有无自己的$options.store,优先使用实例的store,没有的话则给this赋值$store属性。这就是为什么vue每个实例都可以直接用到this.$store的原因。
store是个class,constructor里面利用了vue实例自身的响应式原理,生成vue实例,将各个状态放进data来保管。
14、vue-router基本原理
现在很多vue引用是单页应用,一般不会请求多个页面。vue-router会根据url匹配对应的vue组件进行渲染。
vue-router提供一个install方法,会把router实例挂载到vue.prototype上,说要vue实例可以访问到$router,还会利用vue.component注册一个全局组件router-view。并且会将传入的routes配置进行映射保存,一遍查找使用。router会给window添加hashchange事件,处理函数会匹出配路由对应的组件,之后调用router-view组件的render函数,渲染匹配到的组件。
15、nextTick
用于数据变化,dom更新后,获取dom。
dom更新,是异步操作。如果数据改变一次就更新一次视图,这样很消耗性能,只需等到所有数据更新完后,在一并更新dom,这样减少无谓的渲染,提升渲染效率。
nextTick是通过microtask实现的。
16、递归组件
递归组件,组件内部可以使用name属性作为标签名,自己调用自己。一般侧边栏菜单会用到,判断该菜单是否有子菜单,有的话就自己调用自己。