虚拟dom
优点:
提高开发效率、提升性能、跨平台、浏览器兼容
Diff
调用名为patch的函数,比较新旧Virtual DOM Tree找出差异并更新,对比出是哪个虚拟节点更改了,找出这个虚拟节点,并只更新这个虚拟节点所对应的真实节点打补丁。
深度优先算法,只在同层级进行。
流程
当数据改变时,会触发setter,并且通过Dep.notify去通知所有订阅者Watcher,订阅者们就会调用patch方法,给真实DOM打补丁,更新相应的视图。
patch:对比当前同层的虚拟节点是否为同一种类型的标签,否:没必要比对了,直接整个节点替换成新虚拟节点,是:继续执行patchVnode方法进行深层比对
同种类型:key值、标签名、定义了data,是注释节点,是input标签时type是否相同
patchVnode
找到对应的真实DOM,称为el
判断相同:newVnode和oldVnode是否指向同一个对象,如果是,那么直接return
判断子节点:如果oldVnode有子节点而newVnode没有,则删除el的子节点;如果oldVnode没有子节点而newVnode有,则将newVnode的子节点真实化之后添加到el
判断文本节点:如果他们都有文本节点并且不相等,那么将el的文本节点设置为newVnode的文本节点。
都有子节点:updateChildren,新旧子节点对比,收尾指针法,新的子节点集合和旧的子节点集合,各有首尾两个指针
1、oldS 和 newS 使用sameVnode方法进行比较,sameVnode(oldS, newS)
2、oldS 和 newE 使用sameVnode方法进行比较,sameVnode(oldS, newE)
3、oldE 和 newS 使用sameVnode方法进行比较,sameVnode(oldE, newS)
4、oldE 和 newE 使用sameVnode方法进行比较,sameVnode(oldE, newE)
5、如果以上逻辑都匹配不到,再把所有旧子节点的 key 做一个映射到旧节点下标的 key -> index 表,然后用新 vnode 的 key 去找出在旧节点中可以复用的位置。
图
直到oldStart>oldEnd
key
高效的更新虚拟dom,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素。用index作为key的时候,变化节点后面的所有节点都会导致重新渲染,因为index变化了。
slot
Vue实现的一套内容分发的API,元素作为承载分发内容的出口。插槽用于决定将所携带的内容,插入到指定的某个位置,使得模块分块,具有模块化特质。
分为单个(默认、匿名)具名,作用域(带数据)
$nextTick
将回调延迟到下次 DOM 更新循环之后执行。
经历过宏/微任务,甚至两种并行。在最新版本 2.6.12 中稳定为 微任务。
当页面中的数据发生改变了,就会把该任务放到一个异步队列中,只有在当前任务空闲时才会进行DOM渲染,当DOM渲染完成以后,该函数就会自动执行。在修改数据后立即看到dom执行结果就需要用到nextTick方法。
异步更新DOM
Vue 在更新 DOM 时是异步执行的。只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。
双向绑定v-model原理
vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
文章
事件绑定的其他方式
.stop:阻止冒泡.prevent:阻止默认行为.self:仅绑定元素自身触发.once: 2.1.4 新增,只触发一次passive: 2.3.0 新增,滚动事件的默认行为 (即滚动行为) 将会立即触发,不能和.prevent 一起使用.sync 修饰符
从 2.3.0 起vue重新引入了.sync修饰符,但是这次它只是作为一个编译时的语法糖存在。它会被扩展为一个自动更新父组件属性的 v-on 监听器。
watch和computed
computed:Vue内部做了缓存处理,只有它的依赖属性发生了变化,它才会重新计算并且触发渲染。否则不会再次触发计算。
watch:侦听属性,异步执行
对一个对象类型的vue data进行侦听,当这个对象内的属性发生变化时,默认是不会触发侦听函数的。deep: true就可以侦听到对象内部属性的变化
immediate:父组件向子组件动态传值时,子组件props首次获取到父组件传来的默认值时
deep:监听对象属性
v-if v-show
v-show 只是简单的控制元素的 display 属性,而 v-if 才是条件渲染(条件为真,元素将会被渲染,条件 为假,元素会被销毁)
v-show 有更高的首次渲染开销, v-if 有更高的切换开销
v-if 有配套的 v-else-if 和 v-else
v-if 可以搭配 template 使用,而 v-show 不行
通信
6种方法
父子:
1、props,
e
m
i
t
2
、
emit 2、
emit2、parent,
c
h
i
l
d
r
e
n
3
、
children 3、
children3、ref
父子、兄弟、跨级:
1、
e
m
i
t
,
emit,
emit,on,bus
2、vuex
跨级:
1、
a
t
t
r
s
,
attrs,
attrs,listeners
2、provide,inject
生命周期
路由两种模式原理
改变视图的同时不会向后端发出请求,不会刷新界面,不会向后端发送请求
发送请求:仅hash符号之前的内容会被包含在请求中,history,把url给传送过去,会因找不到资源而报404错误
一个是通过window.location,另一个是window.history来改变浏览器的历史记录栈。
hash:url内带#。hash支持低版本的浏览器
history:pushState() 和 replaceState() 方法
Vuex mutation修改state
是mutation走一步,devtool记录一步,但是在mutation中加入异步函数就会导致我们devtool的记录失败,因为devtool不知道你里面的异步函数什么时候调用,在哪里调用
MVVM渐进式
MVVM是Model-View-ViewModel的缩写,Model代表数据模型负责业务逻辑和数据封装,View代表UI组件负责界面和显示,ViewModel监听模型数据的改变和控制视图行为,处理用户交互,简单来说就是通过双向数据绑定把View层和Model层连接起来。
渐进式:VUE不强求你一次性接受并使用它的全部功能特性
React区别
Vue3
data是函数
由于组价的复用,其实是创建多个vue实例,如果data中仍然是只是一个对象,那么其实创建出来的实例保持的都是对同一个对象的引用。
什么生命周期发异步请求
reated 和 mounted 中发起 ajax 请求是一样的,没有区别。 为啥没有区别:created 和 mounted 是在同一个 tick 中执行的,而ajax 请求的时间一定会超过一个 tick。所以即便ajax的请求耗时是 0ms, 那么也是在 nextTick 中更新数据到 DOM 中。