vue常见问题2

202 阅读15分钟
vue生命周期

创建阶段

  1. beforeCreate

    • 实例初始化之前调用,数据观察( reactive )和事件尚未初始化
    • 常用语初始化非响应式属性或插件相关的配置。
  2. created

    • 实例创建完成,datamethods 可用
    • 模板还未挂在到DOM, this.$el 不可用
    • 常用场景:发起数据请求、初始化数据。

    挂载阶段

  3. beforeMount

  • 模板挂载到DOM之前调用,$el 和虚拟DOM已经创建
  • 很少使用,试用查看模板渲染前的状态。
  1. mounted

    • 模板挂载到DOM后调用,$el 已经替换成真实DOM
    • 常用场景:依赖操作DOM的请求或初始化第三方插件(如图表、动画)

    更新阶段

  2. beforeUpdate

    • 数据更改触发虚拟DOM更新,但虚拟DOM还没重新渲染(尚未应用到真实DOM)。
    • 可用来调试更新的中间状态,适合调试或在更新前作额外处理。
  3. updated

    • 数据更新并重新渲染DOM之后调用。
    • 通常不建议在此阶段操作DOM,因为可能会引起无限更新循环。

    销毁阶段

  4. beforeDestroyVue2) / onBeforeUnmount (Vue3)

    • 实例销毁前调用
    • 可用于清楚计时器、事件监听等
  5. destroyedVue2)/ onUmmounted (Vue3)

    • 实例销毁后调用,事件监听器解绑,子组件销毁。

Vue 2 和 Vue 3 生命周期对照表

​ 在Vue3中,生命周期钩子通过组合式API替代,如下表所示:

vue2生命周期Vue3组合式APIVue3选项式API描述
beforeCreate--实例初始化之前,数据和事件还未初始化
created--实例创建完成,数据和方法已初始化,但模板未挂载
beforeMountonBeforeMount()beforeMount()模板挂载到 DOM 之前调用,虚拟 DOM 已生成。
mountedonMounted()mounted()模板挂载到 DOM 后调用,$el 已替换为真实 DOM。
beforeUpdateonBeforeUpdate()beforeUpdate()数据更新后,虚拟 DOM 重新渲染之前调用。
updatedonUpdated()updated()数据更新并完成 DOM 渲染后调用。
beforeDestroyonBeforeUnmount()beforeUnmount()组件销毁之前调用,用于清理操作。
destroyedonUnmounted()unmounted()组件销毁后调用,实例及其所有内容都已被移除。
activated (keep-alive)onActivated()activated()keep-alive 缓存的组件激活时调用。
deactivated (keep-alive)onDeactivated()deactivated()keep-alive 缓存的组件停用时调用。
<template>
  <keep-alive>
    <MyComponent v-if="showComponent" />
  </keep-alive>
  <button @click="toggle">Toggle Component</button>
</template>

<script>
export default {
  data() {
    return {
      showComponent: true
    };
  },
  methods: {
    toggle() {
      this.showComponent = !this.showComponent;
    }
  }
};
</script>

<script>
export default {
  name: 'MyComponent',
  activated() {
    console.log('Component activated');
  },
  deactivated() {
    console.log('Component deactivated');
  }
};
</script>

一般发请求的阶段

  • 如果请求与DOM无关:在created钩子中发请求,因为数据已经可用,且无需等待DOM渲染完成。
  • 如果请求依赖DOM或需要操作DOM:在mounded钩子中发请求,确保DOM已经渲染完成。

v-for和v-if

