不可以,v-for
计算优先级比v-if
高,首先会把虚拟节点渲染出来,然后再进行v-if
判断。降低渲染性能
如果不使用 key
,Vue
会使用一种最大限度减少动态元素并且尽可能的尝试就地修改/复用
相同类型元素的算法。key 是为 Vue
中 vnode
的唯一标记,通过这个 key
,diff
算法可以更准确、更快速
key
就不是就地复用了,在 sameNode
函数 a.key === b.key 对比中可以避免就地复用的情况。所以会更加准确。key
的唯一性生成 map
对象来获取对应节点,比遍历方式更快当事件没有参数,则默认有个 event
参数;如果有自定义参数,则需要使用$event
传过去。
event
的构造函数是 MouseEvent
,即是原生的 event
对象event
被挂载到当前元素下,即 event.target
props
接收,可以使用数组/对象数据结构,对象结构可以定义类型和默认值。$emit
事件回传js
文件,其中声明一个 Vue
实例即可$on
,$emit
,$off
,参数分别是:注册函数名,真实函数beforeDestroy
中调用$off
beforeCreate
-> 父created
-> 父beforeMount
-> 子beforeCreate
-> 子created
-> 子beforeMount
-> 子mounted
-> 父mounted
beforeUpdate
-> 子beforeUpdate
-> 子updated
-> 父updated
beforeDestroy
-> 子beforeDestroy
-> 子destroyed
-> 父destroyed
beforeCreate
-> created
-> beforeMount
-> mounted
-> beforeUpdate
-> updated
-> beforeDestroy
-> destroyed
采用数据劫持结合观察者模式的方式
通过 Object.defineProperty()来劫持各个属性(只会劫持已经存在的属性)的 setter
,getter
,dep
和 Watcher
实现依赖收集和派发更新的过程:
vue
将 data
初始化为一个 Observer
并对对象中的每个值,重写了其中的 get
、set
,data
中的每个 key
,都有一个独立的 dep
(依赖收集器)。get
中,向 dep
(依赖收集器)添加了监听mount
时,实例了一个 Watcher
,将收集器的目标指向了当前 Watcher
data
值发生变更时,触发 set
,触发了 dep
(依赖收集器)中的所有监听的更新,来触发 Watcher.updatenextTick
中的回调是在下次 DOM
更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick
包装的方法
vuex
是专门为 vue
提供的全局状态管理系统,用于多个组件中数据共享、数据缓存等。(无法持久化、内部核心原理是通过创造一个全局实例 new Vue)
主要包括以下几个模块:
Store
中获取数据,mapGetters
辅助函数仅仅是将 store
中的 getter
映射到局部计算属性。store
中状态的方法,且必须是同步函数。mutation
,而不是直接变更状态,可以包含任意异步操作。Store
拆分为多个 store
且同时保存在单一的状态树中。作用与用法:
开发中缓存组件使用 keep-alive
组件,keep-alive
是 vue 内置组件,keep-alive
包裹动态组件 component
时,会缓存不活动的组件实例,而不是销毁它们,这样在组件切换过程中将状态保留在内存中,防止重复渲染 DOM
。
使用细节:
结合属性 include
和 exclude
可以明确指定缓存哪些组件或排除缓存指定组件。vue3
中结合 vue-router
时变化较大,之前是 keep-alive
包裹 router-view
,现在需要反过来用 router-view
包裹 keep-alive
。
keep-alive
的中缓存的时候还运用了 LRU(Least Recently Used) 算法。
LRU(最近最少使用) 缓存机制:
如果关键字 key
存在于缓存中,则返回关键字的值,否则返回 -1
。如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字-值」
。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间
组件缓存后更新,解决方案可以有以下两种:
vue-router
的项目,每次进入路由的时候,都会执行 beforeRouteEnter
。keep-alive
缓存的组件被激活的时候,都会执行 activated
钩子。原理:
keep-alive
是一个通用组件,它内部定义了一个 map
,缓存创建过的组件实例,它返回的渲染函数内部会查找内嵌的 component
组件对应组件的 vnode
,如果该组件在 map
中存在就直接返回它。由于 component
的 is
属性是个响应式数据,因此只要它变化,keep-alive
的 render
函数就会重新执行。
参数:
keep-alive 接收三个参数:
include 和 exclude,传数组情况居多。
生命周期:
生命周期有:activated 激活、deactivated 离开
当再次前进或者后退的时候只触发 activated
。
使用 keep-alive
会将数据保留在内存中,如果要在每次进入页面的时候获取最新的数据,需要在 activated
阶段获取数据,承担原来 created
钩子中获取数据的任务。那么,我们一般会在动态组件、路由组件去用到 keep-alive
组件。
hash 模式
URL
中 # 后面的东西 它的特点在于:hash
虽然出现 URL
中,但不会被包含在 HTTP
请求中,对后端完全没有影响,因此改变 hash
不会重新加载页面。hash
的改变添加监听事件window.addEventListener("hashchange", funcRef, false);
每一次改变 hash(window.location.hash),都会在浏览器的访问历史中增加一个记录。
利用 hash 的以上特点,就可以来实现前端路由 “更新视图但不重新请求页面” 的功能了
特点:兼容性好但是不美观
history 模式
利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。
这两个方法应用于浏览器的历史记录站,在当前已有的 back
、forward
、go
的基础之上,它们提供了对历史记录进行修改的功能。这两个方法有个共同的特点:当调用他们修改浏览器历史记录栈后,虽然当前 URL
改变了,但浏览器不会刷新页面,这就为单页应用前端路由 “更新视图但不重新请求页面” 提供了基础。
特点:虽然美观,但是刷新会出现 404 需要后端进行配置
1.工厂模式 - 传入参数即可创建实例
虚拟 DOM 根据参数的不同返回基础标签的 Vnode 和组件 Vnode
2.单例模式 - 整个程序有且仅有一个实例
vuex
和 vue-router
的插件注册方法 install
判断如果系统存在实例就直接返回掉
3.观察者模式 (响应式数据原理)
4.策略模式 策略模式指对象有某个行为,但是在不同的场景中,该行为有不同的实现方案-比如选项的合并策略
5.策略模式:优化 if else 冗余代码
6.代理模式:mini-vue proxy
$on
、$emit
基于发布订阅模式$on
用来收集所有的事件依赖,他会将传入的参数 event
和 fn
作为 key
和 value
的形式存到 vm._events
这个事件集合里,就像这样 vm._events[event]=[fn]
;$emit
是用来触发事件的,他会根据传入的 event
在 vm_events
中找到对应的事件并执行 invokeWithErrorHandling(cbs[i], vm, args, vm, info)
invokeWithErrorHandling
方法可以发现,他是通过 handler.apply(context, args)
和 handler.call(context)
的形式执行对应的方法用 js 模拟一颗 dom 树,放在浏览器内存中.当你要变更时,虚拟 dom 使用 diff 算法进行新旧虚拟 dom 的比较,将变更放到变更队列中,反应到实际的 dom 树,减少了 dom 操作。
虚拟 DOM 将 DOM 树转换成一个 JS 对象树,diff 算法逐层比较,删除,添加操作,但是,如果有多个相同的元素,可能会浪费性能,所以,react 和 vue-for 引入 key 值进行区分。
优点:
缺点:
无法进行极致优化: 虽然虚拟 DOM + 合理的优化,足以应对绝大部分应用的性能需求,但在一些性能要求极高的应用中虚拟 DOM 无法进行针对性的极致优化。
首次渲染大量 DOM 时,由于多了一层虚拟 DOM 的计算,会比 innerHTML 插入慢。
组件和组件之间有时候会存在相同的代码逻辑,分为局部混入和全局混入,我们希望对相同的代码逻辑进行抽取
缺点:
Vue3 使用 Composition API 替代了,优点:
Vue 自定义指令有全局注册和局部注册两种方式。先来看看注册全局指令的方式,通过 Vue.directive(id, [definition])
方式注册全局指令。然后在入口文件中进行 Vue.use() 调用。
它的作用价值在于当开发人员在某些场景下需要对普通 DOM 元素进行操作。提高代码复用。
指令本质上是装饰器,是 vue 对 HTML 元素的扩展,给 HTML 元素增加自定义功能。vue 编译 DOM 时,会找到指令对象,执行指令的相关方法。
自定义指令有五个生命周期(也叫钩子函数),分别是 bind
、inserted
、update
、componentUpdated
、unbind
原理
$on、$emit 是基于发布订阅模式的,维护一个事件中心,on 的时候将事件按名称存在事件中心里,称之为订阅者,然后 emit 将对应的事件进行发布,去执行事件中心里的对应的监听器
因为响应式数据 我们给对象和数组本身都增加了 __ob__
属性,代表的是 Observer 实例。当给对象新增不存在的属性 首先会把新的属性进行响应式跟踪 然后会触发对象 __ob__
的 dep
收集到的 watcher
去更新,当修改数组索引时我们调用数组本身的 splice
方法去更新数组
setup
相当于整合了 beforeCreate
和 created
setup
中的函数:如何选择?
ref:
.value
修改值toRef:
toRefs:
.value
属性的 get
和 set
实现响应式.value
,其他情况都需要emits
options
父组件的绑定事件setup
整合 beforeCreate
和 created``,beforeDestroy
改为 beforeUnmount
,destroyed
改为 unmounted
,其他与 vue2 一致.sync
defineAsyncComponent
,使用这个函数包裹 import() 引入异步组件loading
,主要实现原理就是具名插槽