vue3源码分析 -- h

【vue3源码】十四、认识vnode中的shapeFlag和patchFlag属性 介绍vnode中的shapeFlag和patchFlag属性属性 阅读详情

上篇runtime中我们了解到,虚拟 DOM是 Vue 在运行时,通过h函数获取到VNode对象,这里我们就来看下h函数是如何实现的

案例

首先引入h函数,之后通过h函数生成一个vnode对象,并将其打印

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="../../dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script>
      const { h } = Vue

      debugger
      const vnode = h(
        'div',
        {
          class: 'test'
        },
        'hello render'
      )
      console.log(vnode)
    </script>
  </body>
</html>

h函数定义在packages/runtime-core/src/h.ts文件下:

可以看出h函数接收三个参数,当前type为div,propsOrChildren为{ class: 'test'},children 为hello render

在这里插入图片描述

createVNode方法

之后根据参数的长度不同走不同的判断逻辑,其核心是执行createVNode方法,实际执行的是_createVNode,该方法在packages/runtime-core/src/vnode.ts文件中:

export const createVNode = (
  __DEV__ ? createVNodeWithArgsTransform : _createVNode
) as typeof _createVNode

function _createVNode(
  type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
  props: (Data & VNodeProps) | null = null,
  children: unknown = null,
  patchFlag: number = 0,
  dynamicProps: string[] | null = null,
  isBlockNode = false
): VNode {
  if (!type || type === NULL_DYNAMIC_COMPONENT) {
    if (__DEV__ && !type) {
      warn(`Invalid vnode type when creating vnode: ${type}.`)
    }
    type = Comment
  }
  // 是否是 vnode 通过 __v_isVNode 来判断
  if (isVNode(type)) {
    // createVNode receiving an existing vnode. This happens in cases like
    // <component :is="vnode"/>
    // #2078 make sure to merge refs during the clone instead of overwriting it
    const cloned = cloneVNode(type, props, true /* mergeRef: true */)
    if (children) {
      normalizeChildren(cloned, children)
    }
    if (isBlockTreeEnabled > 0 && !isBlockNode && currentBlock) {
      if (cloned.shapeFlag & ShapeFlags.COMPONENT) {
        currentBlock[currentBlock.indexOf(type)] = cloned
      } else {
        currentBlock.push(cloned)
      }
    }
    cloned.patchFlag |= PatchFlags.BAIL
    return cloned
  }

  // class component normalization.
  if (isClassComponent(type)) {
    type = type.__vccOpts
  }

  // 2.x async/functional component compat
  if (__COMPAT__) {
    type = convertLegacyComponent(type, currentRenderingInstance)
  }

  // class & style normalization.
  // class 和 style 的增强
  if (props) {
    // for reactive or proxy objects, we need to clone it to enable mutation.
    props = guardReactiveProps(props)! // 解析 props
    let { class: klass, style } = props // 结构  class 赋值给 klass, style
    if (klass && !isString(klass)) {
      props.class = normalizeClass(klass) // 增强 class
    }
    if (isObject(style)) {
      // reactive state objects need to be cloned since they are likely to be
      // mutated
      if (isProxy(style) && !isArray(style)) {
        style = extend({}, style)
      }
      props.style = normalizeStyle(style)
    }
  }

  // encode the vnode type information into a bitmap
  const shapeFlag = isString(type) // 根据 type 类型进行 shapeFlag 赋值 当前为 div 则 ShapeFlags.ELEMENT
    ? ShapeFlags.ELEMENT
    : __FEATURE_SUSPENSE__ && isSuspense(type)
    ? ShapeFlags.SUSPENSE
    : isTeleport(type)
    ? ShapeFlags.TELEPORT
    : isObject(type)
    ? ShapeFlags.STATEFUL_COMPONENT
    : isFunction(type)
    ? ShapeFlags.FUNCTIONAL_COMPONENT
    : 0

  if (__DEV__ && shapeFlag & ShapeFlags.STATEFUL_COMPONENT && isProxy(type)) {
    type = toRaw(type)
    warn(
      `Vue received a Component which was made a reactive object. This can ` +
        `lead to unnecessary performance overhead, and should be avoided by ` +
        `marking the component with `markRaw` or using `shallowRef` ` +
        `instead of `ref`.`,
      `\nComponent that was made reactive: `,
      type
    )
  }

  return createBaseVNode(
    type,
    props,
    children,
    patchFlag,
    dynamicProps,
    shapeFlag,
    isBlockNode,
    true
  )
}

