Block Tree 与 Slot 结合实现细粒度更新,核心是编译阶段分块隔离与运行时作用域解耦:<slot>被视为动态边界,其内容独立成块、按父组件依赖精准更新,配合v-memo可进一步约束刷新范围。
Vue.js 中 Block Tree 与 Slot 插槽结合实现细粒度更新,核心在于编译阶段的“分块隔离”与运行时的“作用域解耦”。静态内容被提升复用,动态逻辑按依赖边界划分成独立 block;而插槽内容本身由父组件定义、在子组件中渲染,天然具备跨作用域更新能力——两者配合,能让 slot 内部变化只触发对应 block 的 patch,不牵连外层结构。
Vue 3 编译器在解析模板时,会把 <slot> 视为一个潜在的动态节点边界。即使插槽内容是纯静态的,只要它被包裹在带响应式绑定的父元素中(如 v-if 或 :class),整个插槽节点就会被划入一个新的 block。这意味着:
<slot>)本身是一个 block root,它的更新不依赖于子组件内部其他静态区域$slots.xxx),该函数的执行时机和依赖收集独立于子组件的主渲染逻辑默认情况下,插槽内容的更新粒度由父组件的响应式依赖范围决定。若想进一步缩小更新范围,可在插槽内容中使用 v-memo 显式声明缓存条件:
<template v-slot:header><div v-memo="[user.name]">{{ user.name }}/template>:仅当 user.name 变化时才重渲染 header 插槽内部v-memo 会强制创建一个新的 block 边界,让插槽内部的子树脱离父级 block 的更新链路作用域插槽(scoped slot)的数据来自子组件,但模板在父组件中定义。这种分离让 Block Tree 能更精准地绑定依赖:
立即学习“前端免费学习笔记(深入)”;
slot 的 props(如 :data="listItem")会被编译为响应式参数,仅当 listItem 本身变化时,对应插槽 block 才触发更新{{ data.title.toUpperCase() }})只收集父组件自身的依赖,不会错误关联到子组件的其它状态虽然插槽天然适合细粒度更新,但某些写法会无意中扩大更新范围:
{{ $parent.count }}),会让整个插槽 block 绑定到子组件的响应式系统,失去隔离性<slot name="a"/><slot name="b"/>),可能被编译器合并进同一个 block,导致一改全刷key 的动态插槽切换(如 v-if="tab === 'user'" 切换不同插槽)容易引起不必要的 VNode 销毁重建,建议搭配 key 或 v-memo