浅析 v-node

浅析 v-node

🌈 本节我们来探索一下虚拟DOM,将会从以下4个方面进行阐述:

  1. 虚拟DOM的本质
  2. 虚拟DOM的优势
  3. 虚拟DOM转换真实DOM 过程
  4. 虚拟DOM树 diff算法

虚拟DOM的本质

⭐️虚拟DOM 本质上是一个 js 对象,用于描述页面的结构,在 Vue 中,每个组件都有一个render函数,每一个 render 函数运行会返回一棵虚拟DOM树

打印一下虚拟DOM👇
vnode

虚拟DOM的优势

  1. 当组件的 依赖数据 变化时,该组件需要重新渲染,去重新运行render函数,得到一棵新的虚拟DOM树,将新旧两棵树进行对比,通过 patch 算法,做到最小量更新。
  2. 如果每次渲染去对真实DOM的创建、更新、插入是非常消耗性能的,降低渲染效率,用虚拟DOM代替真实DOM,解决了渲染效率的问题。

虚拟DOM转换真实DOM 过程

  1. 当组件首次渲染时,它会先生成虚拟DOM树,然后根据虚拟DOM树创建真实DOM,并把真实DOM挂载到页面中合适的位置,此时,每个虚拟DOM便会对应一个真实的DOM。(首次渲染,虚拟DOM优势不是很大,比操作真实DOM多了一个构建虚拟DOM树的过程,在后续更新过程中,优势变得更大。)
  2. 如果组件不是首次渲染,依赖数据发生变化,则需要重新渲染,重新调用render函数,创建出一个新的虚拟DOM树,用新树和旧树对比,通过内部patch函数,vue会找到最小更新量,然后更新必要的虚拟DOM节点,最后,这些更新过的虚拟节点,会去修改它们对应的真实DOM,做一些属性上的更新,保证了树的稳定和最小量更新。

虚拟DOM树 diff 算法

  1. diff发生的时机

    是在组件实例创建时,以及依赖的属性或数据变化时,会运行一个函数,该函数会做两件事:

    • 运行_render生成一棵新的虚拟dom树(vnode tree)
    • 运行_update,传入虚拟dom树的根节点,对新旧两棵树进行对比,最终完成对真实dom的更新

    核心代码如下:

    // vue构造函数
    function Vue(){
      // ... 其他代码
      var updateComponent = () => {
        this._update(this._render())
      }
      // ... 其他代码
    }
    

    diff就发生在_update函数的运行过程中

  2. _update函数在干什么

    _update函数接收到一个vnode参数,这就是生成的虚拟dom树

    同时,_update函数通过当前组件的_vnode属性,拿到的虚拟dom树

    _update函数首先会给组件的_vnode属性重新赋值,让它指向新树

    然后会判断旧树是否存在:

    • 不存在:说明这是第一次加载组件,于是通过内部的patch函数,直接遍历新树,为每个节点生成真实DOM,挂载到每个节点的elm属性上

    • 存在:说明之前已经渲染过该组件,于是通过内部的patch函数,对新旧两棵树进行对比,以达到下面两个目标:

      • 完成对所有真实dom的最小化处理
      • 让新树的节点对应合适的真实dom
  3. patch函数的对比流程

    1. 相同:是指两个虚拟节点的标签类型、key值均相同,但input元素还要看type属性,具体实现如下👇:
    function sameVnode (a, b) {
        return (
            a.key === b.key && (
            (
                a.tag === b.tag &&
                a.isComment === b.isComment &&
                isDef(a.data) === isDef(b.data) &&
                sameInputType(a, b)
            ) || (
                isTrue(a.isAsyncPlaceholder) &&
                a.asyncFactory === b.asyncFactory &&
             isUndef(b.asyncFactory.error)
                )
            )
        )
    }
    function sameInputType (a, b) {
        if (a.tag !== 'input') return true
        let i
        const typeA = isDef(i = a.data) && isDef(i = i.attrs) && i.type
        const typeB = isDef(i = b.data) && isDef(i = i.attrs) && i.type
        return typeA === typeB || isTextInputType(typeA) && isTextInputType(typeB)
    } 
    
    1. 新建元素:根据一个虚拟节点提供的信息,创建一个真实dom元素,并且挂载到该虚拟节点的elm属性上
       fucntion create(){
         // 其他代码... 
         // ns 表示 namespace
         vnode.elm = vnode.ns
         ? nodeOps.createElementNS(vnode.ns, tag)
         : nodeOps.createElement(tag, vnode)
       }
    
    1. 销毁元素:通过vnode.elm.remove()方法进行销毁
    2. 更新:两个虚拟节点进行对比更新,它仅发生在两个虚拟节点相同的情况下,做一些属性的更新
    3. 对比子节点:两个虚拟节点的子节点进行对比
    function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
     // 为新旧两棵树分别创建首位两个指针,遍历的同时做 删除和新建操作
     let oldStartIdx = 0 
     let newStartIdx = 0
     let oldEndIdx = oldCh.length - 1
     let newEndIdx = newCh.length - 1
     // 首先判断 key值,tag类型,再做相应的 创建 删除 更新操作
     // 其他代码....
     }
    

    diff过程:

    1. 根节点对比
      patch函数先对根节点进行对比
      如果两个节点
    • 相同,则进入更新流程
      1. 将旧节点的真实dom赋值到新节点:newVnode.elm = oldVnode.elm
      2. 对比新节点和旧节点的属性,有变化的更新到真实dom中
      3. 当前两个节点处理完毕,开始对比子节点
    • 不相同
      ⭐️ vue会认为这是两棵不一样的树,直接旧树不要,根据新树创建元素
      1. 新节点递归 新建元素
      2. 旧节点销毁元素
    1. 对比子节点

    对比子节点时,vue一切的出发点,都是为了最小量更新,尽量做到只是元素的移动,属性的更新,实在不行只能新建和删除元素。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
docker-compose 是 Docker 官方的一个用于定义和运行容器化应用的工具。它使用 YAML 文件来配置应用的服务、网络和卷等方面的设置。 当使用 docker-compose 部署 MySQL 时,可能会遇到无法访问 MySQL 的问题。出现这种情况一般有以下几个可能的原因: 1. 网络配置问题:docker-compose 在默认情况下会创建一个默认的网络,并将所有定义的服务连接到该网络。如果服务的网络配置不正确,可能导致无法访问 MySQL。可以通过检查网络配置或创建自定义网络来解决此问题。 2. 端口映射问题:MySQL 默认使用 3306 端口进行通信,但是在容器内部的端口与宿主机上的端口之间可能存在映射问题。可以通过检查端口映射配置或使用容器的 IP 地址来解决此问题。 3. 认证问题:MySQL 服务通常需要进行身份验证才能访问。在 docker-compose 文件中,可以通过设置环境变量来指定 MySQL 的用户名和密码。如果未正确设置这些环境变量,可能导致无法访问 MySQL。可以检查环境变量配置或者在容器内部手动配置用户名和密码来解决此问题。 4. 容器启动顺序问题:如果在 docker-compose 文件中定义了多个服务,并且它们之间有依赖关系,那么容器启动的顺序可能会影响 MySQL 的访问。可以通过在容器之间添加依赖或者设置延迟启动来解决此问题。 总结起来,当 docker-compose 部署的 MySQL 无法访问时,通常是由于网络配置、端口映射、认证配置或容器启动顺序等问题造成的。通过检查这些配置,并进行适当的调整或修复,通常可以解决无法访问 MySQL 的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值