这里isVNode(type)通过判断type是否是 VNode,我们来看下isVNode方法:

export function isVNode(value: any): value is VNode {
  return value ? value.__v_isVNode === true : false
}

主要通过__v_isVNode属性来判断是否是VNode,之后再判断props即传入的{ class: 'test'},对class 、style增强,这块我们放到之后来讨论

接着又对shapeFlag赋值,当前type为 string 类型,此时被赋值为ShapeFlags.ELEMENT即等于1,最后将处理好的type、props、children、shapeFlag等参数传入createBaseVNode方法中

在这里插入图片描述

_createVNode方法核心:

  • 对class 、style增强
  • 对shapeFlag标记赋值

对shapeFlag标记赋值

接着再看下createBaseVNode方法:

function createBaseVNode(
  type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
  props: (Data & VNodeProps) | null = null,
  children: unknown = null,
  patchFlag = 0,
  dynamicProps: string[] | null = null,
  shapeFlag = type === Fragment ? 0 : ShapeFlags.ELEMENT,
  isBlockNode = false,
  needFullChildrenNormalization = false
) {
  const vnode = {
    __v_isVNode: true,
    __v_skip: true,
    type,
    props,
    key: props && normalizeKey(props),
    ref: props && normalizeRef(props),
    scopeId: currentScopeId,
    slotScopeIds: null,
    children,
    component: null,
    suspense: null,
    ssContent: null,
    ssFallback: null,
    dirs: null,
    transition: null,
    el: null,
    anchor: null,
    target: null,
    targetAnchor: null,
    staticCount: 0,
    shapeFlag,
    patchFlag,
    dynamicProps,
    dynamicChildren: null,
    appContext: null
  } as VNode

  if (needFullChildrenNormalization) {
    normalizeChildren(vnode, children) // 创建子节点
    // normalize suspense children
    if (__FEATURE_SUSPENSE__ && shapeFlag & ShapeFlags.SUSPENSE) {
      ;(type as typeof SuspenseImpl).normalize(vnode)
    }
  } else if (children) {
    // compiled element vnode - if children is passed, only possible types are
    // string or Array.
    vnode.shapeFlag |= isString(children)
      ? ShapeFlags.TEXT_CHILDREN
      : ShapeFlags.ARRAY_CHILDREN
  }

  // validate key
  if (__DEV__ && vnode.key !== vnode.key) {
    warn(`VNode created with invalid key (NaN). VNode type:`, vnode.type)
  }

  // track vnode for block tree
  if (
    isBlockTreeEnabled > 0 &&
    // avoid a block node from tracking itself
    !isBlockNode &&
    // has current parent block
    currentBlock &&
    // presence of a patch flag indicates this node needs patching on updates.
    // component nodes also should always be patched, because even if the
    // component doesn't need to update, it needs to persist the instance on to
    // the next vnode so that it can be properly unmounted later.
    (vnode.patchFlag > 0 || shapeFlag & ShapeFlags.COMPONENT) &&
    // the EVENTS flag is only for hydration and if it is the only flag, the
    // vnode should not be considered dynamic due to handler caching.
    vnode.patchFlag !== PatchFlags.HYDRATE_EVENTS
  ) {
    currentBlock.push(vnode)
  }

  if (__COMPAT__) {
    convertLegacyVModelProps(vnode)
    defineLegacyVNodeProperties(vnode)
  }

  return vnode
}

