<Vue.js设计与实现>学习笔记(四):我理解的组件化
1. 组件的实现原理组件本质上是一组DOM元素的封装其核心实现涉及组件实例的创建、选项的处理如props、setup、render、以及组件的挂载与更新。渲染器在遇到组件类型的VNode时会执行组件内部逻辑并递归地渲染其子节点最终完成整个组件树的构建。// 组件实例的简化结构constinstance{// 当前组件的VNodevnode:null,// 组件选项如 setup、render 等type:null,// Props 数据props:{},// 响应式状态 (data)state:null,// setup 返回的响应式状态setupState:null,// 组件是否已挂载isMounted:false,// 组件渲染生成的子树 VNodesubTree:null};// 组件挂载的核心流程 (简化)functionmountComponent(vnode,container){// 1. 创建组件实例constinstance{vnode,type:vnode.type,props:{},isMounted:false,subTree:null};// 2. 初始化 Props (从 vnode.props 中获取)// 3. 执行 setup 函数constsetupResultinstance.type.setup(instance.props);// 4. 处理 setup 返回值if(typeofsetupResultfunction){// 如果返回函数则作为 render 函数instance.type.rendersetupResult;}else{// 如果返回对象则作为 setupStateinstance.setupStatesetupResult;}// 5. 定义并执行渲染副作用 (effect)// 当响应式数据变化时此副作用会重新执行constcomponentUpdateFn(){// 执行 render 函数得到子树 VNodeconstsubTreeinstance.type.render(instance.props,instance.setupState);if(!instance.isMounted){// 首次挂载: 调用 patch 将 subTree 渲染为真实 DOMpatch(null,subTree,container);instance.isMountedtrue;}else{// 更新: 用新的 subTree 与旧的 subTree 进行对比并更新 DOMpatch(instance.subTree,subTree,container);}// 保存当前 subTree 供下次更新使用instance.subTreesubTree;};// 使用 effect 包裹使其能自动追踪响应式依赖effect(componentUpdateFn);}2. 异步组件与函数式组件异步组件通过defineAsyncComponent函数定义允许组件按需加载适合代码分割、优化首屏加载等场景。加载过程中可配置Loading组件、Error组件、超时和重试等。函数式组件是用普通函数定义的组件函数的返回值作为渲染内容。它没有组件实例无data、生命周期等编写更简洁轻量。// defineAsyncComponent 的底层简化实现functiondefineAsyncComponent(loader){// 缓存加载成功的组件letInnerCompnull;return{name:AsyncComponentWrapper,setup(){// 响应式状态是否加载成功constloadedref(false);// 执行 loader即 () import(...)loader().then(comp{InnerCompcomp;loaded.valuetrue;});// 渲染函数return(){// 加载成功则渲染目标组件否则渲染占位内容returnloaded.value?{type:InnerComp}:{type:Text,children:};};}};}// 异步组件使用 defineAsyncComponentconstAsyncCompdefineAsyncComponent(()import(./HeavyComponent.vue));// 带配置的异步组件constAsyncCompWithConfigdefineAsyncComponent({loader:()import(./HeavyComponent.vue),loadingComponent:LoadingComp,// 加载中显示errorComponent:ErrorComp,// 加载失败显示delay:200,// 延迟显示 Loadingtimeout:3000// 超时时间});// 函数式组件一个普通函数functionFunctionalComponent(props){return{type:div,children:Hello,${props.name}};}3. 内建组件和模块Vue.js提供了一些内建组件它们不负责渲染具体的UI内容而是控制渲染行为需要渲染器级别的底层支持。主要包括KeepAlive缓存组件实例避免频繁创建/销毁保持组件状态。Teleport将组件内容渲染到指定的DOM容器如body不受父组件样式影响。Transition为组件的进入/离开提供动画过渡效果。template !-- KeepAlive缓存 Tab 组件切换时保留状态 -- KeepAlive Tab v-ifcurrentTab 1 / Tab v-else-ifcurrentTab 2 / /KeepAlive !-- Teleport将弹窗渲染到 body -- Teleport tobody Dialog :visibleshowDialog / /Teleport !-- Transition进入/离开动画 -- Transition div v-ifshow动画内容/div /Transition /template