1、diff复杂度原理及具体过程画图
diff 算法是一种通过同层的树节点进行比较的高效算法,避免了对树进行逐层搜索遍历,所以时间复杂度只有 O(n)。
diff 算法有两个比较显著的特点:
1、比较只会在同层级进行,不会跨层级比较。
2、在diff 比较的过程中,循环从两边向中间收拢。
diff流程: 首先定义 oldStartIdx、newStartIdx、oldEndIdx 以及 newEndIdx 分别是新老两个 VNode 的两边的索引。
接下来是一个 while 循环,在这过程中,oldStartIdx、newStartIdx、oldEndIdx 以及 newEndIdx 会逐渐向中间 靠拢。while 循环的退出条件是直到老节点或者新节点的开始位置大于结束位置。
while 循环中会遇到四种情况:
情形一:当新老 VNode 节点的 start 是同一节点时,直接 patchVnode 即可,同时新老 VNode 节点的开始索引都加1。
情形二:当新老 VNode 节点的 end 是同一节点时,直接 patchVnode 即可,同时新老 VNode 节点的结束索引都减1。
情形三:当老 VNode 节点的 start 和新 VNode 节点的 end 是同一节点时,这说明这次数据更新后 oldStartVnode 已经跑到了 oldEndVnode 后面去了。这时候在 patchVnode 后,还需要将当前真实 dom 节点移到 oldEndVnode 的后面,同时老 VNode 节点开始索引加 1,新 VNode 节点的结束索引减1。
情形四:当老 VNode 节点的 end 和新 VNode 节点的 start 是同一节点时,这说明这次数据更新后 oldEndVnode 跑到了 oldStartVnode 的前面去了。这时候在 patchVnode 后,还需要将当前真实 dom 节点移动到 oldStartVnode 的前面,同时老 VNode 节点结束索引减 1,新 VNode 节点的开始索引加 1。
while 循环的退出条件是直到老节点或者新节点的开始位置大于结束位置。
情形一:如果在循环中,oldStartIdx大于oldEndIdx了,那就表示oldChildren比newChildren先循环完毕,那么 newChildren里面剩余的节点都是需要新增的节点,把[newStartIdx, newEndIdx]之间的所有节点都插入到DOM中。
情形二:如果在循环中,newStartIdx大于newEndIdx了,那就表示newChildren比oldChildren先循环完毕,那么 oldChildren里面剩余的节点都是需要删除的节点,把[oldStartIdx, oldEndIdx]之间的所有节点都删除。
2、Vue组件中的Data为什么是函数,根组件却是对象呢?
综上可知,如果data是一个函数的话,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。
所以说vue组件的data必须是函数。这都是因为is的特带来的,跟vue本身设计无关。
3、Vue的组件通信
1、props 和
$emit父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过
$emit触发事件2、
$attrs和$listeners3、中央事件总线 bus
上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过
bus.$emit触发事件,bus.$on监听触发的事件。4、provide 和 inject
父组件中通过provider来提供变量,然后在子组件中通过iniect来注入变量。不论子组件有多深,只要调用了iniect那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
5、v-model
父组件通过v-model传递值给子组件时,会自动传递一个value的prop属性,在子组件中通过
this.$emit(input,val)自动修改v-model绑定的值。6、
$parent和$children7、boradcast 和 dispatch
8、vuex处理组件之间的数据交互 如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。
4、什么情况下使用 Vuex
如果应用够简单,最好不要使用 Vuex,一个简单的 store 模式即可,需要构建一个中大型单页应用时,使用Vuex能更好地在组件外部管理状态。
vuex流程图:
5、Vuex可以直接修改state的值吗?
可以直接修改,但是极其不推荐,state的修改必须在mutation来修改,否则无法被devtool所监测,无法监测数据的来源,无法保存状态快照,也就无法实现时间漫游/回滚之类的操作。
6、为什么Vuex的mutation不能做异步操作
Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现,这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,否则无法被devtools所监测。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。
7、怎么修改Vuex中的状态? Vuex中有哪些方法
通过
this.$store.state.属性的方法来访问状态通过
this.$store.commit('mutation中的方法')来修改状态
8、Vuex的缺点
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的,并且state中的值会伴随着浏览器的刷新而初始化,无缓存。
9、什么是 Vue.nextTick()?
$nextTick 是在下次DOM更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM,意思是 等你dom加载完毕以后再去调用nextTick()里面的数据内容。
写在最后
码字不易,谢谢关注、点赞和转发。
越笨拙,越努力; 越努力,越幸运; 大家加油!