​ 在Vue中, v-if v-show 是两个常用的条件指令,他们的主要区别体现在实现机制、性能开销和使用场景。

  1. v-if

    • 工作原理: v-if 根据条件动态的添加或移除 DOM 节点。

    • 渲染时机:只有条件为 true 时,Vue 才会创建并插入DOM 节点;条件为 false 时,Vue 会销毁对应的 DOM 节点。

    • 性能影响:由于需要频繁的创建和销毁DOM , v-if 在条件频繁切换时性能较差

    • 使用场景:

      • 适用于 初次加载时无需显示条件变化较少 的场景。
      • 例如:数据需要异步加载,初始化状态下无需显示。
      <template>
        <div>
          <p v-if="isVisible">我会被动态插入或移除</p>
          <button @click="toggle">切换显示</button>
        </div>
      </template>
      
      <script>
      export default {
        data() {
          return {
            isVisible: false
          };
        },
        methods: {
          toggle() {
            this.isVisible = !this.isVisible;
          }
        }
      };
      </script>
      
      
  2. v-show

  • 工作原理: v-show 切换的是原生的css display 属性(display:none 或正常显示)

  • 渲染时机:无论条件为 true 还是 false , 元素始终会被渲染到DOM中,只是被隐藏或显示。

  • 性能影响:由于只是简单的切换CSS 属性, v-show 切换开销很低,适合频繁切换的场景。

  • 使用场景:

    • 适用于 频繁显示/隐藏 的场景
    • 例如:模态框的显隐、选项卡的切换。
    <template>
      <div>
        <p v-show="isVisible">我会一直存在 DOM 中,只是显示或隐藏</p>
        <button @click="toggle">切换显示</button>
      </div>
    </template>
    
    <script>
    export default {
      data() {
        return {
          isVisible: false
        };
      },
      methods: {
        toggle() {
          this.isVisible = !this.isVisible;
        }
      }
    };
    </script>
    		
    
特性v-ifv-show
实现机制通过添加或移除DOM元素实现通过切换元素的CSS display 属性实现
初始渲染在条件为 true 时,才会渲染元素元素总是渲染到DOM,只是默认隐藏
切换性能开销较高:每次切换都会重新销毁和创建元素开销较低:仅切换 display ,无需销毁和重建DOM
使用场景适合条件少改变的场景适合频繁切换显示/隐藏的场景

Vue 的内部指令

​ Vue 提供了一系列内置指令,用于操作DOM、绑定数据和实现响应式效果。这些指令在模板中通过v-前缀使用。

Vue常用内置指令

指令描述
v-if条件渲染,元素根据条件添加或移除
v-else必须与 v-ifv-else-if 一起使用,用于提供“否则”的分支
v-else-if条件渲染的“否则如果”分支。
v-show条件显示,切换元素的 display 属性。
v-for列表渲染,用于遍历数组或对象
v-bind动态绑定属性或class、style等。
v-on绑定事件监听器
v-model双向绑定输入控件的值
v-slot用于分发内容到子组件的插槽
v-pre跳过元素和子元素的编译
v-cloak防止模板闪烁(配合CSS使用)
v-once渲染一次,之后不会再更新
v-html(Vue3)优化性能,条件满足是缓存组件渲染结果