该方法首先定义了一个vnode对象,属性__v_isVNode标记为该对象是否为VNode对象。由于当前needFullChildrenNormalization默认传入的是true,所以直接执行normalizeChildren(vnode, children)方法来创建子节点,再来看下normalizeChildren方法:

export function normalizeChildren(vnode: VNode, children: unknown) {
  let type = 0
  const { shapeFlag } = vnode // 当前shapeFlag 是 1 children是字符串
  // children 为 undefined 或 null
  if (children == null) {
    children = null
  } else if (isArray(children)) { // 是否是数组
    type = ShapeFlags.ARRAY_CHILDREN
  } else if (typeof children === 'object') { // 是否是对象
    if (shapeFlag & (ShapeFlags.ELEMENT | ShapeFlags.TELEPORT)) {
      // Normalize slot to plain children for plain element and Teleport
      const slot = (children as any).default
      if (slot) {
        // _c marker is added by withCtx() indicating this is a compiled slot
        slot._c && (slot._d = false)
        normalizeChildren(vnode, slot())
        slot._c && (slot._d = true)
      }
      return
    } else {
      type = ShapeFlags.SLOTS_CHILDREN
      const slotFlag = (children as RawSlots)._
      if (!slotFlag && !(InternalObjectKey in children!)) {
        // if slots are not normalized, attach context instance
        // (compiled / normalized slots already have context)
        ;(children as RawSlots)._ctx = currentRenderingInstance
      } else if (slotFlag === SlotFlags.FORWARDED && currentRenderingInstance) {
        // a child component receives forwarded slots from the parent.
        // its slot type is determined by its parent's slot type.
        if (
          (currentRenderingInstance.slots as RawSlots)._ === SlotFlags.STABLE
        ) {
          ;(children as RawSlots)._ = SlotFlags.STABLE
        } else {
          ;(children as RawSlots)._ = SlotFlags.DYNAMIC
          vnode.patchFlag |= PatchFlags.DYNAMIC_SLOTS
        }
      }
    }
  } else if (isFunction(children)) { // 是否是 函数
    children = { default: children, _ctx: currentRenderingInstance }
    type = ShapeFlags.SLOTS_CHILDREN
  } else {
    children = String(children) // 此时 'hello render'
    // force teleport children to array so it can be moved around
    if (shapeFlag & ShapeFlags.TELEPORT) {
      type = ShapeFlags.ARRAY_CHILDREN
      children = [createTextVNode(children as string)]
    } else {
      type = ShapeFlags.TEXT_CHILDREN
    }
  }
  vnode.children = children as VNodeNormalizedChildren
  // 9 按位或赋值  vnode.shapeFlag |= type 等同于 vnode.shapeFlag = vnode.shapeFlag | type
  vnode.shapeFlag |= type 
}

该方法接收两个参数,一个是定义的vnode对象,一个是children即hello render。之后再从vnode对象中解构出shapeFlag,即当前 string 类型为 1,根据children类型不同对children、type和 shapeFlag重新赋值

由于当前children为 string 类型,执行children = String(children),此时children为hello render,并将其vnode.children = children重新赋值。type = ShapeFlags.TEXT_CHILDREN 即 type 为 8

在这里插入图片描述

最后对 vnode.shapeFlag |= type 按或位赋值即为 9

在这里插入图片描述

这里拓展下 |= 按或位赋值,vnode.shapeFlag |= type 等同于 vnode.shapeFlag = vnode.shapeFlag | type。当前 vnode.shapeFlag = 8,type = 1,转为二进制:

// type = 1
00000000 00000000 00000000 00000001

// shapeFlag = 8
00000000 00000000 00000000 00001000

// 或 就是通过上下 ↕ 比较,如果上下是 0 则是 0,上下是 0 和 1 则是 1
// 结果是 9 
00000000 00000000 00000000 00001001

所以此时计算后的 vnode.shapeFlag = 9,之后 createBaseVNode 执行完毕返回 vnode 对象,至此 h 函数执行完毕,打印 vnode 对象:

在这里插入图片描述

对class、style增强

