Open zhangzheng-zz opened 3 years ago
export default function Console (BaseComponent) {
return {
mounted () {
console.log('HOC')
},
props: BaseComponent.props,
render (h) {
const slots = Object.keys(this.$slots).reduce((acc, key) => acc.concat(this.$slots[key]), [])
.map(vnode => {
// 将slot透传 slot 中的 VNode 的context 引用的还是原来的父组件实例,context应该引用的是高阶组件
// 导致了使不使用具名插槽都一样,最后都是按默认插槽来处理的
// this._self 指向 HOC 实例
vnode.context = this._self
return vnode
})
return h(
BaseComponent,
{
on: this.$listeners,
props: this.$props,
// 作用域插槽 slot 可以访问父作用域中的数据
scopedSlots: this.$scopedSlots,
attrs: this.$attrs
},
slots
)
}
}
}
vue 2 vs vue3 应用: 1、composition api vs options api 将API和功能逻辑抽离成块,方便定位 2、全局属性和实例属性 Vue (use\mixins) app (use\mixins) 3、setup的使用,替代 beforeCreate created 内部没有this对象 4、响应式的 api ref reactive vs data 对象 源码: 1、响应式的实现,设计模式一致,观察者发布订阅模式, 编码实现不同 Object.definePrototype 增删Key 深度嵌套(递归) Proxy vue2 Dep 发布者 Watcher 观察者 在 Watch 中 Dep.target = this [建立依赖] get 触发依赖联系 vue3 effect 触发依赖联系 2、vue3 具有对模板分为静态和动态,具有静态提升 HOISTED 静态节点超过6个的话就会直接字符串化 提高 diff 效率 diff 算法实现不一致 3、nextTick 对低版本放弃兼容 4、vue3 模块分包,tree-shaking, vue2 的方法都是挂载在实例上面 5、加入 patchFlags 标记节点类型 分别执行不同的 patch (process) 没有标记就是 full diff
编译时: parse(ast) -> transform(遍历ast,节点标记等) -> generrate(code 字符串传递给 render 函数,render 的产出是 vnode) 运行时: render产出的 vnode 输出DOM渲染,vnode 的 diff, 生命周期与调度等内容 响应式: 响应式更新
观察者与发布订阅者不同 观察者中 发布者和订阅者(观察者)是相互依赖的 必须要求观察者【订阅内容改变事件】 , 而发布订阅者是由【调度中心】进行调度,那么看看观察者模式 是如何【相互依赖】。
compile 的结果
compile 的流程
baseCompiler -> ast 树 -> transform 对 ast 节点进行转换(静态提升) -> 通过 generate 生成 code 代码字符串
vue2 vs vue3
1、响应式: vue2 深度劫持,消耗大,对对象属性,数组的劫持能力 2、全局:vue2方法(use、mixin)挂载在Vue全局,vue3分包分模块,tree-shaking,将响应式API reactive 暴露。 3、编译:vue2不分静态动态模板从头diff,vue3定向diff,静态提升序列化成字符串 4、options Api composition API
vue3 diff
patchElement -> patchChildren 类型不一样的节点旧直接卸载 patch 孩子的时候 text null array 核心 patch array 从头比对 从尾比对 一方结束的情况: 新短旧长,从头/尾卸载旧 新长旧短,从头/尾渲染新 乱序:
vue2 diff
头头比对 尾尾比对 交叉比对 头尾比对 移除与更新
调度
nextTick 的实现就是将回调 fn 放到清空当前任务 flushJobs 之后 p.then(flushJobs)包装之后成为微任务。 当前任务是指queueJob里面的任务,包括了DOM的更新 调度: 维护三个队列,在DOM各个时期将相应的任务入队。flushJobs是清空队列的方法,经过 promise.then(f) DOM的更新是一个effect副作用函数,在trigger的时刻会触发这个副作用,effect判断有传入调度器, 不会立刻执行effect,而是放入队列,等待异步执行。队列会去重。防止重复执行。(渲染)****