![](https://img-blog.csdnimg.cn/20201014180756780.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
vue设计与实现 笔记
文章平均质量分 66
内容来自于《vue设计与实现》
loyd3
不加微信捏
展开
-
【vue设计与实现】解析器 - 解析文本与解码HTML实体
如上面的代码所示,由于字符原创 2023-01-15 15:24:45 · 2130 阅读 · 0 评论 -
【vue设计与实现】解析器 - 解析属性
上面这段内容才是 parseAttributes 函数要处理的内容。由于该函数只用来解析属性和指令因此会不断地消费上面这段模板内容,直到遇到标签的“结束部分”为止。其中,结束部分指的是字符>或者字符串 />。上面这段代码的关键点之一是,需要在消费标签的“开始部分”和无用的空白字符之后再调用 parseAttribute 函数。用来匹配没有使用引号引用的属性值, 该正则表达式会一直对字符串进行匹配,直到遇到空白字符或字符>为止,实际上,parseAttributes 函数消费模板内容的过程,就是不断地解析。原创 2023-01-08 19:20:03 · 394 阅读 · 0 评论 -
【vue设计与实现】解析器 - 解析标签节点
在经过上述处理后,parseTag 函数会返回一个标签节点。parseElement 函数在得到由parseTag 函数产生的标签节点后,需要根据节点的类型完成文本模式的切换,如下面的代码所示。至此,就实现了对标签节点的解析。原创 2023-01-05 12:36:49 · 412 阅读 · 0 评论 -
【vue设计与实现】解析器 - 状态机的开启与停止
前面介绍了,在调用parseElement函数解析标签节点时,会递归地调用parseChildren函数,从而开启新的状态机。在状态机都执行完成后,这时父级节点栈为空,状态机全部停止运行,模板解析完毕。对于第一种解释方式,我们得到的错误信息是“无效的结束标签”。换句话说,按照我们当前的实现思路来解析上述例子中的模板,最终得到的错误信息是:“无效的结束标签”。可以看到模板中存在一段完整的内容我们希望解析器可以正常对其进行解析,这很可能也是符合用户意图的。,为了搞清楚这个问题,我们需要模拟状态机的运行过程。原创 2023-01-04 08:39:07 · 383 阅读 · 4 评论 -
【vue设计与实现】解析器 - 文本模式及其对解析器的影响 & 递归下降算法构造模板 AST
文本模式指的是解析器在工作时所进人的一些特殊状态,。当解析器遇到一些特殊标签时,会切换模式,这些特殊标签是:遇到,会切换到遇到会切换到遇到标签,因此 Vue.is 模板解析器在遇到标签时也会换到模式解析器的行为会因工作模式的不同而不同在模式下,解析器能够处理。当解析器处于状态时,解析器不能识别标签元素。解析器在模式下的工作方式与在模式下类似。原创 2023-01-01 19:23:24 · 456 阅读 · 1 评论 -
【vue设计与实现】编译器 - 代码生成
这里将讨论如何根据JavaScript AST生成渲染函数的代码,即代码生成。需要访问JavaScript AST中的节点,为每一种类型的节点生成相符的 JavaScript代码。genFunctionDecl函数用来为函数声明类型的节点生成对应的 JavaScript代码。配合上述生成器函数的实现,就能得到符合语气的渲染函数代码,用下面的代码测试。这里要注意的一点是,每处理完一个节点,需要在生成的代码后面拼接逗号。对于 genFunctionDecl 函数,另外需要注意的是,原创 2022-12-30 19:51:38 · 1430 阅读 · 3 评论 -
【vue设计与实现】编译器 - 将模板 AST转为 JavaScript AST
而谊染函数是由 JavaScript代码来描述的,因此,我们需要将模板 AST转换为用于描述渲染函数的JavaScript AST。使用上面两个转换函数即可完成标签节点和文本节点的转换,即把模板转换成 h 函数的调用。但是,转换后得到的 AST 只是用来描述渲染函数 render 的返回值的,所以我们最后一步要做的就是,上面这段渲染函数的JavaScript代码所对应的JavaScript AST 就是我们的转换目标。如上面这段 JavaScript AST的代码所示,它是对渲染函数代码的完整描述。原创 2022-12-29 15:40:59 · 768 阅读 · 0 评论 -
【vue设计与实现】编译器 - 转换上下文与节点操作 & 进入与退出
节点替换是在对AST进行转换的时候,把某些节点替换为其他类型的节点。上面代码的关键点在于,在递归地调用 traverseNode 函数进行子节点的转换之前,必须设置 context.parent 和 context.childIndex 的值,这样才能保证在接下来的递归节点替换转换中,context对象所存储的信息是正确的。接下来,我们就可以在转换函数中使用 replaceNode函数对 AST中的节点进行。这里有一点需要注意,由于当前节点被移除了,所以后续的转换函数将不再需要处理该节点。原创 2022-12-25 20:00:18 · 603 阅读 · 0 评论 -
【vue设计与实现】编译器 - AST的转换
可以看到,解耦之后,节点操作封装到了 transformELement和 transformText 这样的独立函数中。接着,我们把回调函数存储到context.nodeTransforns 数组中,然后遍历该数组,并逐个调用注册在其中的回调函数。答案是“当然可以”,我们可以使用回调函数的机制来实现解耦,如下面代码所示。为了对AST进行转换,我们需要能访问AST 的每一个节点,这样才有机会对特定节点进行修改、替换、删除等操作。新的AST可以是原语言或原DSL的描述,也可以是其他语言或其他DSL的描述。原创 2022-12-22 11:18:23 · 556 阅读 · 0 评论 -
【vue设计与实现】编译器 - 构造AST
因此,一棵用于描述HTML的AST将拥有与HTML标签非常相似的树型结构。根据Token列表构建AST的过程,其实就是对 Token列表进行扫描的过程。从第一个Token开始,顺序地扫描整个 Token列表,直到列表中的所有 Token处理完毕。实际上,不同用途的编译器之间可能会存在非常大的差异。了解了AST的结构,接下来的任务是,使用程序根据模板解析后生成的Token构造出这样一棵AST。可看到,AST在结构上与模板是“同构”的,它们都具有树型结构,这样,栈顶的节点将始终充当父节点的角色。原创 2022-12-20 10:37:57 · 594 阅读 · 1 评论 -
【vue设计与实现】编译器 - parser的实现原理与状态机
总而言之,通过有限自动机,我们能够将模板解析为一个个Token,进而可以用它们构建一棵AST了。但在具体构建AST之前,我们需要思考能否简化 tokenzie 函数的代码。解析器的入参是字符串模板,解析器会逐个读取字符串模板中的字符,并根据一定的规则将整个字符串切割为一个个Token。所谓“有限状态”,就是指有限个状态,而自动机意味着随着字符的输人,解析器会自动地在不同状态间迁移。,后续我们将使用Token一词来代表吃法记号进行讲解。,当你编写正则表达式的时候,其实就是在编写有限自动机。原创 2022-12-19 08:50:28 · 991 阅读 · 0 评论 -
【vue设计与实现】编译器 - 基本的编译技术
在语义分析的基础上,我们即可得到模板 AST。因为Vuejs 模板编译器的最终目标是生成渲染函数,而渲染函数本质上是JavaScript代码,所以我们需要将模板AST转换成用于描述渲染函数的JavaScript AST。详细来说,Vue.js模板编译器会首先对模板进行词法分析和语法分析,得到模板AST。对于vue.js模板编译器来说,源代码就是组件的模板,而目标代码是能够在浏览器平台上运行的JavaScript代码,或其他拥有JavaScript运行时的平台代码,Vue.js模板编译器的目标代码其实就是。原创 2022-12-18 22:19:55 · 561 阅读 · 0 评论 -
【vue设计与实现】内部组件和模块 2 - 缓存管理
在KeepAlive组件的内部实现中,如果用户提供了自定义的缓存实例,则直接使用该缓存实例来管理缓存。从本质上来说,这等价于将缓存的管理权限从KeepAlive组件转交给用户了。在上面这段代码中,设置缓存的容量为2,假设有三个组件Comp1,Comp2,Comp3,并且他们都会被缓存。该Map对象的键也就是vnode.type的值,值是用于描述组件的vnode对象。可以看到,在不同的模拟策略下,最终的缓存结果会有所不同。这会导致缓存不断增加,极端情况下会占用大量内存。还可以换一种切换组件的方式,如下所示。原创 2022-12-16 11:03:13 · 309 阅读 · 0 评论 -
【vue设计与实现】内部组件和模块 1 - KeepAlive组件的实现原理
组件的激活和失活KeepAlive一词来自于HTTP协议,在HTTP协议里,KeepAlive又称HTTP持久链接(HTTP persistent connection),其作用是允许多个请求或响应共用一个TCP连接。如果没有KeepAlice,一个HTTP连接会在每次请求/响应结束后关闭,当下一次请求发生时,会建立一个新的HTTP连接,频繁地销毁,创建HTTP连接会带来额外的性能开销,KeepAlive就是为了解决这个问题的。原创 2022-11-18 10:32:13 · 329 阅读 · 0 评论 -
【vue设计与实现】异步组件与函数式组件 5 - 函数式组件
首先,在mountComponent函数内检查组件的类型,如果是函数式组件,则直接将组件函数作为组件选项对象的render选项,并将组件函数的静态props属性作为组件的props选项即可。函数式组件没有自身状态,但仍然可以接收由外部传入的props。当然,出于更加严谨的考虑,我们需要通过isFunctional变量实现选择性地执行初始化逻辑,一个函数式组件本质上就是一个普通函数,该函数的返回值是虚拟DOM。在patch函数内部,通过检测vnode.type的类型来判断组件的类型。原创 2022-11-17 09:46:00 · 298 阅读 · 0 评论 -
【vue设计与实现】异步组件与函数式组件 4 - 重试机制
这样,用户就可以在错误发生时主动选择重试或直接抛出错误。重试指的是当加载出错时,有能力重新发起加载组件的请求。load函数内部调用fetch函数来发送请求,原创 2022-11-16 13:35:26 · 421 阅读 · 0 评论 -
【vue设计与实现】异步组件与函数式组件 3 - 延迟与Loading组件
如果从加载开始的一开始就展示Loading组件,那么在网络状况好的情况下,异步组件的加载速度会非常快,这会导致Loading组件刚完成渲染就立即进入卸载阶段,于是出现闪烁的情况。这样体验特别不好,因此。异步组件加载过程可能很慢,所以可以通过展示Loading组件来提供更好的用户体验,这样用户就不会有“卡死”的感觉了。要注意的是,在渲染函数中,如果组件正在加载,并且用户指定了Loading组件,则渲染该Loading组件。例如,当超过200ms没有完成加载,才展示Loading组件。这样就能避免闪烁问题。原创 2022-11-14 08:48:52 · 1003 阅读 · 0 评论 -
【vue设计与实现】异步组件与函数式组件 2 - 超时与Error组件
在组件渲染时,只要error.value的值存在,且用户配置了errorComponent组件,就直接渲染errorComponent组件并将error.value的值作为该组件的props传递,在弱网环境下,加载一个组件可能需要很长时间,因此,要为用户提供指定超时时长的能力,当加载组件的时间超过了指定时长后,会触发超时错误。首先设计用户接口,为了让用户能够指定超时时长,defineAsyncComponent函数需要接受一个。这样就实现了对加载超时的兼容,以及对Error组件的支持。原创 2022-11-11 09:15:36 · 481 阅读 · 0 评论 -
【vue设计与实现】异步组件与函数式组件 1 - 异步组件要解决的问题和实现
异步组件,异步两个字指的是,以异步的方式加载并渲染一个组件。这在代码分割、服务端下发组件等场景中尤为重要。原创 2022-11-10 08:24:41 · 388 阅读 · 0 评论 -
【vue设计与实现】组件的实现原理 5 - 插槽的工作原理与实现 & 注册生命周期
这里的疑问在于,在A组件的setup函数中调用onMounted函数会将该钩子函数注册到A组件上,而在B组件的setup函数中调用onMounted函数会将该钩子函数注册到B组件上。可以看到,只需要再合适的时机遍历instance.mounted数组,并逐个执行该数组内的生命周期钩子函数即可。在运行的实现上,插槽则依赖于setupContext中的slot对象,如下面代码所示。有了这些之后,就可以着手修改mountComponent函数,如下面的代码所示。组件时,可以根据插槽的名字来插入自定义的内容。原创 2022-11-07 08:42:46 · 346 阅读 · 0 评论 -
【vue设计与实现】组件的实现原理 4 - setup函数的作用与实现 & 组件事件与emit的实现
可以看到,自定义事件change被编译成名为onChange的属性,并存储在props数据对象中,这实际上是一种约定。这里要额外注意的是,在介绍props时提到,任何没有显式声明未props的属性都会存储到attrs中,也就是说,其中props为外部为组件传递的props数据对象,setupContext保存着与组件接口相关的数据和方法。组件的setup函数时Vue.js3新增的组件选项,setup函数主要用来配合组合式API,当使用该组件时,可以监听由emit函数发射的自定义事件。原创 2022-11-04 09:01:55 · 876 阅读 · 1 评论 -
【vue设计与实现】组件的实现原理 3 - props与组件的被动更新
上面的实现中,没有处理attrs与slots的更新,attrs的更新本质上与更新props的原理相似。本质上,原理都是根据组件的props选项定义以及为组件传递的props数据来处理。我们将组件选项中定义的MyComponent.props对象和为组件传递的vnode.props对象想结合,最终解析出组件在渲染时需要使用的props和attrs数据。在虚拟DOM层面,组件的props与普通HTML标签的属性差别不大。另外,在编写组件时,由于props数据与组件自身的状态数据都需要暴露到渲染函数中,并。原创 2022-11-03 10:40:06 · 1332 阅读 · 0 评论 -
【vue设计与实现】组件的实现原理 2-组件实例与组件的生命周期
组件实例本质上就是一个状态集合(或一个对象),它维护这组件运行过程中的所有信息,例如:注册到组件的生命周期函数,组件渲染的子树(subTree),组件是否被挂载等等。为了解决上一节中关于组件更新的问题,需要引入组件实例的概念,以及与之相关的状态信息,如下面代码:一个组件实例本质上就是一个对象实际上,在需要的时候,可以任意地在组件实例instance上添加需要的属性,但是要注意保持组件实例轻量,减少内存占用。现在可以通过instance.isMounted属性来区分组件的挂载和更新,因此,可以在合适的时机调原创 2022-10-31 10:28:01 · 167 阅读 · 0 评论 -
【vue设计与实现】组件的实现原理 1-渲染组件&组件状态与自更新
但是上面的代码还存在缺陷,注意看effect函数内调用patch函数完成渲染时,第一个参数总是null,也就是,每次更新发生时都会进行全新的挂载,而不会打补丁,这样是不对的,通过组件,可以将一个大的页面拆分为多个部分,每个部分都可以作为单独的组件,这些组件共同组成完整的页面。要解决这个问题,就需要实现组件实例,用它来维护组件整个生命周期的状态,这样渲染器才能在正确的时机执行合适的操作。但是这样多次修改响应式数据的值,就会导致渲染函数执行多次,这实际上是没有必要的,所以需要一个调度器,原创 2022-10-25 13:07:53 · 728 阅读 · 0 评论 -
【vue设计与实现】快速Diff算法 3-如何移动元素
而子序列中的元素在原序列中不一定连续。一个序列可能有很多个递增子序列,其中最长的一个就称为最长递增子序列。当然,对于同一个数值序列来说,其最长递增子序列可能有多个,例如在[0,8,4,12] 中 最长递增子序列是[0,8,12] 也可以是[0,4,12]在代码中可以是用lis函数获取最长递增子序列,并且lis函数返回的结果是最长递增子序列中的元素在参数数组中的位置索引。而[0,1] 对应的是 最长递增子序列在数组中的索引[2,3]有了最长递增子序列的索引信息后,下一步就要重新对节点进行编号。原创 2022-10-10 08:59:50 · 432 阅读 · 0 评论 -
【vue设计与实现】快速Diff算法 2-判断是否需要进行DOM移动操作
在经过预处理后,无论是新子节点,还是旧子节点,都有部分节点未经处理,这时候旧需要进行进一步的处理。之前关于快速Diff算法的例子比较理想化,也就是处理完相同的前置节点或后置节点后,新旧两组子节点总会有一组子节点被全度处理完毕。这里要注意的是,由于数组source的索引是从0开始的,而未处理节点的索引则未必是从0开始的,所以在填充数组时要使用表达式。这里要注意的事,由于数组source的索引是从0开始的,而未处理节点的索引则未必是从0开始的,所以在填充数组时要使用表达式。的值作为数组的索引值。原创 2022-10-08 09:16:00 · 279 阅读 · 0 评论 -
【vue设计与实现】快速Diff算法 1
可以看到最后还遗留一个未被处理的节点p4,可以看到,节点p4是一个新增节点,那么程序是如何得出“节点p4是新增节点的”,这里就需要观察三个索引j,newEnd和oldEnd之间的关系。对于相同的前置节点和后置节点,由于在新旧子节点中的相对位置不变,所以不需要移动,但还是要再它们之间打补丁。条件一和条件二同时成立时,说明在新的一组子节点中,存在遗留节点,且这些节点都是。对于前置节点,可以建立索引j,其初始值为0,用来指向两组子节点的开头。可以发现,两组子节点有相同的前置节点p1和相同的后置节点p3和p4。原创 2022-09-28 10:20:27 · 535 阅读 · 0 评论 -
【vue设计与实现】双端Diff算法 3-添加新元素 & 移除元素
在前面的章节,非理想情况的处理,即在一轮比较过程中,不会命中四个步骤的任何一步。这时,拿新的一组子节点中的头部节点去旧的子节点中寻找可复用的节点,并非总是能找得到。例如下面的例子:旧子节点: p1,p2,p3新子节点:p4,p1,p3,p2首先进行第一轮比较,发现在四个步骤的比较中都找不到可复用的节点。于是用新子节点的头部节点p4去旧子节点中寻找相同key值的节点,发现在旧的子节点中根本就没有p4节点。原创 2022-09-26 16:07:06 · 539 阅读 · 0 评论 -
【vue设计与实现】双端Diff算法 2-非理想状况的处理方式
在上面的例子 新子节点的头部节点p2 会在旧子节点的索引为1的位置找到可复用的节点,也就是说更新后,p2应该变成头部节点。由于都是头部节点,因此不需要进行DOM移动操作,直接打补丁即可,这样就更新完成,最终,真实DOM节点的顺序与新的一组子节点的顺序一致。接着开始下一步的比较,发现在第一步旧子节点的头部节点p1和新子节点的头部节点p1,两者的key值相同,可以复用。这样做其实就是,在旧的一组子节点中找到与新的一组子节点的头部节点具有相同key值的节点。旧的一组子节点:[p1,p2,p3,p4]原创 2022-09-23 13:31:52 · 318 阅读 · 0 评论 -
【vue设计与实现】双端Diff算法 1-双端比较的原理和优势
前面介绍了简单Diff算法的实现原理,虽然简单Diff算法有很多有点,但是缺陷也很多,这些缺陷可以通过双端Diff算法解决简单Diff算法的问题在于,对DOM的移动操作并不是最优的,有时理论上只需要移动一次的DOM操作,使用简单Diff算法却移动了两次,而双端Diff算法就可以做到。顾名思义,双端Diff算法是一种同时对新旧两组子节点的两个端点进行比较的算法,因此需要四个索引值来分别指向新旧两组子节点的端点。原创 2022-09-16 16:04:06 · 1022 阅读 · 0 评论 -
【vue设计与实现】简单Diff算法 4-添加新元素 & 移除不存在的元素
新的子节点组多了一个节点,而旧的一组子节点没有这个节点,因将其视为新增节点。原创 2022-09-09 08:56:11 · 176 阅读 · 0 评论 -
【vue设计与实现】简单Diff算法 3-找到需要移动的元素 & 移动元素
现在我们能够通过key值找到可复用的节点,但是如何判断一个节点是否需要移动,以及如何移动。对于第一个问题,可以先这么想:在什么情况下节点不需要移动?其实很简单,。更新算法在进行时,每一次寻找可复用的节点时,都会记录该可复用节点在旧的一组子节点的。如果发现旧的子节点和新的子节点位置索引不同,则节点是需要移动的。。。可以用。原创 2022-09-08 15:46:38 · 364 阅读 · 0 评论 -
【vue设计与实现】简单Diff算法 2-DOM复用与Key的作用
但是想要通过DOM的移动来完成更新,必须要保证一个前提,新旧两组子节点中的确存在可复用的节点。那么,应该如何确定新的子节点是否出现在就的一组子节点中,有一种方案是通过vnode.type来判断,只要vnode.type的值相同,就认为是相同的节点,但是这样不靠谱,如果vnode相同,而children不同呢。使用之前的算法来的话,需要6次DOM操作,因为类型不同,需要卸载旧节点后再加载新节点,这样每更新一个节点就需要两次DOM操作。但是通过观察可以发现,两组节点只是顺序不一样,所以最优的处理方式是,原创 2022-09-07 09:38:16 · 229 阅读 · 0 评论 -
【vue设计与实现】简单Diff算法 1-减少DOM操作的性能开销
这种做法问题也很明显,这里假定的是新的一组子节点的数量和旧的相同,但是新旧两组子节点的数量未必相同。类似地,新的一组子节点的数量也可以比旧的多,这时候应该挂在新增节点。之前针对两组子节点的更新,采用了一种简单直接的手段,即卸载全部旧子节点,再挂在全部新子节点。关于Diff算法,简单来说,当新旧vnode的子节点都是一组节点的时候后,为了以最小的性能开销完成更新操作,需要比较两组子节点,用于比较的算法就叫Diff算法。因此,在更新时,不应该是遍历旧的一组子节点,而是遍历其中长度较短的那一组。原创 2022-09-05 13:20:14 · 483 阅读 · 0 评论 -
【vue设计与实现】挂载和更新 8-文本节点和注释节点
这样就能用vnode来描述文本节点和注释节点了。由于文本节点和注释节点只关心文本内容,所以用vnode.children来存储它们对应的文本内容。注意这里使用的是文本节点的nodeValue属性来完成文本内容的更新。,注释节点和文本节点。那么如何用vnode描述注释节点和文本节点?上面的代码中包含,元素节点。原创 2022-08-24 08:49:00 · 360 阅读 · 0 评论 -
【vue设计与实现】挂载和更新 7-更新子节点
注意这里在挂载的时候要区分子节点类型,为什么要区分子节点的类型?其实这是一个规范性问题,因为只有子节点的类型是规范化的,才有利于编写更新逻辑。那么应该怎么规范化vnode.children,在搞清楚这个问题之前,先要搞清楚一个HTML页面中,元素的子节点都有哪些情况。因此渲染器执行更新时,新旧子节点都分别是三种情况之一。因此可以总结出更新子节时有九种可能。(新节点有三种情况,旧节点也有三种情况,组合起来用九种情况)一个元素的子节点无非以下三种情况。如何更新元素的子节点。原创 2022-08-23 08:52:58 · 356 阅读 · 0 评论 -
【vue设计与实现】挂载和更新 6-事件冒泡与更新时机问题
由于bol是一个响应式数据,所以当值发生变化的时候,会触发副作用函数重新执行,在更新截断,渲染器会为父级div元素绑定click事件处理函数。最后,比较两者,如果事件处理函数被绑定的时间晚于事件发生的时间,则不执行该事件处理函数。,但根据浏览器的不同,e.timeStamp的值会有所不同,既可以是高精时间也可能是非高精时间。理论上来说,在首次渲染完成之后,由于bol.value的值为false,所以渲染器不会为div元素绑定点击事件。而p元素具有click点击事件,并且当点击它时,事件处理函数会将。...原创 2022-08-16 14:20:22 · 255 阅读 · 0 评论 -
【vue设计与实现】挂载和更新 5-事件的处理
使用数组来描述事件,数组中每个元素都是一个独立的事件处理函数,并且这些事件处理函数都能正确地绑定到对应元素上。当invoker函数执行时,在调用真正的事件处理函数之前,先检查invoker.value的数据结构是否是数组,如果是数组则遍历它,并逐个调用定义在数组中的事件处理函数。也就是说,如果一个元素同时绑定了多种事件,将会出现事件覆盖的现象。但目前的实现仍然存在问题,现在将事件处理函数缓存在el._vei属性中,但。,因此可以约定,在vnode.props对象中,,这样就不会发生事件覆盖的现象了。...原创 2022-08-08 13:17:39 · 399 阅读 · 0 评论 -
【vue设计与实现】挂载和更新 4-卸载操作&区分vnode的类型
就比如说,初次渲染的vnode是一个p元素,后续又渲染了一个input元素,这就会造成新旧vnode描述的内容不同,即vnode.type属性的值不同。从上面的代码可以看到,调用createElement函数创建真实DOM元素时,会把真实DOM元素赋值给vnode.el属性,这样就在vnode和真实DOM元素之间建立了联系,因此有了这些只需要根据虚拟节点对象。如果后续渲染时,为render函数传递了新的vnode,则不会进行卸载操作,而是把新旧vnode都传递给patch函数进行。更新的情况有好几种,...原创 2022-08-04 20:07:21 · 776 阅读 · 0 评论 -
【vue设计与实现】挂载和更新 3-class的处理
正因为class的值是多种类型的,所以必须在设置元素的class之前将值转化为统一的字符串形式,再把改字符串作为元素的class值去设置。通过对class的处理,可以看到vnode.props对象中定义的属性值的类型并不总是和DOM元素属性的数据结构保持一致,这取决于上层API的设计。在获得正常化的class值后,接下来就是如果将其设置到元素上,而在浏览器中为一个元素设置class有三种方式,即setAttribute,el.className和el.classList,而其中。其对应的vnode是。...原创 2022-08-01 08:27:58 · 386 阅读 · 0 评论