
获得徽章 0
- 赞过评论3
- Vue2.x 中插槽的渲染更新过程:插槽作为子组件的 children,分为普通插槽和作用域插槽
在编译阶段:对于父组件中的普通插槽会向 data 中设置属性 { slot: slotName },而作用域插槽则会向子组件的 data 中设置属性 { scopedSlots: _u([{ key: slotName, fn }], null, true | false, hash) },对于子组件中的 <slot></slot> 借助渲染帮助函数生成 _t(slotName, children | null, attrs|null, bind) 。
在运行阶段:在父组件实例化过程中,在其 _render 时生成子组件 VNode ,并把插槽作为其 componentOptions 的 children 保存到子组件 VNode 上。在子组件实例化时,会通过 resolveSlots 把 _renderChildren(也就是 children) 按照 data 中的普通插槽名 slotName 分组保存到 vm.$slots 上。在子组件 _render 过程中,会通过 normalizeScopedSlots 传入 _parentVnode.data.scopedSlots 和 vm.$slots 生成 vm.$scopedSlots,在执行 render 函数时,执行 _t(slotName, children, attrs, bind) 取 vm.$scopedSlots 中对应 slotName 的函数去渲染插槽。
对于普通插槽来说,内容是来自父组件,在生成内容时如果访问到数据,则会触发依赖收集(收集的是父组件的渲染 Watcher),当修改数据时,会派发更新,重新渲染父组件,在做子组件更新时,由于插槽内容发生了变化,会做子组件的强制更新。
对于作用域插槽传入的 props 是来自子组件,作用域插槽中访问数据时,会触发依赖收集(收集的是子组件的渲染 Watcher),当修改数据时,会做派发更新,重新渲染子组件,然后重新 _t() 执行作用域插槽函数。展开赞过评论1 - Vue2.x 中 keep-alive 组件运行机制:
1. 从组件本身角度:keep-alive 使用 LRU (最近最少使用) 缓存机制对其第一个 child (组件 vnode) 做缓存,当缓存数量超过其 props 数据 max (默认是 10) 时,则移除 keys 中的第一个缓存的组件 vnode,也就是最不经常使用的,当其 props 数据 include 和 exclude 发生变化时,也会对缓存做移除处理。
2. 从渲染更新角度:在 keep-alive 组件的 render 过程中,
第一种情况:如果未命中缓存,则会正常执行其返回的组件 vnode 的 patch 流程,与正常组件渲染不同的是,vnode 上的 data 多携带了一个 keepAlive 为 true 的属性,这也就是被 keep-alive 包裹的组件会调用 activated 钩子函数的原因。
第二种情况:如果命中了缓存,则会向返回的组件 vnode 添加 componentInstance (之前缓存的组件 vnode 实例),这保证了在 patch 过程不会再次对组件 vnode 做实例化,而是直接进行组件 prepatch,最后会对上次的组件 vnode 执行 deactivated 钩子函数 (而不是 destroyed 钩子函数),对当前的组件 vnode 执行 activated 钩子函数,但不会再执行 mounted 钩子函数。展开赞过评论3 - Vue2.x 中 v-if 与 v-show 的区别:
1. 在编译阶段,v-if 会生成 js 的三元表达式;v-show 则是会放到 data 的 directives 属性中。
2. 在运行阶段:
2.1 执行方式:v-if 通过其表达式的值来决定是否渲染元素,如果为 false 则会返回一个空的 vnode,而不会渲染真正的元素;v-show 则是通过 style 来对元素进行显示或隐藏,无论表达式真假都会渲染元素。
2.2 执行时机:v-if 是在 render 过程;v-show 是在 patch 过程的 invokeInsertHook 中。展开等人赞过19 - Vue2.x 计算属性与侦听器区别:
1. 两者本质都是 watcher:计算属性是 lazy watcher,实例化 Watcher 时不会求值,只有访问到它时才会去订阅其中响应式数据的变化;侦听器是 user watcher,实例化 Watcher 时,就会去订阅所侦测数据的变化。
2. 计算属性的值可以是函数也可以是对象,是对象时,可以设置 get 和 set 以及 cache (cache 为 false,则不会去做数据订阅,只是简单地求值);侦听器的值可以是字符串、函数也可以是对象,是对象时,可以设置 deep、sync、immediate (deep 为 true 时,会让 侦听器 watcher 去订阅侦测对象的每个属性的变化,sync 为 true 时,会同步执行 watcher 回调,immediate 为 true 时,会在实例化 Watcher 后立即执行一次 watcher 回调),侦听器除了可以侦听响应式属性,还支持 'obj.xxx' 以及 侦测一个函数。
3. 计算属性 watcher 的 update 过程只是去修改 dirty 为 true,在渲染 watcher (render 中访问了计算属性) 或 侦听器 watcher (侦听了计算属性) 的 update 时去重新进行求值;侦听器 watcher 的 update 过程,要不同步执行回调 (sync 为 true),要不 nextTick 时,异步执行回调。展开等人赞过15 - Vue2.x 中 Observer 中 dep 属性的作用:
当 data 中属性值是对象或数组的情况,会调用 observe 把属性值也变成响应式对象( childOb ),目的是当访问 data 上的属性时,调用 childOb.dep.depend() 进行依赖收集。这样,当向对象添加新的或删除属性或者向数组添加新的或删除元素时,则会调用 childOb.dep.notify() 进行派发更新。展开评论点赞