我们再回过来看下 h 函数如何对 class style 增强的,该逻辑在 _createVNode 方法中:

function _createVNode(
  type: VNodeTypes | ClassComponent | typeof NULL_DYNAMIC_COMPONENT,
  props: (Data & VNodeProps) | null = null,
  children: unknown = null,
  patchFlag: number = 0,
  dynamicProps: string[] | null = null,
  isBlockNode = false
): VNode {
  // 省略

  // class & style normalization.
  // class 和 style 的增强
  if (props) {
    // for reactive or proxy objects, we need to clone it to enable mutation.
    props = guardReactiveProps(props)! // 解析 props
    let { class: klass, style } = props // 结构  class 赋值给 klass, style
    if (klass && !isString(klass)) {
      props.class = normalizeClass(klass) // 增强 class
    }
    if (isObject(style)) {
      // reactive state objects need to be cloned since they are likely to be
      // mutated
      if (isProxy(style) && !isArray(style)) {
        style = extend({}, style)
      }
      props.style = normalizeStyle(style)
    }
  }
  // 省略
  
  return createBaseVNode(
    type,
    props,
    children,
    patchFlag,
    dynamicProps,
    shapeFlag,
    isBlockNode,
    true
  )
}

结合一下案例进行分析:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="../../dist/vue.global.js"></script>
  </head>
  <body>
    <div id="app"></div>
    <script>
      const { h, render } = Vue
      // <div :class="{ red: true }">增强的 class</div>
      debugger
      const vnode = h(
        'div',
        {
          class: {
            red: true
          }
        },
        '增强的 class'
      )
      render(vnode, document.querySelector('#app'))
    </script>
  </body>
</html>

可以看出 { class: klass, style } = props 对 props 解构,并将 class 赋值给 klass,如果存在 klass 且不为 string 类型,则执行 props.class = normalizeClass(klass),对其 props.class 重新赋值。我们再看下 normalizeClass 方法:

export function normalizeClass(value: unknown): string {
  let res = ''
  // 是字符串 直接赋值
  if (isString(value)) {
    res = value
  } else if (isArray(value)) {
    // 是数组 则递归迭代再拼接
    for (let i = 0; i < value.length; i++) {
      const normalized = normalizeClass(value[i])
      if (normalized) {
        res += normalized + ' '
      }
    }
  } else if (isObject(value)) {
    // 是对象 则 for in 再拼接返回
    for (const name in value) {
      if (value[name]) {
        res += name + ' '
      }
    }
  }
  return res.trim()
}

根据 value 类型,如果是字符串则直接返回;如果是数组则递归迭代再拼接返回;如果是对象则迭代再拼接返回。由于当前 value 是对象 { red: true },所以此时的 res 为 red:

在这里插入图片描述

最终的结果:

在这里插入图片描述

总结

1)createVNode 核心是处理 shapeFlag 赋值,之后在 createBaseVNode 中又通过 shapeFlag 和 type 根据按位或运算,重新对 shapeFlag 赋值

2)h 函数本质上是对四个属性处理 children、props、shapeFlag、type 和 class style 的增强

vue3.0源码解读 -渲染系统 vue3.0的patch相对于2.0做了很多优化,vue3.0在编译阶段会对vnode截形flag标记,用于对vnode更新时的diff做性能优化。下面我们从patch函数入口开始一步一步的了解3.0时如何进行patch的,以及具体有了哪些性能提升。 ... 阅读详情

相关推荐

vue3 源码分析-运行流程分析