Vue2 和Vue3 内置指令的区别

  1. v-model 的改进

    • Vue2:

      • v-model 默认绑定到表单元素的 value 属性
      • 默认事件是input
      • 只能绑定单个值
      //父组件     
      <template>
        <child-component 
          v-model:title="title" 
          v-model:content="content">
        </child-component>
        <div>
          <p>Title: {{ title }}</p>
          <p>Content: {{ content }}</p>
        </div>
      </template>
      
      <script>
      import ChildComponent from './ChildComponent.vue';
      
      export default {
        components: { ChildComponent },
        data() {
          return {
            title: 'Default Title',
            content: 'Default Content'
          };
        }
      };
      </script>
      
      //子组件
      <template>
        <div>
          <input 
            type="text" 
            :value="title" 
            @input="$emit('update:title', $event.target.value)" 
            placeholder="Edit Title">
          <textarea 
            :value="content" 
            @input="$emit('update:content', $event.target.value)" 
            placeholder="Edit Content">
          </textarea>
        </div>
      </template>
      
      <script>
      export default {
        props: {
          title: String, // 对应 v-model:title
          content: String // 对应 v-model:content
        }
      };
      </script>
      
      

      运行结果:

      1. ​ 父组件的 title 和 content 数据分别绑定到子组件中的输入框和文本区域
      2. 子组件通过 @emit 发出事件更新父组件的数据

      原理分析

      1. 多个 v-model 的语法

        • vue3 中,默认 v-model 的绑定属性为 modelValue ,对应时间为 update:modelValue
        • 当需要绑定多个值时,可以通过命名的方式指定不同的绑定键(如 v-model:titlev-model:comtent
      2. 事件名称约定

        • vue 自动将 v-model:name 转换为 prop="name" event="update:name"
        • 例如: v-model:title 实际上等效于
        :title="title" @update:title="title = $event"
        
      3. 灵活性

        • 可以根据需求自定义多个 v-model ,实现复杂场景的双休绑定
  2. v-bindv-on 的简化语法

    • vue2 和vue3均支持 :@ 的简写形式
      • v-bind 可写为 :attr
      • v-on 可写为 @event
    • vue3 支持动态参数
    <button :[dynamicAttr]="value">Click</button>
    
  3. v-for 的键值对写法

    • vue2和vue3 的 v-for 使用方法一致,用于渲染列表。

    • 新增

      • vue3 中的 v-for 支持解构赋值
      <template>
        <ul>
          <li v-for="({ user: { name, age }, job }, index) in data" :key="index">
            {{ name }} ({{ age }}岁) - 职业: {{ job }}
          </li>
        </ul>
      </template>
      
      <script>
      export default {
        data() {
          return {
            data: [
              { user: { name: "张三", age: 25 }, job: "工程师" },
              { user: { name: "李四", age: 30 }, job: "设计师" },
              { user: { name: "王五", age: 35 }, job: "产品经理" },
            ],
          };
        },
      };
      </script>
      
  4. 新增指令

    • v-memo (Vue3)

      • 用于缓存组件的渲染结果,仅在依赖发生变化时重新渲染
      <template v-memo="[key]">
        <!-- 缓存渲染内容 -->
      </template>
      
  5. 指令绑定的增强

    • vue3 引入了对自定义指令的全面改进,支持 bindupdate 钩子合并为单个 mountedupdated 钩子

      app.directive('example', {
        mounted(el, binding) {
          console.log('Mounted:', binding.value);
        },
        updated(el, binding) {
          console.log('Updated:', binding.value);
        }
      });
      
      

vue2 和 vue3 内置指令的完整对比表

指令vue2vue3备注
v-for支持支持无变化
v-show支持支持无变化
v-for支持支持vue3支持解构赋值
v-model单一绑定多个绑定vue3支持绑定多个值
v-bind支持支持vue3支持动态参数
v-on支持支持vue3支持动态参数
v-slot支持支持无变化
v-pre支持支持无变化
v-cloak支持支持无变化
v-once支持支持无变化
v-html支持支持无变化
v-text支持支持无变化
v-mome不支持支持vue3新增,用于缓存渲染内容
vue的单向数据流

​ 在vue中,单向数据流指的是数据从父组件通过 props 向子组件传递的流向是 单向的,即数据只能从父组件流向子组件,而不能从子组件反向修改父组件的状态。这种设计主要是为了保持数据的可预测性和组件之间的隔离性。

实现单向数据流的原因

  1. ​ 提升数据的可维护性
    • 单向数据流使得数据的来源清晰,减少了调试和维护的复杂性
  2. 防止数据不一致
    • 如果允许子组件直接修改父组件的数据,会导致数据来源混乱,从而增加出错的可能性
  3. 保持组件的独立性
    • 单向数据流使得组件更容易复用,因为他们依赖于外部的输入而不得直接修改外部的状态

应用场景

  1. 父组件传递数据
    • 父组件向子组件传递数据(通过 props
    • 子组件只能使用这些数据,不能直接修改
  2. 子组件通知父组件
    • 如果子组件需要让父组件知道某些事件(如用户输入变化),应通过 $emit 通知父组件,父组件再更新数据

computed 和 watch 的区别和运用的场景

  1. 定义和用途
特性computedwatch
定义用于声明式地定义基于响应式数据的派生值用户监听响应式数据的变化并执行副作用(如异步操作)
依赖的方式自动追踪依赖的响应式数据,当依赖变化时,计算值会更新手动指定监听的响应式数据,当数据变化时触发回调
返回值必须有返回值,作为计算数据的值无需返回值,执行自定义逻辑(如API调用)
缓存会缓存计算结果,只有依赖发生变化时才重新计算不缓存,监听回调每次数据变化都会执行

应用场景

  1. computed 的适用场景
  • 声明式计算属性

    • 当需要通过一个或多个数据计算出一个派生值时,优先使用 computed
    • 例:根据用户输入的名字动态生成全名
  • 优化性能(带缓存)

    • 如果依赖的数据频繁变化,但实际计算结果未变化,computed 的缓存机制可以减少不必要的重复计算
    <template>
      <p>{{ fullName }}</p>
    </template>
    
    <script>
    export default {
      data() {
        return {
          firstName: 'John',
          lastName: 'Doe'
        };
      },
      computed: {
        fullName() {
          console.log('计算 fullName');
          return `${this.firstName} ${this.lastName}`;
        }
      }
    };
    </script>
    
    
  1. watch 的适用场景
  • 执行副作用

    • 当某些数据变化需要触发副作用(如API请求、定时器、DOM操作)时,使用 watch

    • 例:监听搜索框输入内容,动态获取搜索结果

    <template>
      <input v-model="searchQuery" placeholder="搜索..." />
    </template>
    
    <script>
    export default {
      data() {
        return {
          searchQuery: ''
        };
      },
      watch: {
        searchQuery(newQuery) {
          this.fetchResults(newQuery);
        }
      },
      methods: {
        fetchResults(query) {
          console.log('Fetching results for:', query);
        }
      }
    };
    </script>
    
    
  • 深度监听

    • 当需要监听对象或数组的深层次变化时, watch 提供了 deep 选项
    watch: {
      userProfile: {
        handler(newProfile) {
          console.log('User profile changed:', newProfile);
        },
        deep: true
      }
    }
    
  • 异步操作

    • 如果数据变化需要执行异步任务(如延迟调用或API请求),watch 是最佳选择。
  1. 选中指南

    需求场景推荐使用
    需要基于响应式数据计算派生值,并且需要缓存结果computed
    数据变化需要触发副作用(如调用函数、API请求)watch
    复杂的逻辑,需要监听对象或数组的深度变化watch(deep)
    数据变化频繁且加上结果不会频繁变化computed
vue 响应式数据的原理
  1. vue2响应式原理

    • 实现方式:

      • vue2 使用 object.defineProperty 将对象的每个属性转为 gettersetter
      • 当读取属性时(getter),vue 收集依赖(如模板中的绑定)
      • 当修改属性时(setter),vue通知依赖重新渲染
    • 优点

      • 基础浏览器兼容性好,可以支持旧版本浏览器(如IE11)
    • 缺点

      • 无法检测新增属性或删除属性

        • 必须通过 Vue.set()this.$set() 动态添加响应式属性
        this.$set(this.obj, 'newProp', value);
        
    • 数组变化的局限性

      • vue2无法监听数组的直接赋值,例如修改数组的索引
      • 必须使用 Vue 提供的方法(如 splice )或 this.$set()
    • 性能问题

      • 对每个对象的每个属性都需要单独设置 getter 和setter ,处理深层嵌套对象的成本较高
  2. vue3 响应式原理

    核心机制:Proxy

    • 实现方式

      • vue3 使用 JavaScript 的 proxy 对整个对象进行代理,而不是逐个属性设置
      • proxy 能监听对象的任意操作(读取、写入、删除、动态添加属性等)
      • Vue 提供的 reactive 和 ref 是基于 proxy 实现的。
    • 优点

      • 支持动态属性

        • 不再需要 Vue.set(),可以直接监听新增或删除的属性
      • 数组索引和长度变化的响应式

        • Proxy 可以正确地追踪数组的索引修改和长度变化
        const arr = reactive([1, 2, 3]);
        arr[2] = 4; // 自动触发更新
        
      • 性能优化

        • 对整个对象进行代理,不需要递归地为每个属性添加 gettersetter
        • 只有实际访问的属性才会触发代理逻辑
      • 更现代的设计

        • 使用 proxy 提高了灵活性,为未来的JavaScript 标准和特性(如 Relect)打下基础
  3. 主要区别

    特性Vue2Vue3
    实现方式Object.definePropertyProxy
    动态属性监听需要使用 Vue.set()$set支持直接监听新增和删除的属性
    数组变化监听不支持索引和长度变化,需要用特定方法支持直接监听索引和长度的变化
    性能深层对象需递归处理,开销较大整体代理,无需递归处理
    API易用性使用传统的 data 配置项退阿金使用 reactiveref
    兼容性支持旧版浏览器(如IE11)不支持IE11,需要现代浏览器支持
Vue的父子组件生命周期钩子函数执行顺序

​ 在vue 中,父子组件的生命周期钩子函数执行顺序是按照组件的创建和销毁顺序来安排的。

  1. vue2 的生命周期钩子函数执行顺序

    组件挂载是(创建阶段)

    1. 父组件的 beforeCreate
    2. 父组件的 created
    3. 父组件的 beforeMount
    4. 子组件的 created
    5. 子组件的 beforeMount
    6. 子组件的 mounted
    7. 父组件的 mounted

    组件更新时

    1. 父组件的 beforeUpdate
    2. 子组件的 beforeUpdate
    3. 子组件的 updated
    4. 父组件的 updated

    组件销毁时

    1. 父组件的 beforeDestory
    2. 子组件的 beforeDestory
    3. 子组件的 destoryed
    4. 父组件的 destoryed
  2. vue3的生命周期钩子函数执行顺序

    vue3中的生命周期钩子与 Vue2 基本一致,但钩子函数的名称发生了变化,同时引入了 setup 函数。

    函数挂载时(创建阶段)

    1. 父组件的 setup
    2. 父组件的 onBeforeMount
    3. 子组件的 setup
    4. 子组件的 onBeforeMount
    5. 子组件的 onMounted
    6. 父组件的 onMounted

    组件更新时

    1. 父组件的 onBeforeUpdate
    2. 子组件的 onBeforeUpdate
    3. 子组件的 onUpdated
    4. 父组件的 onUpdated

    组件销毁时

    1. 父组件的 onBeforeUnmount
    2. 子组件的 onBeforeUnmount
    3. 子组件的 onUnmounted
    4. 父组件的 onUnmounted
  3. 执行顺序总结

阶段父组件钩子子组件钩子
挂载beforeCreatecreatedbeforeMount→ 等待子组件完成 →mountedbeforeCreatecreatedbeforeMountmounted
更新beforeUpdate→ 等待子组件完成 →updatedbeforeUpdateupdated
销毁beforeDestroy→ 等待子组件完成 →destroyedbeforeDestroydestroyed
虚拟DOM是什么,及其优缺点

​ 虚拟DOM是一种编程概念,它通过在内存中创建一个轻量级的 JavaScript 对象(即虚拟DOM数),用来描述真实 DOM 的结构。

​ 它是实际DOM 的抽象表示,可以被看做是一个用 JavaScript 对 DOM 数的模拟。

​ 在Vue 和 React 等框架中, 虚拟DOM 的主要作用是提高性能,通过高效的算法将虚拟DOM与真实DOM进行对比(diff),并只更新发生变化的部分,而不是直接操作整个真实DOM。

虚拟DOM 的工作流程

  1. 创建虚拟DOM

    • 使用JavaScript对象描述DOM结构

    • 例如

      const vnode = {
        tag: 'div',
        props: { id: 'app' },
        children: [
          { tag: 'h1', children: 'Hello, World!' },
          { tag: 'p', children: 'This is a virtual DOM example.' }
        ]
      };
      
      
  2. 渲染虚拟DOM

    • 框架根据虚拟DOM构建真实DOM并插入页面
  3. 更新虚拟DOM

    • 当状态发生变化时,重新生成新的虚拟DOM
  4. Diff 算法

    • 对比新旧两个虚拟DOM树,找出变化的部分
  5. 更新真实DOM

    • 将变化的部分应用到真实DOM上。

虚拟DOM 的优缺点

  1. 性能优化
    • 最小化DOM操作
      • 真实DOM操作时性能瓶颈,虚拟DOM通过计算出最小的差异集合,减少不必要的DOM操作
    • 批量更新
      • 虚拟DOM在内存中完成对比后,可以一次性应用所有更改
  2. 跨平台能力
    • 虚拟DOM是对真实DOM 的抽象,不仅可以用在浏览器中,也可以用在其他环境(如果服务器端渲染、移动端Natvie渲染)
  3. 简化复杂的状态更新
    • 使用虚拟DOM后,开发者只需专注于描述组件的状态,框架会自动处理DOM的更新逻辑。
  4. 增强可维护性
    • 使用声明式的方法描述UI,可以使代码更简洁、易读,降低开发和维护成本。

虚拟DOM的缺点

  1. 初次渲染较慢
    • 初次将虚拟DOM转换为真实DOM 需要一定的开销
    • 如果页面非常复杂,初次渲染的性能可能比直接操作DOM稍差
  2. 对小型应用的意义有限
    1. 对于简单或静态页面,直接操作DOM更高效,而虚拟DOM 的diff算法会正价额外的计算开销
  3. 难以掌握细颗粒度优化
    • 虚拟DOM封装了DOM操作逻辑,开发者失去了对底层优化的完全控制。例如:手动对特地DOM节点进行优化可能更高效

虚拟DOM示例

原生DOM操作

const element = document.createElement('div');
element.id = 'app';

const title = document.createElement('h1');
title.textContent = 'Hello, World!';
element.appendChild(title);

document.body.appendChild(element);

虚拟 DOM

const vnode = {
  tag: 'div',
  props: { id: 'app' },
  children: [
    { tag: 'h1', children: 'Hello, World!' }
  ]
};

// 将 vnode 渲染为真实 DOM 的伪代码
function render(vnode) {
  const el = document.createElement(vnode.tag);
  if (vnode.props) {
    Object.keys(vnode.props).forEach(key => {
      el.setAttribute(key, vnode.props[key]);
    });
  }
  if (vnode.children) {
    vnode.children.forEach(child => {
      el.appendChild(render(child));
    });
  }
  return el;
}

document.body.appendChild(render(vnode));

虚拟DOM 的应用场景

  1. 动态视图更新
    • 需要频繁更新UI的应用(如表单、图表、游戏等)
  2. 跨平台开发
    • RN、Weex等使用虚拟DOM将web技术应用于移动开发
  3. 复杂的状态管理
    • 使用虚拟DOM可以将复杂的状态更新逻辑交给框架处理,降低开发成本。

总结

特性虚拟DOM
优点提高性能、减少DOM操作、跨平台支持、简化状态更新
缺点初次渲染慢、小型应用意义不大、对底层优化控制力不足
适用场景动态页面更新、多平台开发、复杂状态管理
不适用场景静态页面、小型应用、需要极致性能优化的场景
vue2、vue3、React的diff算法区别

​ vue合React都使用了虚拟DOM 和 Diff 算法来优化界面更新,但它们在具体实现和优化策略上存在一些差异。

  1. Vue2的Diff算法

    核心特性

    1. ​ 模板驱动更新
      • Vue2使用模板生成虚拟DOM,通过 object.defineProperty 实现响应式
      • 更新过程是基于依赖跟踪( dependency tracking)的,只有相关的组件或节点会触发更新。
    2. 双层Diff过程
      • vue2会优先比较组件级别的变化,再对子节点进行递归的逐层对比
    3. Diff算法优化
      • 采用静态节点标记
        • 编译时标记哪些节点是静态的(即内容不会变化),跳过这些节点的更新对比。
      • 递归对比虚拟DOM树,深度优先

    局限性

    • 无法充分利用现代浏览器特性
      • vue2 的Diff 算法基于 Object.defineProperty,无法全局监控对象的属性变化
    • 性能问题
      • 对于大型复杂的DOM树,递归对比可能会带了一定性能开销。
  2. Vue3的Diff算法

    核心特性

    1. 基于Proxy 的响应式

      • Vue3使用 Proxy 替代 Object.defineProperty ,能够精装追踪数据变化
      • 只对发生变化的部分重新生成虚拟DOM,不需要全局更新
    2. 编译时优化 - Block Tree 概念:

      • Vue 3 在编译时生成块(Block Tree),将动态内容和静态内容分离。
      • 只对动态部分进行 Diff,从而减少无关部分的对比。 - 动态节点标记:
      • Vue 3 会在编译时标记动态节点的范围,Diff 时直接定位到动态节点。
    3. 子树优先更新

      • Vue 3 优化了子组件的更新逻辑,避免了不必要的深层递归。
    4. Fragment 支持

      • Vue 3 支持多根节点的组件(Fragment),减少多余的 DOM 包裹元素。
    5. React 的Diff算法

    核心特性

    1. 单向数据流
      • React使用状态驱动更新,通过 setState 或 Hooks 触发组件重新渲染。
      • 每次更新都会生成完整的新虚拟DOM
    2. 树形对比算法
      • React的Diff 算法主要优化树形结构,通过以下规则减少计算量
        • 同层比较:只比较同一层的节点,不会夸层对比。
        • Key 优化:
          • React使用 key 标识节点的唯一性,从而减少节点复用错误
          • 如果 key 一致,直接复用节点;否则视为新增或删除。
      • 对于复杂树结构,React 会根据节点类型进行复用、替换、或重建操作。
    3. Fiber 架构
      • Fiber的出现
        • React 在16版本引入了Fiber架构,支持任务分片和可中断更新
        • 在更新虚拟 DOM 时,React 会根据优先级分配任务,从而实现动画、输入等高优先级任务的平滑处理。
      • 时间切片
        • Fiber 提供了一个异步的 Diff 过程,通过时间切片(Time Slicing)将更新分为多帧完成。

    优点:

    • 支持中断的任务调度,适合复杂的用户交互场景。
    • 优化了深度嵌套组件的更新过程。

    缺点

    • 每次更新都会生成完整的虚拟 DOM,可能带来一定的性能开销。
    • Diff 过程复杂度较高
  3. Diff 算法的对比

特性Vue 2Vue 3React
响应式实现Object.definePropertyProxy状态驱动(setState 或 Hooks)
Diff 策略深度优先,逐层递归静态内容标记 + 动态内容快速定位同层对比 + Key 优
性能优化静态节点标记Block Tree,子树优先更新Fiber 架构,时间切片
动态节点标记部分支持编译时完全支持依赖 key 提高效率
调度机制无调度机制单一任务模型多任务优先级调度(Fiber)
跨层对比支持跨层对比动态节点优先对比不支持跨层对比
场景适用静态内容较多的场景动态与静态内容混合的场景复杂的交互与动画场景

image.png