const createApp = ((...args) => { const app = ensureRenderer().createApp(...args); { injectNativeTagCheck(app); } const { mount } = app; app.mount = (containerOrSelector) => { const container = normal

qq_33162534的博客 1270

vue3中h函数的使用

需要注意的是,我们这里的 comp 是一个 vnodes ,而 setup 函数并不是响应式的环境,所以当我们在 setup 函数中调用 h 函数来获取 vnodes 时,h函数是用于创建一个 vnodes ,它既可以用于创建原生元素,也可以创建组件,其渲染后的效果等同于使用模版语言来进行创建。我们可以看到 slots 其实是一个对象,键是插槽的名字,值其实就是一个 渲染函数 h(),这里使用的是一个批量注册的方式导入 HelloWorld 组件,Comp 是一个全局组件。

weixin_39724159的博客 3500

Oracle Linux中/var/log/pcp/pmlogger目录膨胀问题分析与解决

本文详细分析了Oracle Linux系统中/var/log/pcp/pmlogger目录异常膨胀的常见原因与解决方案。当PCP性能监控框架的pmlogger服务日志轮转或清理机制失效时,会导致该目录无限增长,威胁系统稳定。文章提供了从服务状态诊断、配置文件审查到安全清理与预防策略的全流程实战指南,帮助运维人员快速回收磁盘空间并恢复服务正常运行。

weixin_29208327的博客 376

通达信高低点预测主图指标公式

牛股顶55:={分型顶 AND}H=HHV(H,BARSLAST(牛股底54)) AND L>LLV(L,BARSLAST(牛股底54)) AND BARSLAST(牛股顶54)<BARSLAST(牛股底54) AND (BARSNEXT(牛股底54)<BARSNEXT(牛股顶54) OR BARSNEXT(牛股顶54)=DRAWNULL);牛股顶432:=牛股顶431 AND (H=HHV(H,BARSLAST(牛股底431)) OR BARSLAST(牛股底431)=DRAWNULL);

2503_91947154的博客 1397

quartus 13.1常见报错解决方法

在使用quartus中会遇到很多由于安装或设置不规范造成的错误。我就目前我遇到的一些错误以及我的解决方法分享给大家,这个文章将会持续更新,如果读者有遇到软件中错误无法解决的问题,也欢迎在评论区留言。 一、编译出现lience错误 在对设计的电路编译时,系统在程序运行3秒内即结束并报错,大概意思为现有的证书不支持编译。这个常见问题源自破解不成功,这里读者很有可能犯的错误是在使用破解器的时候没有区分x86(即32-bit)和x64软件破解器对应的文件夹。 如图所示有两种破解器,分别对应32位和64位的软件,大部

肥宅的博客 3万+

S7-1500 PLC与多台S7-200SMART PLC进行PROFINET通信的快捷方法

S7-1500 PLC与多台S7-200SMART PLC进行PROFINET通信的快捷方法

Robot_PLC_HMI_Automation 5692

分享 13 个关于 vue3 全局 API 的源码解析

作者 | Tz来源 | https://juejin.cn/post/6979394726927532068前言不知不觉vue-next的版本已经来到了3.1.2,最近对照着源码学习vue...

前端达人 573

新手必看:C#调用YOLO模型完成图片/视频目标检测(上位机版)

新手学习C#调用YOLO模型,核心是先把基础流程跑通,再逐步优化。图片检测是基础,视频检测就是在图片的基础上加循环和线程,而上位机的实际项目,就是在这个基础上适配工业硬件和业务需求。本文的代码都是新手能直接复制运行的,如果你运行时遇到问题,先检查前期准备是否到位,再看避坑指南。记住,新手别追求一步到位,先实现功能,再慢慢优化性能和界面。等你能熟练调用YOLO模型后,再去研究模型训练、量化优化等进阶内容,会轻松很多。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 988

函数式编程、createVNode、render、h 函数

函数式编程、createVNode、render、h 函数

m0_38004751的博客 1048

智能硬件产品 App 全球发布 第 1 章:全球 App 发布战略设计

本章阐述智能硬件 App 全球发布战略,涵盖市场分析、竞争格局、用户画像及资源配置。通过制定可执行的全球化推广路径,整合地区法规合规、渠道分发策略与营销活动设计,助力团队快速进入主流商店并确立品牌影响力。同时构建可量化的 KPI 监控体系,指导项目进度追踪与效果复盘,确保产品迭代持续优化,降低运营总成本。

moton2017的博客 157

fanuc机器人I/O分配

FANUC机器人在和其他外部设备进行通讯时,需要对信号进行配置。 在机器人处于UOP自动分配状态时,系统会自动检索已配对设备,并分配相应的机架号。 当我们需要手动对信号进行分配时,可参考以下机架号进行配置。 不同的通讯协议对应的机架号不同,外部通讯协议常用的机架号参考下表: 序号 机架号 通讯类型 1 0 Process I/O 2 1-15

haier123888的博客 1万+

【Vue.js】900- Vue 3.0 进阶之 VNode 探秘

本文是 Vue 3.0 进阶系列 的第五篇文章,在这篇文章中,阿宝哥将介绍 Vue 3 中的核心对象 —— VNode,该对象用于描述节点的信息,它的全称是虚拟节点(virtual nod...

pingan8787 2965

企业级大数据平台的数据网格(Data Mesh)转型之路

随着企业数字化转型的深入,传统大数据平台面临数据孤岛化、治理成本高、业务响应慢等核心痛点。数据网格作为一种新兴的分布式数据管理架构,通过领域驱动设计(DDD)、数据产品化和联邦治理模式,为企业提供了打破数据壁垒、提升数据生产力的全新路径。本文聚焦企业级数据平台从传统架构(数据湖/数据仓库)向数据网格转型的关键技术、实施步骤和组织配套,涵盖技术架构设计、核心算法实现、项目实战案例及工具链推荐。背景介绍:定义转型目标、术语体系与核心挑战核心概念与联系:解析数据网格四大支柱及技术架构图谱核心算法原理。

AI 领航者的博客 1084

【Vue.js】890- Vue 3.0 进阶之 VNode 探秘

本文是 Vue 3.0 进阶系列 的第五篇文章,在这篇文章中,阿宝哥将介绍 Vue 3 中的核心对象 —— VNode,该对象用于描述节点的信息,它的全称是虚拟节点(virtual nod...

pingan8787 1375

运动想象 (MI) 分类学习系列 (19) : EEG-TransNet

本文提出了一种基于注意力机制的卷积神经网络(EEG-TransNet),用于运动想象脑电图(MI-EEG)解码。该方法创新性地通过平均池化和方差池化提取多模态时间信息,并结合自注意力模块捕获长期依赖关系。消融实验表明,方差池化比最大池化更有效(p<0.05),且注意力模块和卷积编码器对特征判别性至关重要。可视化分析验证了该方法能学习到更具判别性的紧凑特征。该工作为MI-EEG解码提供了新的多尺度时间信息融合视角,代码已开源。

走在深度学习前沿的小宋 359

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Vue3 学习笔记 —— 函数式编程、createVNode、render、h 函数

Vue3 学习笔记 —— 函数式编程、createVNode、render、h 函数

Lyrelion的博客 1万+

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

vue3源码分析

vue

cq1453001422的博客 8301

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

轻松理解 Vue3 编译优化 - 从入门到源码分析

优化方式作用实际效果静态提升提升不变的内容减少创建节点的开销,节省内存Patch Flag标记动态节点精准定位需要更新的内容Block Tree追踪动态节点快速找到动态节点,无需遍历通过这篇文章,我们从生活例子出发,一步步深入到源码实现,相信你已经对 Vue3 的编译优化有了清晰的认识。这些优化不是魔法,而是 Vue 团队在编译阶段和运行时层面的精心设计。记住:优秀的框架就像一个细心的管家,帮我们处理好所有的细节,让我们能专注于业务逻辑的开发。

weixin_43334866的博客 1724

vue3源码分析——实现slots

本期来实现, slot——插槽,分为普通插槽,具名插槽,作用域插槽,所有的源码请查看在 模板中使用插槽的方式如下: 在中的内容最终会被成render函数,render函数里面会调用h函数转化成vnode,在vnode的使用方法如下: 看完slots的基本用法,一起来实现个slots,方便自己理解slots的原理哦!😀😀😀使用slots的地方是this.slots,并且调用的属性是default,那么slots,并且调用的属性是default,那么slots则是一个对象,对象里面有插槽的...

twinkle的博客 3164

vue3源码分析——解密nextTick的实现

本期主要实现了`nextTick()`,通过`nextTick`看到了`vue`更新`dom`的方式是异步的。并且在这种方式的基础之上,需要使用到**js的事件循环**,在事件循环中**微任务比宏任务的优先级更高**。所以**nextTick使用的是微任务方式来更新dom** 。 看似不到20行的代码,里面却包含着这么多知识点,只能说大佬就是大佬,灵活运用👍👍👍...

twinkle的博客 976

vue3源码分析——实现组件的挂载流程

接下来一起学习下,runtime-core里面的方法,本期主要实现的内容是,通过createApp方法,到mount最后把咋们的dom给挂载成功!,所有的源码请查看咋们需要使这个测试用例跑成功!,在图中可以发现,调用app传入了一个render函数,然后挂载,对比期望结果!思考再三,先把这一节先说了,jest是怎么来测试dom的?默认的环境是,在中可以看到npm有在node中实现了浏览器环境的api的库,jsdom、happy-dom 等,咋们这里就使用比较轻的happy-dom,但是hap...

twinkle的博客 1507

vue3源码分析——实现element属性更新,child更新

本期来实现, vue3更新流程,更新元素的props,以及更新元素的child,所有的源码请查看在上面流程图中,如果在中有一个对象,并且赋值为 ,然后通过某种方式重新赋值为2,就会触发更新流程;effect收集依赖肯定是在里面,但是具体在哪里呢?在中,里面有三个函数看到上面三个函数,想必大家都知道是在哪个函数进行effect了吧!😊😊😊 属性更新 属性更新,毫无疑问的是,元素中的属性进行更新,新增,修改和删除等! 分析 通过上面的需求,分析以下内容:问题解决: 更新children...

twinkle的博客 1114

vue-org-tree 组织结构图组件应用及源码分析

需求: 最近业务需要做类似思维导图的组织结构树功能,需要能动态增删改节点,且每层的节点样式并不相同 可用插件: 网上能找到的组织结构图插件有: 1.orgchart.js 地址:https://github.com/dabeng/OrgChart.js 这个缩进方式太另类了,个人不喜欢; 2.vue-orgchart 地址:https://github.com/spiritre...

lianzhang861的博客 1万+

vue3源码分析 -- runtime

runtime运行时,主要在目录下,核心提供了hrender等函数。在理解它们之前,我们需要了解下HTML DOM 树和虚拟 DOM等概念。

triggerV的博客 695

vue3源码分析——实现组件更新

前面的两期主要是实现,的更新除了的更新外,还有的更新哦,本期就带大家一起来看看,本期所有的源码请查看vue3在更新element的时候,除了需要分情况讨论更新children外,还需要来看vue3的属性有没有变化;那么同样的道理,对于组件的更新,也是需要来更新属性,插槽等根据上面的流程图,可以写出这样的测试用例 分析 根据上面的流程图,可以分析出下面的需求问题解决:方法的调用肯定是在中的存在的时候来调用,里面需要进行新老节点的对比,判断是否需要进行更新.更新则调用去更新vnode的props...

twinkle的博客 1142

vue3源码分析(一)—— 项目架构目录

文章目录前言源码目录 前言 Vue.js 3.0 (以下简称Vue3),正式发布在 2020 年 09 月 18 日 相关资料: vue3源码地址:https://github.com/vuejs/vue-next vue3迁移指南:https://v3.cn.vuejs.org/guide/migration/introduction.html vue3官方文档:https://v3.cn.vuejs.org/guide/introduction.html vue3在线编译调试:http://vue

娃哈哈_的博客 7034
上一篇: Element UI 设置 el-table-column 宽度 width 为百分比无效
下一篇: Vue中 toRaw 和 markRaw 的使用
ZoeLandia
博客等级 码龄6年 734粉丝 183原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值