<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Vue3 on ZiYang FrontEnd Interview</title><link>https://fe-interview.pangcy.cn/tags/vue3/</link><description>Recent content in Vue3 on ZiYang FrontEnd Interview</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 06 Mar 2025 13:07:39 +0800</lastBuildDate><atom:link href="https://fe-interview.pangcy.cn/tags/vue3/index.xml" rel="self" type="application/rss+xml"/><item><title>Vue3与Vue2响应式原理差异</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-01/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-01/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ul>
&lt;li>&lt;strong>核心能力维度&lt;/strong>：框架机制理解、响应式原理深度、API设计思想&lt;/li>
&lt;li>&lt;strong>技术评估点&lt;/strong>：&lt;/li>
&lt;/ul>
&lt;ol>
&lt;li>对象属性检测的全面性（新增/删除属性）&lt;/li>
&lt;li>数组监听机制差异&lt;/li>
&lt;li>响应式初始化性能特征&lt;/li>
&lt;li>数据结构支持范围扩展&lt;/li>
&lt;li>依赖收集与触发效率优化&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Proxy拦截能力 &amp;gt; Object.defineProperty局限性 &amp;gt; 数组方法重写机制&lt;/p>
&lt;h4 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;ol>
&lt;li>
&lt;p>&lt;strong>检测能力&lt;/strong>：&lt;br>
Vue2通过&lt;code>Object.defineProperty&lt;/code>劫持已有属性，新增/删除属性需&lt;code>Vue.set&lt;/code>/&lt;code>Vue.delete&lt;/code>。Vue3的&lt;code>Proxy&lt;/code>代理整个对象，通过&lt;code>get&lt;/code>/&lt;code>set&lt;/code>/&lt;code>deleteProperty&lt;/code>拦截器自动捕获所有属性变动。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>数组处理&lt;/strong>：&lt;br>
Vue2重写数组原型方法（push/pop等）并手动触发更新，但无法检测索引赋值（&lt;code>arr[2]=x&lt;/code>）和&lt;code>length&lt;/code>修改。Vue3的Proxy可直接捕获数组索引赋值、方法调用及长度变化。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>性能优化&lt;/strong>：&lt;br>
Vue2在初始化时递归遍历所有属性设置getter/setter，深层对象性能损耗大。Vue3的Proxy采用惰性劫持，仅在访问时创建响应式关联，减少初始化开销。&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h4 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;ul>
&lt;li>误以为Proxy一定更快（大规模属性访问场景Proxy开销可能更大）&lt;/li>
&lt;li>忽略Vue3仍需&lt;code>ref&lt;/code>处理基础类型（Proxy无法代理原始值）&lt;/li>
&lt;li>混淆数组响应式实现方式（Vue3仍需要特殊处理部分数组操作）&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3的Proxy方案相比Vue2有以下关键改进：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>属性检测&lt;/strong>：Proxy原生支持属性增删检测，无需特殊API，解决Vue2的动态属性追踪痛点。&lt;/li>
&lt;li>&lt;strong>数组处理&lt;/strong>：直接响应索引赋值和&lt;code>length&lt;/code>变化，无需重写数组方法，代码更简洁。&lt;/li>
&lt;li>&lt;strong>性能优势&lt;/strong>：惰性劫持减少初始化消耗，嵌套对象性能提升约50%（Vue官方数据）。&lt;/li>
&lt;li>&lt;strong>数据结构&lt;/strong>：支持Map/Set等ES6集合类型，扩展响应式系统适用范围。&lt;/li>
&lt;/ol>
&lt;p>改进意义在于提升开发体验（减少手动干预）、降低内存占用（统一依赖存储）、提高框架性能基准。&lt;/p>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="28ad678" class="language-javascript ">
 &lt;code>// Vue2数组处理示例 
const vm = new Vue({ 
 data: { 
 list: [1,2,3] 
 }, 
 methods: { 
 update() { 
 this.list[1]5 = 5; // 不触发更新 
 this.$set(this.list, 1, 5); // 必须使用API 
 } 
 } 
}); 

// Vue3等效实现 
const state = reactive({ list: [1,2,3] }); 
state.list[1] = 5; // 自动触发响应 &lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>&lt;strong>可扩展性建议&lt;/strong>：&lt;/p></description></item><item><title>Proxy替代Object.defineProperty的原因</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-02/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-02/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该题主要考查候选人以下核心能力：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>响应式原理理解&lt;/strong>：对比新旧响应式方案的实现差异&lt;/li>
&lt;li>&lt;strong>ES6新特性掌握&lt;/strong>：Proxy和Reflect API的实际应用&lt;/li>
&lt;li>&lt;strong>框架演进洞察力&lt;/strong>：理解架构升级背后的工程考量&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点包括：&lt;/p>
&lt;ul>
&lt;li>Object.defineProperty在数组监听和动态属性上的局限性&lt;/li>
&lt;li>Proxy在深层对象代理中的按需响应机制&lt;/li>
&lt;li>属性删除、数组索引修改等边缘场景的处理差异&lt;/li>
&lt;li>响应式系统性能优化的实现原理&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Proxy &amp;gt; Object.defineProperty &amp;gt; 数组方法重写 &amp;gt; 响应式初始化性能&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Object.defineProperty通过劫持对象属性的getter/setter实现响应式，但存在三个致命缺陷：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>数组监听缺陷&lt;/strong>：只能通过重写数组原型方法拦截变更，无法检测索引赋值（arr[2]=1）和length变化&lt;/li>
&lt;li>&lt;strong>属性新增无效&lt;/strong>：初始化后添加的属性无法自动响应，必须使用Vue.set&lt;/li>
&lt;li>&lt;strong>性能瓶颈&lt;/strong>：递归转换整个对象所有属性，造成初始化性能损耗&lt;/li>
&lt;/ol>
&lt;p>Proxy通过创建对象代理层，使用Reflect实现操作转发，优势显著：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="5e5df29" class="language-javascript ">
 &lt;code>const proxy = new Proxy(obj, {
 get(target, key) {
 track(target, key) // 依赖收集
 // 嵌套对象延迟代理（提升性能关键）
 return isObject(res) ? reactive(res) : res 
 },
 set(target, key, value) {
 trigger(target, key) // 触发更新
 return Reflect.set(...arguments)
 }
})&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>误认为Proxy可以直接代理嵌套对象（实际需要递归代理）&lt;/li>
&lt;li>混淆数组方法重写与Proxy原生拦截的区别&lt;/li>
&lt;li>忽视Reflect在保持代理行为一致性中的作用&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3选用Proxy主要因其解决了三大核心问题：&lt;/p></description></item><item><title>reactive与ref的核心区别</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-03/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-03/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ul>
&lt;li>&lt;strong>核心能力维度&lt;/strong>：Vue响应式原理深度理解、API设计差异辨析、数据类型处理能力&lt;/li>
&lt;li>&lt;strong>技术评估点&lt;/strong>：
&lt;ol>
&lt;li>Proxy与getter/setter实现机制差异&lt;/li>
&lt;li>基本类型与引用类型响应式处理限制&lt;/li>
&lt;li>自动解包特性与.value访问的必要性&lt;/li>
&lt;li>引用稳定性与响应式保持能力&lt;/li>
&lt;li>对象类型在两种API间的转换关系&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Proxy响应式代理 &amp;gt; getter/setter拦截 &amp;gt; 自动解包机制 &amp;gt; 引用类型包装原理&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>&lt;strong>reactive()&lt;/strong> 使用Proxy代理整个对象，递归转换嵌套属性。直接操作属性触发响应，适用于引用类型数据。&lt;strong>ref()&lt;/strong> 通过对象包装和value属性访问，利用getter/setter实现拦截，支持任意数据类型。当值为对象时，内部自动调用reactive转换。&lt;/p>
&lt;p>&lt;strong>常见误区&lt;/strong>：&lt;/p>
&lt;ol>
&lt;li>认为ref不能处理对象类型（实际上会自动调用reactive）&lt;/li>
&lt;li>在模板中错误使用.value（模板自动解包）&lt;/li>
&lt;li>在reactive对象中手动解包嵌套的ref&lt;/li>
&lt;/ol>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;strong>根本差异&lt;/strong>：&lt;code>reactive&lt;/code>基于Proxy代理对象实现响应式，&lt;code>ref&lt;/code>通过对象包装的value属性存取触发响应。&lt;code>ref.value&lt;/code>的设计使基本类型可通过引用传递，而Proxy无法直接代理非对象值。&lt;/p>
&lt;p>&lt;strong>必须使用ref的场景&lt;/strong>：&lt;/p>
&lt;ol>
&lt;li>处理字符串/数值等基本类型时（无法被Proxy代理）&lt;/li>
&lt;li>需要保持引用稳定性时（如需要替换整个值并保持响应）&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>转换示例&lt;/strong>：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="0d2008c" class="language-javascript ">
 &lt;code>// ref对象转reactive
const countRef = ref(0)
// 自动解包：访问state.count无需.value
const state = reactive({ count: countRef })
console.log(state.count) // 0

// reactive对象转ref
const data = reactive({ a: 1 })
const dataRef = ref(data) // 等价于ref(reactive({a:1}))
console.log(dataRef.value.a) // 1&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>为什么模板中访问ref不用.value？&lt;/strong>&lt;br>
模板编译时自动解包，仅顶层ref属性需要.value&lt;/p></description></item><item><title>reactive处理基本类型的限制</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-04/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-04/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该题主要考察以下核心维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>响应式系统原理&lt;/strong>：理解Proxy在Vue3中的核心作用及局限性&lt;/li>
&lt;li>&lt;strong>数据类型认知&lt;/strong>：基本类型与引用类型在内存管理的本质差异&lt;/li>
&lt;li>&lt;strong>API设计思想&lt;/strong>：框架为何通过不同API(reactive/)处理不同数据类型&lt;/li>
&lt;li>&lt;strong>框架限制规避&lt;/strong>：掌握响应式失效场景的解决方案&lt;/li>
&lt;/ol>
&lt;p>具体评估点：&lt;/p>
&lt;ul>
&lt;li>Proxy代理机制对数据类型的限制&lt;/li>
&lt;li>基本类型的不可变性（Primitive Immutability）问题&lt;/li>
&lt;li>reactive与ref的底层实现差异&lt;/li>
&lt;li>响应式依赖收集的实现路径&lt;/li>
&lt;li>框架的防御性编程策略&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Proxy代理机制 &amp;gt; 基本类型存储方式 &amp;gt; 响应式依赖收集&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3的响应式系统基于Proxy实现对象属性访问拦截。基本类型（String/Number等）存储在栈内存中，具有不可变性（重新赋值即创建新值）。Proxy只能代理对象，通过对属性get/set操作的拦截建立依赖跟踪。当使用reactive(42)时：&lt;/p>
&lt;ol>
&lt;li>Proxy无法作用于非对象类型，导致响应式链路断裂&lt;/li>
&lt;li>框架内部会抛出&amp;quot;value cannot be made reactive&amp;quot;警告&lt;/li>
&lt;li>实际返回的仍是原始数值，失去响应能力&lt;/li>
&lt;/ol>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>误以为reactive会自动包装基本类型&lt;/li>
&lt;li>混淆ref与reactive的适用场景&lt;/li>
&lt;li>不理解Proxy只能代理对象引用&lt;/li>
&lt;li>试图通过对象包装解决但未正确处理（如reactive({val:5}）的嵌套问题&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3的reactive()强制要求对象参数的核心原因在于其依赖Proxy实现属性访问拦截。基本类型在内存中以值形式存在，Proxy无法直接代理原始值。当尝试reactive(5)时：&lt;/p>
&lt;ol>
&lt;li>Proxy代理失败，无法建立属性访问监听&lt;/li>
&lt;li>数值变更时无法触发Setter逻辑&lt;/li>
&lt;li>框架在开发模式下会发出类型警告&lt;/li>
&lt;/ol>
&lt;p>解决方案是使用ref()，其通过将基本类型包裹在{ value: xxx }对象中，使Proxy可以代理该包装对象。访问时通过.value属性实现依赖追踪，数值变更时触发响应更新。&lt;/p>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="cae472f" class="language-javascript ">
 &lt;code>// 错误用法：直接代理基本类型
const invalid = reactive(0) // 返回原始值，失去响应性

// 正确方案：使用ref包装
const count = ref(0)
// DOM模板中自动解包
{{ count }}

// 逻辑层通过.value操作
function increment() {
 count.value&amp;#43;&amp;#43;
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>&lt;strong>优化建议&lt;/strong>：&lt;/p></description></item><item><title>watch与watchEffect的差异</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-05/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-05/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该问题主要考察以下核心维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>响应式系统理解&lt;/strong>：对Vue3响应式原理及Watcher工作机制的掌握&lt;/li>
&lt;li>&lt;strong>API设计差异&lt;/strong>：区分两种观察器在底层实现上的关键差异&lt;/li>
&lt;li>&lt;strong>性能优化意识&lt;/strong>：根据不同场景选择最佳监听方案的决策能力&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>依赖收集机制（显式指定 vs 自动追踪）&lt;/li>
&lt;li>执行时机控制（立即执行与延迟执行）&lt;/li>
&lt;li>回调参数的设计差异&lt;/li>
&lt;li>副作用清理与执行顺序控制&lt;/li>
&lt;li>多状态关联时的触发策略优化&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>依赖收集：&lt;code>watch&lt;/code>显式指定依赖 vs &lt;code>watchEffect&lt;/code>自动收集&lt;/li>
&lt;li>执行策略：&lt;code>watchEffect&lt;/code>立即执行 vs &lt;code>watch&lt;/code>的lazy初始化&lt;/li>
&lt;li>参数特征：&lt;code>watch&lt;/code>获取新旧值 vs &lt;code>watchEffect&lt;/code>无值参数&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>&lt;code>watchEffect&lt;/code>基于Vue的响应式跟踪系统，在同步执行回调时建立依赖关系图。当任何响应式依赖变更时，触发副作用重新执行。其采用&lt;code>getter&lt;/code>拦截实现自动依赖收集，类似计算属性的工作机制。&lt;/p>
&lt;p>&lt;code>watch&lt;/code>需要显式声明监听目标，底层通过遍历监听源构建依赖关系。其回调接收新旧值对比，内部使用值快照机制保证数据一致性。&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="fb94b21" class="language-javascript ">
 &lt;code>// watch实现伪代码
function watch(source, cb) {
 const getter = isRef(source) 
 ? () =&amp;gt; source.value
 : () =&amp;gt; traverse(source)
 
 let oldValue
 const job = () =&amp;gt; {
 const newValue = effect.run()
 cb(newValue, oldValue)
 oldValue = newValue
 }
}

// watchEffect实现
function watchEffect(effect) {
 const reactiveEffect = new ReactiveEffect(effect)
 reactiveEffect.run()
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>误认为watchEffect无法获取旧值（正确方式：需手动维护状态）&lt;/li>
&lt;li>在watch回调中修改监听源导致无限循环（需添加执行条件判断）&lt;/li>
&lt;li>忽略flush timing配置对DOM更新的影响（post vs sync）&lt;/li>
&lt;/ol>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;code>watch&lt;/code>与&lt;code>watchEffect&lt;/code>的核心差异体现在：&lt;/p></description></item><item><title>Options API与Composition API架构对比</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-06/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-06/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>框架机制理解&lt;/strong>：对比两种API设计范式的实现原理与设计哲学&lt;/li>
&lt;li>&lt;strong>工程化思维&lt;/strong>：评估代码组织方式对复杂系统维护的影响&lt;/li>
&lt;li>&lt;strong>逻辑抽象能力&lt;/strong>：判断对逻辑复用模式的理解深度&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>Options API的碎片化问题（数据/方法/生命周期分散）&lt;/li>
&lt;li>Composition API的函数式编程优势&lt;/li>
&lt;li>基于功能组织的代码封装策略&lt;/li>
&lt;li>响应式系统在两种模式下的实现差异&lt;/li>
&lt;li>逻辑复用的实现路径差异（Mixins vs Composition函数）&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Composition API &amp;gt; 逻辑聚合 &amp;gt; 响应式API &amp;gt; 代码可维护性 &amp;gt; TypeScript支持&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Options API通过对象选项（data/computed/methods）组织代码，导致同一功能逻辑分散在不同选项块中。例如用户验证功能可能涉及：&lt;/p>
&lt;ul>
&lt;li>data中的表单字段&lt;/li>
&lt;li>methods中的提交方法&lt;/li>
&lt;li>watch中的字段校验&lt;/li>
&lt;li>mounted中的初始加载&lt;/li>
&lt;/ul>
&lt;p>Composition API通过&lt;code>setup()&lt;/code>函数实现：&lt;/p>
&lt;ol>
&lt;li>使用&lt;code>ref&lt;/code>/&lt;code>reactive&lt;/code>集中声明响应式数据&lt;/li>
&lt;li>将相关逻辑封装为独立函数（如&lt;code>useFormValidation&lt;/code>）&lt;/li>
&lt;li>通过return暴露必要属性和方法&lt;/li>
&lt;/ol>
&lt;p>这种基于功能组织的模式类似乐高积木，开发者可以自由组合逻辑模块。同时由于函数闭包特性，组合函数内可直接使用相关响应式API，解决了Options API中必须通过&lt;code>this&lt;/code>访问实例属性的限制。&lt;/p>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>认为Composition API只是语法糖（实际改变了代码组织范式）&lt;/li>
&lt;li>在setup中过度使用逻辑混合（应保持单一职责）&lt;/li>
&lt;li>忽视生命周期钩子的使用差异（onMounted代替mounted）&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Options API与Composition API的核心差异在于代码组织范式：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>横向切割 vs 纵向聚合&lt;/strong>：Options API按功能类型切割代码（数据归data，方法归methods），Composition API按业务功能聚合代码&lt;/li>
&lt;li>&lt;strong>逻辑复用方式&lt;/strong>：Options API依赖mixins（存在命名冲突风险），Composition API通过可组合函数实现精准复用&lt;/li>
&lt;li>&lt;strong>类型推导&lt;/strong>：Composition API的函数式结构更利于TypeScript类型推导&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>示例&lt;/strong>：用户定位功能在Options API中的实现：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="77ae999" class="language-javascript ">
 &lt;code>// 分散在多个选项块
export default {
 data() {
 return { coords: null }
 },
 mounted() {
 navigator.geolocation.watchPosition(
 pos =&amp;gt; this.coords = pos
 )
 },
 methods: {
 formatCoords() { /* 格式化逻辑 */ }
 }
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>使用Composition API重构：&lt;/p></description></item><item><title>组合式API常用方法解析</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-07/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-07/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考核以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>响应式系统原理&lt;/strong>：对Vue3响应式机制的理解深度&lt;/li>
&lt;li>&lt;strong>组合式API应用能力&lt;/strong>：核心API的适用场景与实现差异&lt;/li>
&lt;li>&lt;strong>异步状态管理&lt;/strong>：事件循环与响应式更新的协同机制&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>ref与reactive的响应式实现差异&lt;/li>
&lt;li>computed的缓存特性与依赖收集机制&lt;/li>
&lt;li>provide/inject的跨层级通信原理&lt;/li>
&lt;li>微任务队列与DOM更新时机的关联性&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>响应式基础（ref/reactive） &amp;gt; 计算属性（computed） &amp;gt; 依赖注入（provide/inject） &amp;gt; 异步更新机制&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>&lt;strong>ref&lt;/strong>：通过&lt;code>Object.defineProperty&lt;/code>实现基本类型值的响应式包装，内部值存储在&lt;code>.value&lt;/code>属性中。当操作&lt;code>.value&lt;/code>时触发依赖收集与更新通知。&lt;/li>
&lt;li>&lt;strong>reactive&lt;/strong>：基于Proxy代理对象，实现深层次响应式。直接操作属性即可触发更新，但解构会丢失响应性。&lt;/li>
&lt;li>&lt;strong>computed&lt;/strong>：惰性求值的响应式引用，依赖变更时缓存失效。内部通过&lt;code>effect&lt;/code>实现依赖追踪。&lt;/li>
&lt;li>&lt;strong>异步陷阱&lt;/strong>：Vue的响应式更新在同步代码中自动批处理，但在异步回调（如&lt;code>setTimeout&lt;/code>或Promise）中直接赋值&lt;code>.value&lt;/code>可能导致更新未及时触发，需配合&lt;code>nextTick&lt;/code>确保DOM更新队列执行。&lt;/li>
&lt;/ol>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>误将reactive用于基本类型导致性能浪费&lt;/li>
&lt;li>异步回调中遗漏&lt;code>.value&lt;/code>操作引发更新丢失&lt;/li>
&lt;li>混淆computed与methods的使用场景&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;strong>核心API作用&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>&lt;code>ref&lt;/code>：包装基本类型值为响应式对象，通过&lt;code>.value&lt;/code>访问&lt;/li>
&lt;li>&lt;code>reactive&lt;/code>：创建深层次响应式对象，适用于复杂数据结构&lt;/li>
&lt;li>&lt;code>computed&lt;/code>：创建依赖其他响应式状态的计算属性，具有缓存优化&lt;/li>
&lt;li>&lt;code>provide/inject&lt;/code>：实现跨组件层级的状态注入，解决prop逐层传递问题&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>异步场景注意点&lt;/strong>：
在异步回调中直接修改&lt;code>.value&lt;/code>可能错过Vue的批量更新时机 。由于Vue的响应式更新在同步任务中合并处理，而异步任务处于新的调用栈（Call Stack），此时赋值操作会立即触发渲染队列，可能导致重复计算或视图更新不同步。需在修改后调用&lt;code>nextTick&lt;/code>确保更新时序正确。&lt;/p>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="编码示例">编码示例 &lt;a href="#%e7%bc%96%e7%a0%81%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="d4f228e" class="language-javascript ">
 &lt;code>// 异步请求中的正确用法
const dataRef = ref(null);

fetchData().then((response) =&amp;gt; {
 dataRef.value = response; // 正确触发响应式更新
}).catch(() =&amp;gt; {
 dataRef.value = null; // 边界条件处理
});

// 组件卸载时取消请求（示例）
onBeforeUnmount(() =&amp;gt; {
 abortController.abort();
});&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="优化建议">优化建议 &lt;a href="#%e4%bc%98%e5%8c%96%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>&lt;strong>低端设备优化&lt;/strong>：对大型响应式对象使用&lt;code>shallowRef&lt;/code>减少代理开销&lt;/li>
&lt;li>&lt;strong>高并发场景&lt;/strong>：结合&lt;code>watchEffect&lt;/code>自动清理副作用，避免内存泄漏&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>reactive处理Map/Set的局限？&lt;/strong>
回答提示：需使用&lt;code>reactive&lt;/code>包装容器+自定义拦截器&lt;/p></description></item><item><title>script setup语法糖的优势</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-08/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-08/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该题目主要考察以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vue编译原理理解&lt;/strong>：能否解释&lt;code>&amp;lt;script setup&amp;gt;&lt;/code>如何通过编译器转换生成标准组件代码&lt;/li>
&lt;li>&lt;strong>Composition API运用能力&lt;/strong>：评估对新型组件编写模式的理解深度&lt;/li>
&lt;li>&lt;strong>工程化效率认知&lt;/strong>：分析语法糖特性对开发体验的改善作用&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>编译器对顶层绑定的自动暴露机制&lt;/li>
&lt;li>编译器宏（如defineProps）的工作原理&lt;/li>
&lt;li>相比传统Options API的代码精简效果&lt;/li>
&lt;li>类型推导与TS支持的实现方式&lt;/li>
&lt;li>运行时性能与编译器优化的关系&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>编译器转换 &amp;gt; 自动暴露机制 &amp;gt; 编译器宏支持 &amp;gt; 类型推导优化&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>编译时转换&lt;/strong>：&lt;code>&amp;lt;script setup&amp;gt;&lt;/code>在编译阶段会被转换为标准&lt;code>&amp;lt;script&amp;gt;&lt;/code>组件格式。例如：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="7b9a767" class="language-javascript ">
 &lt;code>// 源码
&amp;lt;script setup&amp;gt;
const count = ref(0)
&amp;lt;/script&amp;gt;

// 编译后
export default {
 setup() {
 const count = ref(0)
 return { count } // 自动收集顶层变量
 }
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>编译器通过AST分析识别顶层变量，自动生成return语句暴露变量。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>自动暴露机制&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>仅暴露&lt;strong>顶层声明&lt;/strong>的变量/函数&lt;/li>
&lt;li>非顶层变量（如setup函数内部声明的变量）不会被暴露&lt;/li>
&lt;li>通过&lt;code>expose&lt;/code>编译器选项可精确控制暴露内容&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>编译器宏&lt;/strong>：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="d4c1722" class="language-javascript ">
 &lt;code>// 源码
defineProps({ msg: String }) 

// 编译后
export default {
 props: { msg: String },
 // 自动注入setup函数
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>宏在编译阶段被解析为组件选项，实现类型安全的props/emits声明。&lt;/p></description></item><item><title>组合式API生命周期变化</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-09/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-09/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vue版本差异理解&lt;/strong>：对Options API与Composition API设计差异的掌握程度&lt;/li>
&lt;li>&lt;strong>生命周期机制&lt;/strong>：不同版本生命周期钩子的触发时机与使用场景&lt;/li>
&lt;li>&lt;strong>组合式API原理&lt;/strong>：setup函数执行时机及其对传统生命周期的替代方案&lt;/li>
&lt;/ol>
&lt;p>具体评估点：&lt;/p>
&lt;ul>
&lt;li>组合式API钩子命名规范的设计意图&lt;/li>
&lt;li>setup函数与beforeCreate/created的执行顺序关系&lt;/li>
&lt;li>传统选项式生命周期在组合式模式下的迁移策略&lt;/li>
&lt;li>组合式API中重复注册生命周期回调的能力&lt;/li>
&lt;li>响应式系统初始化的阶段差异&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>命名规则：&lt;code>onXxx&lt;/code>函数式注册 &amp;gt; 选项声明式&lt;/li>
&lt;li>执行时机：setup函数介于beforeCreate和created之间&lt;/li>
&lt;li>替代方案：setup函数直接执行代码替代created逻辑&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>组合式API通过&lt;code>onMounted&lt;/code>等函数注册生命周期回调，其命名采用&lt;strong>动词+生命周期&lt;/strong>的结构（如&lt;code>onMounted&lt;/code>），强调主动订阅行为。这种设计：&lt;/p>
&lt;ul>
&lt;li>与&lt;code>watch&lt;/code>等API保持命名一致性&lt;/li>
&lt;li>支持多次调用注册多个回调&lt;/li>
&lt;li>需显式导入避免全局污染&lt;/li>
&lt;/ul>
&lt;p>&lt;code>setup()&lt;/code>执行阶段替代了传统选项中的&lt;code>beforeCreate&lt;/code>和&lt;code>created&lt;/code>：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="b53419b" class="language-text ">
 &lt;code>组件初始化
    ↓ 
beforeCreate
    ↓ 
setup() 执行
    ↓ 
created&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>在&lt;code>setup&lt;/code>中：&lt;/p>
&lt;ul>
&lt;li>同步代码相当于&lt;code>created&lt;/code>阶段执行&lt;/li>
&lt;li>无法访问&lt;code>beforeCreate&lt;/code>阶段的组件实例（此时未初始化）&lt;/li>
&lt;/ul>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>错误尝试在setup中调用&lt;code>onCreated&lt;/code>（不存在该API）&lt;/li>
&lt;li>误认为setup完全替代所有生命周期（仍需通过钩子函数处理挂载后逻辑）&lt;/li>
&lt;li>在setup外混合使用选项式生命周期导致执行顺序混乱&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>组合式API将生命周期钩子改为&lt;code>on+大写事件名&lt;/code>的函数形式（如&lt;code>onMounted&lt;/code>），这种命名模式：&lt;/p>
&lt;ol>
&lt;li>符合函数式编程范式，通过导入函数主动注册回调&lt;/li>
&lt;li>支持同一生命周期注册多个处理函数&lt;/li>
&lt;li>与watch(onInvalidate)等API命名风格统一&lt;/li>
&lt;/ol>
&lt;p>对于&lt;code>beforeCreate&lt;/code>和&lt;code>created&lt;/code>：&lt;/p>
&lt;ul>
&lt;li>其功能被&lt;code>setup()&lt;/code>函数替代&lt;/li>
&lt;li>&lt;code>setup()&lt;/code>内的同步代码在&lt;code>beforeCreate&lt;/code>之后、&lt;code>created&lt;/code>之前执行&lt;/li>
&lt;li>原本在&lt;code>created&lt;/code>中的初始化逻辑可直接写入&lt;code>setup&lt;/code>顶层作用域&lt;/li>
&lt;li>需要&lt;code>beforeCreate&lt;/code>的场景可使用选项API混合写法（不推荐）&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="代码示例">代码示例 &lt;a href="#%e4%bb%a3%e7%a0%81%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="dbd6181" class="language-javascript ">
 &lt;code>import { onMounted } from &amp;#39;vue&amp;#39;

export default {
 setup() {
 // 替代created的初始化逻辑
 const data = ref(null)
 
 // 替代mounted逻辑
 onMounted(async () =&amp;gt; {
 data.value = await fetchData()
 })

 // 错误示例：试图访问未初始化的DOM
 // document.querySelector(...) 

 return { data }
 },
 // 必要时的传统钩子混合使用
 beforeCreate() {
 // 极少数需要早于setup执行的逻辑
 }
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="可扩展性建议">可扩展性建议 &lt;a href="#%e5%8f%af%e6%89%a9%e5%b1%95%e6%80%a7%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>复杂逻辑使用&lt;code>setup&lt;/code>函数拆分到独立hooks&lt;/li>
&lt;li>异步初始化使用Suspense组件处理加载状态&lt;/li>
&lt;li>性能敏感场景使用&lt;code>onDeactivated&lt;/code>清理资源&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>为什么没有onBeforeCreate？&lt;/strong>&lt;br>
→ 因组件实例在setup执行前未完成初始化，无法安全操作&lt;/p></description></item><item><title>组合式API逻辑复用实现</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-10/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-10/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考核以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>组合式API机制理解&lt;/strong>：考察对Vue3组合式API设计理念的掌握，包括逻辑拆分与复用策略&lt;/li>
&lt;li>&lt;strong>响应式系统运用&lt;/strong>：检验ref/reactive等响应式API的正确使用，及在组合函数中的值传递&lt;/li>
&lt;li>&lt;strong>生命周期整合&lt;/strong>：评估在自定义hook中正确绑定/清除副作用（如事件监听、异步请求）&lt;/li>
&lt;li>&lt;strong>代码抽象能力&lt;/strong>：验证业务逻辑解耦能力，包括参数处理、状态暴露、错误边界等工程化实践&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>组合函数的命名规范与结构&lt;/li>
&lt;li>响应式数据在组件间的状态保持&lt;/li>
&lt;li>生命周期钩子的正确绑定&lt;/li>
&lt;li>异步操作的竞态处理（如请求取消）&lt;/li>
&lt;li>TypeScript类型支持实现&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Composition API Design &amp;gt; 响应式系统 &amp;gt; 生命周期管理 &amp;gt; TypeScript类型推导&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>组合函数本质是返回响应式状态+函数的闭包封装，利用Vue的setup()执行上下文实现逻辑复用。通过ref维持响应式引用，在onMounted等钩子中绑定原生事件或异步操作，通过onUnmounted进行资源清理，避免内存泄漏。&lt;/p>
&lt;p>典型错误包括：&lt;/p>
&lt;ol>
&lt;li>直接返回解构对象导致响应式丢失&lt;/li>
&lt;li>未在卸载阶段移除事件监听&lt;/li>
&lt;li>异步回调中使用过期状态&lt;/li>
&lt;/ol>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>在组合函数内直接修改DOM（违反响应式原则）&lt;/li>
&lt;li>忘记处理异步操作的错误状态&lt;/li>
&lt;li>多个组件实例共享同一响应式引用（未使用函数式返回）&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>通过组合函数封装逻辑需遵循以下步骤：&lt;/p>
&lt;ol>
&lt;li>创建以&lt;code>use&lt;/code>开头的函数，使用ref/reactive封装状态&lt;/li>
&lt;li>在setup阶段执行副作用（如事件绑定）&lt;/li>
&lt;li>返回组件可用的响应式状态与方法&lt;/li>
&lt;li>使用toRefs保持解构后响应式&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>鼠标跟踪器示例&lt;/strong>：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="31f867c" class="language-javascript ">
 &lt;code>import { ref, onMounted, onUnmounted } from &amp;#39;vue&amp;#39;

export function useMouse() {
 const x = ref(0)
 const y = ref(0)
 
 const update = (e) =&amp;gt; {
 x.value = e.pageX
 y.value = e.pageY
 }

 onMounted(() =&amp;gt; {
 window.addEventListener(&amp;#39;mousemove&amp;#39;, update)
 })

 onUnmounted(() =&amp;gt; {
 window.removeEventListener(&amp;#39;mousemove&amp;#39;, update)
 })

 return { x, y }
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>&lt;strong>API请求示例&lt;/strong>：&lt;/p></description></item><item><title>Vue3的Tree shaking实现原理</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-11/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-11/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ul>
&lt;li>&lt;strong>核心能力维度&lt;/strong>：框架设计原理、模块化工程能力、构建工具理解&lt;/li>
&lt;li>&lt;strong>技术评估点&lt;/strong>：
&lt;ol>
&lt;li>ES模块静态分析机制与Tree shaking的关联性&lt;/li>
&lt;li>Vue3编译器标记如何配合模块系统实现按需引入&lt;/li>
&lt;li>全局API设计对代码优化的负面影响&lt;/li>
&lt;li>框架架构演进对打包优化的影响&lt;/li>
&lt;li>功能模块解耦与代码可摇树性的关系&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>ES Module静态结构 &amp;gt; 编译器模板分析 &amp;gt; 全局API副作用 &amp;gt; 模块解耦设计&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3通过以下技术栈实现Tree shaking：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>模块化架构&lt;/strong>：将框架拆分为&lt;code>@vue/runtime-core&lt;/code>等独立ES模块，每个功能（如keep-alive、transition）作为独立导出&lt;/li>
&lt;li>&lt;strong>模板编译器&lt;/strong>：在SFC编译阶段分析模板中实际使用的组件/指令，自动生成精准的import语句&lt;/li>
&lt;li>&lt;strong>函数式API设计&lt;/strong>：组合式API（ref、computed）均为命名导出，配合构建工具的dead code elimination&lt;/li>
&lt;/ol>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="df99625" class="language-javascript ">
 &lt;code>// Vue3组件编译结果示例
import { createVNode, keepAlive } from &amp;#39;vue&amp;#39;

// 仅当模板包含&amp;lt;keep-alive&amp;gt;时才会引入对应模块
export function render() {
 return createVNode(keepAlive, {/* props */})
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>错误认为选项式API也能实现Tree shaking（实际上选项对象无法静态分析）&lt;/li>
&lt;li>混淆编译时优化与运行时开销的关系&lt;/li>
&lt;li>忽视sideEffects配置在打包流程中的作用&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3通过三阶段实现Tree shaking：首先采用ES模块架构，所有功能模块独立导出；其次编译器在模板解析阶段标记实际使用的组件，生成精确的import；最后配合API的函数式设计消除副作用。以keep-alive为例，未使用时其模块不会被import，最终被Rollup等工具移除。相较而言，Vue2的全局API（如Vue.component）因挂载在单一对象上，导致构建工具无法判断使用情况，必须全量包含。&lt;/p>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="架构对比">架构对比 &lt;a href="#%e6%9e%b6%e6%9e%84%e5%af%b9%e6%af%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="63b15d1" class="language-javascript ">
 &lt;code>// Vue2全局API（无法tree-shaking）
Vue.component(&amp;#39;keep-alive&amp;#39;, { /* 实现 */ })

// Vue3模块化设计（可摇树）
// 用户代码
import { KeepAlive } from &amp;#39;vue&amp;#39;

// 构建后未使用模块被移除&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="编译器优化">编译器优化 &lt;a href="#%e7%bc%96%e8%af%91%e5%99%a8%e4%bc%98%e5%8c%96" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>模板编译阶段通过AST分析：&lt;/p></description></item><item><title>Fragment特性的多根节点支持</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-12/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-12/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ul>
&lt;li>&lt;strong>核心能力维度&lt;/strong>：Vue框架原理理解、虚拟DOM机制、版本差异分析能力&lt;/li>
&lt;li>&lt;strong>技术评估点&lt;/strong>：
&lt;ol>
&lt;li>Fragment节点在虚拟DOM中的表现形式&lt;/li>
&lt;li>Vue3的patch算法对多根节点的处理逻辑&lt;/li>
&lt;li>编译器对多根模板的转换机制&lt;/li>
&lt;li>无容器元素对CSS布局的影响&lt;/li>
&lt;li>与传统Vue2单根限制的对比优势&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>虚拟DOM结构 &amp;gt; Patch算法优化 &amp;gt; CSS层叠上下文&lt;/p>
&lt;h4 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;p>Vue3通过引入&lt;code>Fragment&lt;/code>节点类型突破单根限制。当模板存在多个根节点时：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>编译阶段&lt;/strong>将根层级元素转换为&lt;code>Fragment&lt;/code>虚拟节点（vnode.type为Symbol类型）&lt;/li>
&lt;li>&lt;strong>渲染阶段&lt;/strong>处理Fragment时，仅将其子节点挂载到父级，自身不生成真实DOM&lt;/li>
&lt;li>&lt;strong>Patch过程&lt;/strong>：
&lt;ul>
&lt;li>对比新旧Fragment时，执行&lt;code>patchChildren&lt;/code>而非&lt;code>patch&lt;/code>&lt;/li>
&lt;li>通过&lt;code>key&lt;/code>值复用DOM元素，动态调整子节点顺序&lt;/li>
&lt;li>使用最长递增子序列算法优化移动操作&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>类比快递分拣：Fragment类似透明包装袋，仅用于归类物品（子节点）但不增加额外重量（DOM层级）&lt;/p>
&lt;h4 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;ul>
&lt;li>误认为多个根节点会创建多个组件实例&lt;/li>
&lt;li>混淆Fragment与空div的DOM渲染差异&lt;/li>
&lt;li>未考虑动态组件可能导致的位置索引错乱&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3通过Fragment虚拟节点实现多根模板支持。在编译阶段将多根模板转换为带有Symbol类型标识的Fragment虚拟节点，该节点在patch过程中仅作为逻辑容器，通过对比子节点列表完成DOM更新。相较于Vue2强制包裹的div，Fragment避免了不必要的DOM层级，解决如flex/grid布局中因冗余嵌套导致的样式错乱问题。&lt;/p>
&lt;p>具体处理时，当检测到新旧vnode均为Fragment类型，直接进入子节点diff流程。通过双端对比算法优化更新效率，仅对发生变化的子节点进行DOM操作。这种机制确保在保留响应式特性的同时，维持与CSS布局系统的原生兼容性。&lt;/p>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="a26ad1a" class="language-javascript ">
 &lt;code>// Vue3编译后的渲染函数示例
import { createVNode, openBlock, createBlock } from &amp;#39;vue&amp;#39;

export function render() {
 return (
 openBlock(),
 createBlock(
 Fragment, 
 null,
 [
 createVNode(&amp;#39;div&amp;#39;, null, &amp;#39;Node1&amp;#39;),
 createVNode(&amp;#39;span&amp;#39;, null, &amp;#39;Node2&amp;#39;)
 ],
 PatchFlags.STABLE_FRAGMENT // 标记子节点结构稳定
 )
 )
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>&lt;strong>边界处理&lt;/strong>：&lt;/p></description></item><item><title>Teleport组件的DOM传送场景</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-13/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-13/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;strong>核心能力维度&lt;/strong>：&lt;/p>
&lt;ol>
&lt;li>Vue框架特性理解（Teleport组件机制）&lt;/li>
&lt;li>CSS层叠上下文原理&lt;/li>
&lt;li>DOM渲染层级控制实战经验&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>技术评估点&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>Teleport组件如何解决样式隔离问题&lt;/li>
&lt;li>堆叠上下文（Stacking Context）的形成与影响&lt;/li>
&lt;li>CSS选择器在动态DOM环境中的可靠性&lt;/li>
&lt;li>多层级组件间的z-index管理策略&lt;/li>
&lt;li>响应式系统与DOM操作执行的时序问题&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>&lt;strong>堆叠上下文规则&lt;/strong> &amp;gt; &lt;strong>Teleport渲染机制&lt;/strong> &amp;gt; &lt;strong>CSS选择器穿透性&lt;/strong>&lt;/li>
&lt;li>&lt;strong>z-index生效条件&lt;/strong>：元素须处于同一堆叠上下文才可比较层级&lt;/li>
&lt;li>&lt;strong>目标容器稳定性&lt;/strong>：确保CSS选择器定位的DOM节点存在且稳定&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>当使用&lt;code>&amp;lt;Teleport to=&amp;quot;body&amp;quot;&amp;gt;&lt;/code>传送模态框时，组件将被渲染到&lt;code>&amp;lt;body&amp;gt;&lt;/code>末尾，脱离原组件树的渲染上下文。此时模态框的z-index直接与&lt;code>&amp;lt;body&amp;gt;&lt;/code>子节点比较，避免被父组件的低层级上下文覆盖。浏览器渲染时，&lt;strong>后出现的DOM节点默认层级更高&lt;/strong>，但需确保模态框的z-index值足够大（推荐2000+）以覆盖页面其他元素。&lt;/p>
&lt;p>&lt;strong>常见误区&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>错误认为提高z-index即可解决所有层级问题，忽视堆叠上下文隔离&lt;/li>
&lt;li>使用非稳定选择器（如&lt;code>.class&lt;/code>）可能导致目标容器意外变更&lt;/li>
&lt;li>未处理SSR场景下客户端注水时的DOM一致性&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;strong>避免z-index问题&lt;/strong>：&lt;/p>
&lt;ol>
&lt;li>将模态框传送至&lt;code>&amp;lt;body&amp;gt;&lt;/code>末尾，脱离父级堆叠上下文&lt;/li>
&lt;li>设置模态框z-index为2000以上（超越常规元素）&lt;/li>
&lt;li>确保目标容器（如&lt;code>&amp;lt;body&amp;gt;&lt;/code>）未创建新的堆叠上下文（避免使用transform/opacity）&lt;/li>
&lt;/ol>
&lt;p>&lt;strong>to属性注意事项&lt;/strong>：&lt;/p>
&lt;ol>
&lt;li>选择器应指向&lt;strong>稳定存在的DOM节点&lt;/strong>（推荐ID选择器）&lt;/li>
&lt;li>避免使用动态类名或复杂选择器，防止匹配元素变更&lt;/li>
&lt;li>服务端渲染时需确保客户端注水后目标节点存在&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="b23aee1" class="language-javascript ">
 &lt;code>// 安全使用Teleport的示例
&amp;lt;template&amp;gt;
 &amp;lt;Teleport to=&amp;#34;#modal-root&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;modal&amp;#34; :style=&amp;#34;{ zIndex: 2001 }&amp;#34;&amp;gt;
 &amp;lt;!-- 模态内容 --&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/Teleport&amp;gt;
&amp;lt;/template&amp;gt;

// 在public/index.html提前放置锚点
&amp;lt;body&amp;gt;
 &amp;lt;div id=&amp;#34;app&amp;#34;&amp;gt;&amp;lt;/div&amp;gt;
 &amp;lt;div id=&amp;#34;modal-root&amp;#34;&amp;gt;&amp;lt;/div&amp;gt; &amp;lt;!-- 专用容器 --&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>&lt;strong>优化建议&lt;/strong>：&lt;/p></description></item><item><title>Suspense组件的异步解决方案</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-14/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-14/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>React异步渲染机制&lt;/strong>：理解Suspense与React异步组件协同工作原理&lt;/li>
&lt;li>&lt;strong>组件状态协调&lt;/strong>：掌握fallback插槽在加载状态管理中的核心作用&lt;/li>
&lt;li>&lt;strong>错误边界设计&lt;/strong>：运用onErrorCaptured实现组件树异常捕获与降级处理&lt;/li>
&lt;li>&lt;strong>用户体验优化&lt;/strong>：实现加载骨架屏与优雅的错误提示方案&lt;/li>
&lt;/ol>
&lt;p>技术评估点：&lt;/p>
&lt;ul>
&lt;li>Suspense与React.lazy的协同机制&lt;/li>
&lt;li>错误边界组件与Suspense的嵌套顺序&lt;/li>
&lt;li>异步加载过程中错误冒泡机制&lt;/li>
&lt;li>骨架屏与错误回退的优先级逻辑&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>Suspense工作流 &amp;gt; 错误边界机制 &amp;gt; React.lazy实现原理&lt;/li>
&lt;li>错误冒泡捕获顺序 &amp;gt; 异步组件加载状态管理&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Suspense通过&lt;strong>子组件throw promise&lt;/strong>的机制实现加载状态协调。当包裹的异步组件处于加载状态时，React会暂停渲染并展示fallback内容。其核心流程为：&lt;/p>
&lt;ol>
&lt;li>React.lazy创建的组件初始化时抛出Promise&lt;/li>
&lt;li>Suspense边界捕获该Promise，触发加载状态&lt;/li>
&lt;li>Promise完成后重新渲染&lt;/li>
&lt;li>若加载失败，错误会冒泡至最近的错误边界&lt;/li>
&lt;/ol>
&lt;p>错误边界组件通过&lt;strong>class组件+getDerivedStateFromError&lt;/strong>实现异常捕获。当与Suspense配合时，错误边界必须包裹Suspense组件，才能捕获异步加载过程中发生的错误。&lt;/p>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>混淆Suspense与错误边界的职责（加载态与错误态）&lt;/li>
&lt;li>错误边界未正确包裹Suspense导致异常逃逸&lt;/li>
&lt;li>未处理异步组件加载失败场景&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Suspense通过双缓冲机制协调异步加载状态：当子组件未就绪时，触发fallback插槽内容渲染。结合错误边界时，需用错误边界组件包裹Suspense以捕获异步加载错误，形成完整的状态处理链。&lt;/p>
&lt;p>典型实现方案：&lt;/p>
&lt;ol>
&lt;li>错误边界组件使用&lt;code>componentDidCatch&lt;/code>捕获异常&lt;/li>
&lt;li>React.lazy动态加载目标组件&lt;/li>
&lt;li>Suspense设置fallback骨架屏&lt;/li>
&lt;li>错误边界包裹Suspense形成保护层&lt;/li>
&lt;/ol>
&lt;p>加载流程优先级：正常内容 &amp;gt; fallback &amp;gt; 错误提示。错误边界仅处理异常状态，不干扰常规加载流程。&lt;/p>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="57178fd" class="language-javascript ">
 &lt;code>// 错误边界容器
class ErrorBoundary extends React.Component {
 state = { hasError: false }
 
 static getDerivedStateFromError() {
 return { hasError: true }
 }

 componentDidCatch(error, info) {
 // 上报错误日志
 logError(error, info)
 }

 render() {
 return this.state.hasError 
 ? &amp;lt;ErrorView /&amp;gt;
 : this.props.children
 }
}

// 异步组件加载
const LazyComponent = React.lazy(() =&amp;gt; import(&amp;#39;./Component&amp;#39;))

// 视图层组合
function App() {
 return (
 &amp;lt;ErrorBoundary&amp;gt;
 &amp;lt;Suspense fallback={&amp;lt;Skeleton /&amp;gt;}&amp;gt;
 &amp;lt;LazyComponent /&amp;gt;
 &amp;lt;/Suspense&amp;gt;
 &amp;lt;/ErrorBoundary&amp;gt;
 )
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>&lt;strong>优化建议&lt;/strong>：&lt;/p></description></item><item><title>静态提升(Static Hoisting)优化原理</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-15/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-15/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该题目主要考察以下核心维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>编译器优化原理&lt;/strong>：理解Vue3编译阶段的静态分析机制&lt;/li>
&lt;li>&lt;strong>虚拟DOM机制&lt;/strong>：掌握diff算法优化与静态节点标记的关联&lt;/li>
&lt;li>&lt;strong>运行时性能优化&lt;/strong>：评估hoisting技术对渲染性能的实际影响&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>静态节点识别标准（没有动态绑定/ifeach/for）&lt;/li>
&lt;li>提升后的虚拟节点缓存方式（常量声明位置与复用逻辑）&lt;/li>
&lt;li>虚拟DOM diff过程中静态节点的跳过机制&lt;/li>
&lt;li>编译器输出对比分析能力&lt;/li>
&lt;li>优化前后的性能指标差异量化能力&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>静态分析（Static Analysis）&lt;/li>
&lt;li>常量提升（Hoisting）&lt;/li>
&lt;li>虚拟DOM复用（VNode Reuse）&lt;/li>
&lt;li>Diff算法路径优化&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3编译器在模板编译阶段通过AST分析识别静态节点（不含动态绑定/v指令的节点）。通过&lt;code>patchFlag&lt;/code>标记进行节点类型分类，将纯静态节点提升到渲染函数外部作为常量。编译后的渲染函数中，静态节点引用常量而非每次重新创建。&lt;/p>
&lt;p>当更新发生时，虚拟DOM树中的静态节点保持引用不变。Diff算法通过&lt;code>isSameVNodeType&lt;/code>检查时，由于新旧虚拟节点的引用地址相同，直接跳过比较。对于静态子树，该优化可使diff时间复杂度从O(n)降为O(动态节点数)。&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="ec33730" class="language-text ">
 &lt;code>// 编译前
render() {
 return h(&amp;#39;div&amp;#39;, [
 h(&amp;#39;span&amp;#39;, &amp;#39;static&amp;#39;),
 h(&amp;#39;p&amp;#39;, this.dynamic)
 ])
}

// 编译后
const _hoisted = h(&amp;#39;span&amp;#39;, &amp;#39;static&amp;#39;) // 静态提升
render() {
 return h(&amp;#39;div&amp;#39;, [
 _hoisted, // 引用常量
 h(&amp;#39;p&amp;#39;, this.dynamic)
 ])
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>误认为静态提升只作用于根节点（实际作用于所有层级静态节点）&lt;/li>
&lt;li>混淆模板静态性与数据响应式的关系&lt;/li>
&lt;li>认为优化仅减少内存分配（实际同时优化diff和内存）&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3编译器通过静态分析识别不含动态绑定的节点，将其提升为渲染函数外部的常量。首次渲染创建静态VNode后，后续更新直接复用该引用。虚拟DOM diff时，由于新旧VNode引用相同直接跳过比较，将时间复杂度从O(n)优化为仅处理动态节点。&lt;/p></description></item><item><title>Vue3组件通信方式的变化</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-16/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-16/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该问题主要考查候选人以下三个维度的理解：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>框架演进思维&lt;/strong>：理解Vue3精简核心代码库、拥抱Tree-shaking的设计哲学&lt;/li>
&lt;li>&lt;strong>响应式原理冲突&lt;/strong>：识别事件总线模式与响应式系统在内存管理、依赖追踪方面的根本矛盾&lt;/li>
&lt;li>&lt;strong>工程化权衡能力&lt;/strong>：对比内置事件机制与第三方库在类型安全、维护成本、性能开销等方面的差异&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>事件总线模式导致的隐式耦合问题&lt;/li>
&lt;li>响应式系统与手动内存管理的冲突&lt;/li>
&lt;li>Tree-shaking机制对框架设计的影响&lt;/li>
&lt;li>第三方事件库在TS支持、调试能力方面的优势&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>响应式系统 &amp;gt; 内存管理 &amp;gt; Tree-shaking &amp;gt; 类型安全&lt;/p>
&lt;h4 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;p>Vue3的事件接口移除本质是响应式范式与事件驱动范式的冲突：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>隐式依赖&lt;/strong>：事件总线创建全局订阅关系，与组件树结构解耦，导致调试时难以追踪事件流向&lt;/li>
&lt;li>&lt;strong>内存泄漏&lt;/strong>：手动管理$off的强依赖与响应式自动回收机制冲突，易出现未及时注销的监听器&lt;/li>
&lt;li>&lt;strong>架构污染&lt;/strong>：基于Vue实例的事件系统会携带完整的响应式能力，而mitt等库采用纯事件逻辑（类似Node.js的EventEmitter）&lt;/li>
&lt;/ol>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="8eceff2" class="language-text ">
 &lt;code>典型问题场景：
组件A --$emit--&amp;gt; EventBus --$on--&amp;gt; 组件B
│ │
└--- 卸载时忘记$off -----------&amp;gt; 内存泄漏&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h4 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;ul>
&lt;li>误认为$on/$off移除是API简化&lt;/li>
&lt;li>混淆事件总线与全局状态管理&lt;/li>
&lt;li>忽视组合式API与事件模式的范式冲突&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3移除事件总线接口主要基于三个设计考量：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>响应式治理&lt;/strong>：事件总线模式绕过Vue的响应式依赖追踪，导致组件卸载后残留订阅，破坏自动垃圾回收机制。mitt采用WeakMap存储监听器，在订阅者销毁时可自动释放内存&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>类型安全&lt;/strong>：第三方库如mitt提供完整的TypeScript支持，而Vue2的事件系统缺乏类型推导，&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="cc15df8" class="language-typescript ">
 &lt;code>// mitt示例类型约束
type Events = { foo: string }
const emitter = mitt&amp;lt;Events&amp;gt;()&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>体积优化&lt;/strong>：移除$on/$off符合Tree-shaking设计哲学，允许构建工具剔除未使用代码。第三方事件库（1KB）相比Vue2事件系统（内嵌在核心库）显著减小体积&lt;/p>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="编码示例">编码示例 &lt;a href="#%e7%bc%96%e7%a0%81%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="f36694b" class="language-javascript ">
 &lt;code>// 现代事件总线实现
import mitt from &amp;#39;mitt&amp;#39;

type AppEvents = {
 &amp;#39;search&amp;#39;: string
 &amp;#39;login&amp;#39;: UserInfo
}

export const emitter = mitt&amp;lt;AppEvents&amp;gt;()

// 组件内使用
onMounted(() =&amp;gt; {
 emitter.on(&amp;#39;search&amp;#39;, handleSearch)
})

onBeforeUnmount(() =&amp;gt; {
 emitter.off(&amp;#39;search&amp;#39;, handleSearch) // 显式注销
})

// 事件触发
emitter.emit(&amp;#39;search&amp;#39;, query)&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="可扩展性建议">可扩展性建议 &lt;a href="#%e5%8f%af%e6%89%a9%e5%b1%95%e6%80%a7%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>&lt;strong>大流量场景&lt;/strong>：采用节流模式包装事件处理器&lt;/li>
&lt;li>&lt;strong>低端设备&lt;/strong>：使用Map替代Object存储监听器以提升性能&lt;/li>
&lt;li>&lt;strong>调试模式&lt;/strong>：开发环境添加事件追踪中间件&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>如何实现跨组件事件追踪？&lt;/strong>
通过包装emit/监听函数添加debug信息&lt;/p></description></item><item><title>mitt库与EventBus的核心差异</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-17/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-17/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>框架机制理解&lt;/strong>：对比第三方库与框架内置方案的实现差异&lt;/li>
&lt;li>&lt;strong>类型系统应用&lt;/strong>：TypeScript高级类型在事件总线场景的实践&lt;/li>
&lt;li>&lt;strong>内存管理意识&lt;/strong>：事件监听场景下的资源释放策略&lt;/li>
&lt;li>&lt;strong>模块化设计&lt;/strong>：轻量化方案与框架强耦合实现的取舍&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>类型推导机制（泛型约束 vs 松散类型）&lt;/li>
&lt;li>事件监听器生命周期管理策略&lt;/li>
&lt;li>单例模式与实例化开销对比&lt;/li>
&lt;li>通配符事件支持与扩展性设计&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>TypeScript支持 &amp;gt; 内存泄漏预防 &amp;gt; 无实例化设计 &amp;gt; 通配符事件&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>&lt;strong>类型安全&lt;/strong>：Mitt通过泛型参数约束事件类型，如&lt;code>mitt&amp;lt;Events&amp;gt;&lt;/code>允许定义严格类型的事件名与载荷格式，Vue2的EventBus基于Vue实例的&lt;code>$emit&lt;/code>/&lt;code>$on&lt;/code>使用字符串类型事件名，缺乏类型校验&lt;/li>
&lt;li>&lt;strong>内存管理&lt;/strong>：Vue2需手动在组件&lt;code>beforeDestroy&lt;/code>阶段调用&lt;code>$off&lt;/code>，Mitt虽仍需手动调用&lt;code>off&lt;/code>，但通过&lt;code>on&lt;/code>返回的解绑函数（&lt;code>() =&amp;gt; void&lt;/code>）可与现代框架的&lt;code>onUnmounted&lt;/code>钩子天然配合&lt;/li>
&lt;li>&lt;strong>实例差异&lt;/strong>：Vue EventBus需&lt;code>new Vue()&lt;/code>创建实例（约20KB内存开销），Mitt采用纯对象发布订阅模式（&amp;lt;1KB），无虚拟DOM等额外开销&lt;/li>
&lt;li>&lt;strong>扩展机制&lt;/strong>：Mitt支持&lt;code>*&lt;/code>通配符监听所有事件，事件处理函数接收&lt;code>type&lt;/code>参数，Vue原生未提供类似功能&lt;/li>
&lt;/ol>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>认为Mitt会自动处理事件解绑（仍需主动调用）&lt;/li>
&lt;li>误用Vue的EventBus类型定义导致TS类型不安全&lt;/li>
&lt;li>低估实例化带来的内存消耗差异&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Mitt相较于Vue2 EventBus主要改进包括：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>类型支持&lt;/strong>：通过泛型约束事件类型，杜绝错误事件名和错误载荷类型&lt;/li>
&lt;li>&lt;strong>内存防护&lt;/strong>：配合组合式API的&lt;code>onUnmounted&lt;/code>可便捷实现监听清理，而Vue2选项式API易遗漏&lt;code>$off&lt;/code>&lt;/li>
&lt;li>&lt;strong>零实例&lt;/strong>：纯函数实现无需创建Vue实例，包体积减少97%且无响应式系统开销&lt;/li>
&lt;li>&lt;strong>通配符监听&lt;/strong>：&lt;code>on('*')&lt;/code>可统一处理日志上报等跨事件逻辑，Vue需手动维护事件列表&lt;/li>
&lt;/ol>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="74fd0d1" class="language-typescript ">
 &lt;code>// Mitt类型安全示例
type CustomEvents = {
 &amp;#39;search&amp;#39;: { query: string },
 &amp;#39;submit&amp;#39;: FormData
};

const emitter = mitt&amp;lt;CustomEvents&amp;gt;();

// 组件内使用
emitter.on(&amp;#39;search&amp;#39;, ({ query }) =&amp;gt; {
 if (query.length &amp;lt; 2) {
 console.error(&amp;#39;Query too short&amp;#39;);
 return;
 }
 // 搜索逻辑
});

// 组件卸载时自动解绑
onUnmounted(() =&amp;gt; {
 emitter.off(&amp;#39;search&amp;#39;);
});

// 通配符监听所有事件
emitter.on(&amp;#39;*&amp;#39;, (type, detail) =&amp;gt; {
 analytics.send(type, detail);
});&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>&lt;strong>优化建议&lt;/strong>：&lt;/p></description></item><item><title>Modal组件设计（组合API+Teleport）</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-18/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-18/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>组合式API应用能力&lt;/strong>：考察对Vue3组合式API的逻辑封装能力，能否将状态管理与逻辑复用有机结合&lt;/li>
&lt;li>&lt;strong>Portal机制理解&lt;/strong>：验证对Teleport特性的理解深度，能否正确实现跨DOM层级渲染&lt;/li>
&lt;li>&lt;strong>交互设计完整性&lt;/strong>：检测键盘事件与点击事件处理的完备性，包括事件委托与冒泡控制&lt;/li>
&lt;/ol>
&lt;p>技术评估点包括：&lt;/p>
&lt;ul>
&lt;li>响应式状态管理（ref/reactive）&lt;/li>
&lt;li>Teleport的DOM挂载机制&lt;/li>
&lt;li>事件监听的生命周期管理&lt;/li>
&lt;li>可复用组件的接口设计&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>Composition API逻辑封装 &amp;gt; Teleport实现机制 &amp;gt; 事件委托处理&lt;/li>
&lt;li>模态框状态通过ref驱动，封装为独立可复用模块&lt;/li>
&lt;li>Teleport解决z-index层级战争问题，确保模态框脱离父级上下文&lt;/li>
&lt;li>通过事件源判断实现精准的遮罩层点击检测&lt;/li>
&lt;li>通过键盘事件监听实现ESC关闭，注意多实例竞争条件&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>组合式API通过&lt;code>setup()&lt;/code>函数将状态逻辑打包为独立单元，使用&lt;code>provide/inject&lt;/code>实现跨组件状态共享。Teleport组件通过&lt;code>to&lt;/code>属性指定目标容器，解决模态框受父容器&lt;code>overflow:hidden&lt;/code>样式限制的问题。&lt;/p>
&lt;p>事件处理需注意：遮罩层点击事件需校验&lt;code>event.target&lt;/code>是否为遮罩层本体，防止内容区域点击误触发。ESC监听需在组件挂载时注册全局事件，并在卸载时及时销毁，避免内存泄漏。&lt;/p>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>直接使用事件冒泡处理遮罩层点击，导致内容区域误触发&lt;/li>
&lt;li>忘记移除全局事件监听导致多实例干扰&lt;/li>
&lt;li>未处理多个模态框同时存在时的ESC关闭优先级&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>使用组合式API封装模态框状态逻辑的核心是创建响应式状态容器。通过&lt;code>useModal&lt;/code>函数导出&lt;code>isOpen&lt;/code>状态和操作方法，Teleport组件确保模态框渲染到&lt;code>body&lt;/code>末端。遮罩层点击关闭通过校验事件目标实现，ESC关闭使用&lt;code>document.addEventListener&lt;/code>注册全局监听。&lt;/p>
&lt;p>关键技术实现：&lt;/p>
&lt;ol>
&lt;li>使用&lt;code>ref&lt;/code>创建响应式状态&lt;/li>
&lt;li>Teleport指定&lt;code>to=&amp;quot;body&amp;quot;&lt;/code>实现跨DOM层级渲染&lt;/li>
&lt;li>通过&lt;code>event.target === modalRef.value&lt;/code>精准判断遮罩层点击&lt;/li>
&lt;li>在&lt;code>onMounted&lt;/code>生命周期注册/移除事件监听&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="编码示例">编码示例 &lt;a href="#%e7%bc%96%e7%a0%81%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="135d5b4" class="language-javascript ">
 &lt;code>// 组合式逻辑封装
const useModal = () =&amp;gt; {
 const isOpen = ref(false)
 
 const open = () =&amp;gt; (isOpen.value = true)
 const close = () =&amp;gt; (isOpen.value = false)

 return { isOpen, open, close }
}

// 模态框组件
&amp;lt;template&amp;gt;
 &amp;lt;teleport to=&amp;#34;body&amp;#34;&amp;gt;
 &amp;lt;div v-if=&amp;#34;isOpen&amp;#34; class=&amp;#34;modal-mask&amp;#34; @click=&amp;#34;handleMaskClick&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;modal-content&amp;#34; ref=&amp;#34;modalContent&amp;#34;&amp;gt;
 &amp;lt;slot /&amp;gt;
 &amp;lt;button @click=&amp;#34;close&amp;#34;&amp;gt;关闭&amp;lt;/button&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/teleport&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import { ref, onMounted, onBeforeUnmount } from &amp;#39;vue&amp;#39;

const props = defineProps({
 // 支持自定义关闭策略
 closeOnEsc: { type: Boolean, default: true }
})

const { isOpen, close } = useModal()
const modalContent = ref(null)

const handleMaskClick = (event) =&amp;gt; {
 // 精准点击检测
 if (event.target === modalContent.value.parentElement) {
 close()
 }
}

// ESC关闭逻辑
const handleKeydown = (e) =&amp;gt; {
 if (e.key === &amp;#39;Escape&amp;#39; &amp;amp;&amp;amp; props.closeOnEsc) {
 close()
 }
}

onMounted(() =&amp;gt; {
 document.addEventListener(&amp;#39;keydown&amp;#39;, handleKeydown)
})

onBeforeUnmount(() =&amp;gt; {
 document.removeEventListener(&amp;#39;keydown&amp;#39;, handleKeydown)
})
&amp;lt;/script&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="可扩展性建议">可扩展性建议 &lt;a href="#%e5%8f%af%e6%89%a9%e5%b1%95%e6%80%a7%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>&lt;strong>性能优化&lt;/strong>：使用CSS transform代替top/left定位提升动画性能&lt;/li>
&lt;li>&lt;strong>多实例支持&lt;/strong>：通过事件优先级队列管理多个模态框的ESC关闭顺序&lt;/li>
&lt;li>&lt;strong>无障碍支持&lt;/strong>：添加role=&amp;ldquo;dialog&amp;quot;和aria-modal属性&lt;/li>
&lt;li>&lt;strong>低端设备适配&lt;/strong>：增加触摸事件支持，优化移动端点击体验&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>如何防止模态框内容被父组件CSS样式干扰？&lt;/strong>
提示：Teleport的DOM脱离+CSS作用域控制&lt;/p></description></item><item><title>自定义指令API的生命周期变化</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-19/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-19/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该题主要考察以下核心能力：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>框架机制理解&lt;/strong>：对Vue2到Vue3自定义指令API升级的迁移逻辑的掌握，尤其是钩子函数命名和触发逻辑的变化&lt;/li>
&lt;li>&lt;strong>生命周期对齐逻辑&lt;/strong>：理解指令生命周期与组件生命周期的对应关系，以及Vue3统一API命名背后的设计意图&lt;/li>
&lt;li>&lt;strong>版本差异分析&lt;/strong>：对比Vue2和Vue3的钩子触发顺序及参数变化，体现对底层原理的深入认知&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>新旧钩子映射关系（如&lt;code>bind&lt;/code>→&lt;code>beforeMount&lt;/code>，&lt;code>inserted&lt;/code>→&lt;code>mounted&lt;/code>）&lt;/li>
&lt;li>合并后钩子的触发时机（如&lt;code>mounted&lt;/code>合并了元素插入和绑定的场景）&lt;/li>
&lt;li>参数结构调整（如&lt;code>binding.value&lt;/code>标准化、移除&lt;code>vnode.context&lt;/code>）&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3指令生命周期设计 &amp;gt; 与组件生命周期对齐 &amp;gt; 参数规范化&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3为统一API设计，将指令生命周期与组件生命周期对齐。原先的&lt;code>bind&lt;/code>（元素绑定但未插入DOM）对应&lt;code>beforeMount&lt;/code>，&lt;code>inserted&lt;/code>（元素插入DOM后）对应&lt;code>mounted&lt;/code>。而&lt;code>update&lt;/code>和&lt;code>componentUpdated&lt;/code>被拆分为&lt;code>beforeUpdate&lt;/code>（数据变化但DOM未更新）和&lt;code>updated&lt;/code>（DOM更新后）。&lt;/p>
&lt;p>&lt;code>inserted&lt;/code>的功能被合并到&lt;code>mounted&lt;/code>中，&lt;strong>触发逻辑变为&lt;/strong>：当指令绑定元素完成DOM插入且父组件挂载后触发，仅执行一次。此举消除了Vue2中&lt;code>bind&lt;/code>和&lt;code>inserted&lt;/code>的割裂感，例如在绑定动态样式后插入DOM的场景不再需要分开处理。&lt;/p>
&lt;h3 id="参数变化">参数变化 &lt;a href="#%e5%8f%82%e6%95%b0%e5%8f%98%e5%8c%96" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>Vue2：&lt;code>el, binding, vnode, oldVnode&lt;/code>&lt;/li>
&lt;li>Vue3：&lt;code>el, binding, vnode, prevVNode&lt;/code>&lt;br>
&lt;code>binding&lt;/code>对象新增&lt;code>instance&lt;/code>属性指向组件实例，&lt;code>value&lt;/code>和&lt;code>oldValue&lt;/code>标准化为固定字段，删除&lt;code>expression&lt;/code>字符串的冗余解析。&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3的自定义指令生命周期钩子重命名主要是为了与组件生命周期对齐，提升API一致性。&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>重命名逻辑&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>&lt;code>bind&lt;/code> → &lt;code>beforeMount&lt;/code>（元素attribute绑定后，插入DOM前）&lt;/li>
&lt;li>&lt;code>inserted&lt;/code> → &lt;code>mounted&lt;/code>（元素插入父组件且子组件挂载完成）&lt;/li>
&lt;li>&lt;code>update&lt;/code>和&lt;code>componentUpdated&lt;/code>合并为&lt;code>beforeUpdate&lt;/code>和&lt;code>updated&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>inserted合并逻辑&lt;/strong>：&lt;/p>
&lt;p>原&lt;code>inserted&lt;/code>的DOM插入检测被整合到&lt;code>mounted&lt;/code>，当指令绑定元素&lt;strong>首次完成DOM插入&lt;/strong>时触发。若元素初始为&lt;code>v-if=&amp;quot;false&amp;quot;&lt;/code>后变为&lt;code>true&lt;/code>，会再次触发&lt;code>mounted&lt;/code>。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>参数变化&lt;/strong>：&lt;/p>
&lt;ul>
&lt;li>&lt;code>binding.oldValue&lt;/code>直接反映旧值，无需通过&lt;code>update&lt;/code>钩子对比&lt;/li>
&lt;li>&lt;code>vnode&lt;/code>和&lt;code>prevVNode&lt;/code>分别代表当前与上一次的虚拟节点&lt;/li>
&lt;li>移除&lt;code>vnode.context&lt;/code>，改为通过&lt;code>binding.instance&lt;/code>获取组件实例&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="编码示例">编码示例 &lt;a href="#%e7%bc%96%e7%a0%81%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="6b793f9" class="language-javascript ">
 &lt;code>const customDirective = {
 beforeMount(el, binding) {
 // 替代Vue2的bind：初始化样式
 el.style.color = binding.value;
 },
 mounted(el, binding) {
 // 替代Vue2的inserted：DOM插入后记录日志
 console.log(`Inserted to ${binding.instance.$el.tagName}`);
 },
 updated(el, binding) {
 // 替代Vue2的componentUpdated：更新后对比值
 if (binding.value !== binding.oldValue) {
 el.style.color = binding.value;
 }
 }
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="可扩展性建议">可扩展性建议 &lt;a href="#%e5%8f%af%e6%89%a9%e5%b1%95%e6%80%a7%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>&lt;strong>性能敏感场景&lt;/strong>：在&lt;code>beforeUpdate&lt;/code>中缓存&lt;code>binding.value&lt;/code>减少DOM操作&lt;/li>
&lt;li>&lt;strong>SSR兼容&lt;/strong>：在&lt;code>mounted&lt;/code>中添加客户端特有逻辑，通过&lt;code>if (process.client)&lt;/code>隔离&lt;/li>
&lt;li>&lt;strong>低端设备&lt;/strong>：在&lt;code>unmounted&lt;/code>中手动清理事件监听，防止内存泄漏&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>为何Vue3移除&lt;code>vnode.context&lt;/code>？&lt;/strong>&lt;br>
答：与组件实例解耦，通过&lt;code>binding.instance&lt;/code>显式获取&lt;/p></description></item><item><title>v-if与v-for优先级变化(Vue3)</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-20/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-20/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下三个核心维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vue框架机制理解&lt;/strong>：考察对Vue指令优先级变化及编译原理的掌握程度&lt;/li>
&lt;li>&lt;strong>性能优化意识&lt;/strong>：评估对无效渲染的认知及避免策略&lt;/li>
&lt;li>&lt;strong>工程实践能力&lt;/strong>：测试在复杂场景下的指令组合使用技巧&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>Vue3指令优先级变更的底层逻辑&lt;/li>
&lt;li>无效循环渲染的产生原因及优化原理&lt;/li>
&lt;li>template标签在指令组合中的桥梁作用&lt;/li>
&lt;li>计算属性在数据预处理的性能优势&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue指令优先级 &amp;gt; 编译阶段处理顺序 &amp;gt; 虚拟DOM优化&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3通过编译器将template转换为渲染函数时，采用新的优先级策略：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>静态分析阶段&lt;/strong>检测到v-if会生成条件判断逻辑分支&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>v-for指令&lt;/strong>被转换为可迭代的_createElementVNode调用&lt;/p>
&lt;/li>
&lt;li>
&lt;p>当两者共存时，v-if的判断条件会包裹整个v-for循环，形成类似伪代码结构：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="93868ec" class="language-javascript ">
 &lt;code>if (condition) {
 return list.map(item =&amp;gt; createElement(...))
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;/li>
&lt;/ol>
&lt;p>这种结构改变使得当condition为false时直接跳过整个列表渲染，避免了Vue2时代需要先遍历所有元素再逐个进行条件判断的资源浪费。&lt;/p>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>误认为优先级变化仅影响运行时顺序&lt;/li>
&lt;li>在条件判断依赖循环变量时直接混用指令&lt;/li>
&lt;li>忽略计算属性缓存机制对重复计算的优化作用&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>在Vue3中，v-if优先级高于v-for的设计通过编译阶段的静态分析优化，使得当条件判断失败时直接跳过整个循环的渲染逻辑。这避免了Vue2中先循环后判断导致的无效节点创建，尤其在大数据量场景下显著提升性能。&lt;/p>
&lt;p>正确使用方法：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>模板隔离法&lt;/strong>：使用&lt;code>&amp;lt;template&amp;gt;&lt;/code>标签分离作用域&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="81a54a3" class="language-vue ">
 &lt;code>&amp;lt;template v-if=&amp;#34;isShow&amp;#34;&amp;gt;
 &amp;lt;div v-for=&amp;#34;item in list&amp;#34; :key=&amp;#34;item.id&amp;#34;&amp;gt;
 {{ item.name }}
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>数据预处理&lt;/strong>：通过计算属性过滤数据源&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="6e2e202" class="language-html ">
 &lt;code>&amp;lt;div 
 v-for=&amp;#34;item in filteredList&amp;#34;
 :key=&amp;#34;item.id&amp;#34;
&amp;gt;
 {{ item.name }}
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
computed: {
 filteredList() {
 return this.list.filter(item =&amp;gt; item.visible)
 }
}
&amp;lt;/script&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;/li>
&lt;/ol>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="编码示例">编码示例 &lt;a href="#%e7%bc%96%e7%a0%81%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="6c6c915" class="language-vue ">
 &lt;code>&amp;lt;!-- 方案1：模板包裹 --&amp;gt;
&amp;lt;template v-if=&amp;#34;user.isAdmin&amp;#34;&amp;gt;
 &amp;lt;ul&amp;gt;
 &amp;lt;li 
 v-for=&amp;#34;item in sensitiveItems&amp;#34;
 :key=&amp;#34;item.id&amp;#34;
 &amp;gt;
 {{ item.content }}
 &amp;lt;/li&amp;gt;
 &amp;lt;/ul&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;!-- 方案2：计算属性优化 --&amp;gt;
&amp;lt;template&amp;gt;
 &amp;lt;div 
 v-for=&amp;#34;msg in filteredMessages&amp;#34;
 :key=&amp;#34;msg.id&amp;#34;
 class=&amp;#34;message&amp;#34;
 &amp;gt;
 &amp;lt;span v-if=&amp;#34;!msg.isDeleted&amp;#34;&amp;gt;{{ msg.text }}&amp;lt;/span&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
const filteredMessages = computed(() =&amp;gt; 
 messages.value.filter(m =&amp;gt; m.valid &amp;amp;&amp;amp; !m.isDeleted)
)
&amp;lt;/script&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="可扩展性建议">可扩展性建议 &lt;a href="#%e5%8f%af%e6%89%a9%e5%b1%95%e6%80%a7%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>大数据量场景建议配合&lt;code>v-memo&lt;/code>减少Diff计算&lt;/li>
&lt;li>低端设备可使用&lt;code>&amp;lt;TransitionGroup&amp;gt;&lt;/code>实现渲染批处理&lt;/li>
&lt;li>配合&lt;code>&amp;lt;Suspense&amp;gt;&lt;/code>实现异步数据加载时的优雅降级&lt;/li>
&lt;/ul>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>v-for中key的作用及错误使用后果?&lt;/strong>&lt;/p></description></item><item><title>v-memo指令的缓存优化作用</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-21/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-21/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vue框架原理理解&lt;/strong>：对Vue3新特性及虚拟DOM更新机制的掌握程度&lt;/li>
&lt;li>&lt;strong>性能优化思维&lt;/strong>：针对大型列表场景的渲染优化策略选择能力&lt;/li>
&lt;li>&lt;strong>API应用能力&lt;/strong>：对v-memo指令参数配置和边界条件的把控&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点包括：&lt;/p>
&lt;ul>
&lt;li>虚拟DOM diff算法瓶颈认知&lt;/li>
&lt;li>记忆化技术（memoization）在框架层的实现原理&lt;/li>
&lt;li>依赖数组（dependency array）的深浅比较机制&lt;/li>
&lt;li>动态模板与静态子树的条件更新策略&lt;/li>
&lt;li>指令使用误区与性能反模式识别&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>虚拟DOM复用 &amp;gt; 依赖数组比较 &amp;gt; Patch算法优化&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>v-memo通过缓存虚拟DOM子树及其快照依赖值，在组件更新时：&lt;/p>
&lt;ol>
&lt;li>对比当前依赖数组与缓存快照&lt;/li>
&lt;li>若依赖未变更，跳过整个子树的patch过程&lt;/li>
&lt;li>直接复用已存在的虚拟DOM节点&lt;/li>
&lt;/ol>
&lt;p>技术实现要点：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="1b03800" class="language-javascript ">
 &lt;code>const cached = {
 deps: prevDeps,
 vnode: prevVNode
}
if (isSame(cached.deps, newDeps)) {
 return cached.vnode
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>在动态内容上使用导致更新失效（如：误缓存包含v-for索引的表达式）&lt;/li>
&lt;li>依赖数组包含引用类型时未注意深浅比较规则&lt;/li>
&lt;li>过度使用导致内存泄漏（缓存大量DOM节点）&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>v-memo通过缓存虚拟DOM子树及对应的依赖快照，在组件更新时若依赖值未变化，直接跳过该子树diff过程。例如在表格渲染时，对稳定行数据声明&lt;code>v-memo=&amp;quot;[row.id, row.status]&lt;/code>，当行ID和状态未改变时，即使父组件触发更新，该行也不会重新渲染。&lt;/p>
&lt;hr>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="编码示例">编码示例 &lt;a href="#%e7%bc%96%e7%a0%81%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="014ceef" class="language-vue ">
 &lt;code>&amp;lt;template&amp;gt;
 &amp;lt;tr v-for=&amp;#34;row in rows&amp;#34; :key=&amp;#34;row.id&amp;#34; v-memo=&amp;#34;[row.id, row.status]&amp;#34;&amp;gt;
 &amp;lt;!-- 静态内容占比80%的列 --&amp;gt;
 &amp;lt;td&amp;gt;{{ row.id }}&amp;lt;/td&amp;gt;
 &amp;lt;td&amp;gt;{{ row.name }}&amp;lt;/td&amp;gt;
 &amp;lt;td&amp;gt;{{ formatDate(row.createTime) }}&amp;lt;/td&amp;gt;
 
 &amp;lt;!-- 动态内容需要排除在memo之外 --&amp;gt;
 &amp;lt;td :class=&amp;#34;{ warning: row.status === &amp;#39;pending&amp;#39; }&amp;#34;&amp;gt;
 {{ row.status }}
 &amp;lt;/td&amp;gt;
 &amp;lt;/tr&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="优化说明">优化说明 &lt;a href="#%e4%bc%98%e5%8c%96%e8%af%b4%e6%98%8e" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>&lt;strong>时间复杂度&lt;/strong>：将O(n)的diff计算降为O(1)（命中缓存时）&lt;/li>
&lt;li>&lt;strong>内存消耗&lt;/strong>：需缓存N个vnode，适用于长列表但更新不频繁的场景&lt;/li>
&lt;li>&lt;strong>防踩坑&lt;/strong>：避免缓存包含&lt;code>index&lt;/code>或临时ID的表达式&lt;/li>
&lt;/ol>
&lt;h3 id="扩展建议">扩展建议 &lt;a href="#%e6%89%a9%e5%b1%95%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>低端设备可结合&lt;code>&amp;lt;Teleport&amp;gt;&lt;/code>分块渲染&lt;/li>
&lt;li>高频更新场景建议改用&lt;code>v-once&lt;/code>彻底静态化&lt;/li>
&lt;li>监控内存使用情况防止过度缓存&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="如何验证v-memo是否生效">如何验证v-memo是否生效？ &lt;a href="#%e5%a6%82%e4%bd%95%e9%aa%8c%e8%af%81v-memo%e6%98%af%e5%90%a6%e7%94%9f%e6%95%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>使用Vue DevTools的&amp;quot;Timeline&amp;quot;面板观察组件更新频率&lt;/p></description></item><item><title>渲染函数h函数的导入变化</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-22/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-22/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该问题主要考察以下三个核心维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>模块化设计理解&lt;/strong>：评估对ES Modules机制及显式依赖管理的认知&lt;/li>
&lt;li>&lt;strong>编译优化原理&lt;/strong>：检验Tree-shaking工作机制及其在前端工程化的应用&lt;/li>
&lt;li>&lt;strong>框架架构演进&lt;/strong>：理解Vue3设计哲学变化对生态扩展性的影响&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>ESM模块化与全局变量的优劣对比&lt;/li>
&lt;li>Tree-shaking消除无用代码的触发条件&lt;/li>
&lt;li>自定义渲染器的依赖解耦方式&lt;/li>
&lt;li>框架运行时体积的精细化控制&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>ES Modules &amp;gt; Tree-shaking机制 &amp;gt; 渲染器抽象层设计&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3将h函数从全局注入改为显式导入，主要基于：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>模块精准控制&lt;/strong>：ESM强制显式依赖声明，避免隐式全局变量导致的命名冲突和不可预测性。通过&lt;code>import { h } from 'vue'&lt;/code>明确标识依赖关系，符合现代打包工具（Rollup、Webpack）的静态分析要求。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Tree-shaking优化&lt;/strong>：当h函数未使用时，打包工具通过import语句可准确判定代码使用情况，将未引用的渲染函数剔除。对比Vue2全局注入模式，即使未使用h函数也会保留在最终产物中。&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>渲染器可插拔&lt;/strong>：自定义渲染器开发时，可通过不同import路径引入特定版本的h函数。例如：&lt;/p>
&lt;/li>
&lt;/ol>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="6b3b36b" class="language-javascript ">
 &lt;code>// 自定义WebGL渲染器
import { createRenderer } from &amp;#39;@vue/runtime-core&amp;#39;
import { nodeOps } from &amp;#39;@vue/runtime-webgl&amp;#39;
const { h } = createRenderer(nodeOps)
// 与传统DOM渲染器解耦&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>误区一：&amp;ldquo;手动导入增加开发负担&amp;rdquo; → 实际上通过SFC编译模板自动注入h函数&lt;/li>
&lt;li>误区二：&amp;ldquo;Tree-shaking完全依赖ESM&amp;rdquo; → 需要配合代码压缩工具（如Terser）的DCE（Dead Code Elimination）&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3要求手动导入h函数的核心考量是：&lt;/p></description></item><item><title>组合式API的TS类型推导改进</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-23/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-23/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;strong>核心能力维度&lt;/strong>：TypeScript集成能力、Vue框架原理理解、类型系统设计思想&lt;/p>
&lt;ul>
&lt;li>&lt;strong>TS类型推导机制&lt;/strong>：考察对泛型推断、类型收窄的理解&lt;/li>
&lt;li>&lt;strong>响应式API设计差异&lt;/strong>：对比ref/reactive与Options API的类型声明方式&lt;/li>
&lt;li>&lt;strong>上下文类型追踪&lt;/strong>：setup函数中变量引用的类型流维护&lt;/li>
&lt;li>&lt;strong>开发体验优化&lt;/strong>：类型提示准确性对编码效率的影响&lt;/li>
&lt;li>&lt;strong>复合类型处理&lt;/strong>：处理嵌套对象、联合类型时的类型保障&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>泛型参数自动推断（&lt;code>ref('str')&lt;/code> =&amp;gt; &lt;code>Ref&amp;lt;string&amp;gt;&lt;/code>）&lt;/li>
&lt;li>函数式API的上下文保留（vs Options API的配置对象分离）&lt;/li>
&lt;li>类型推导与响应式代理的协作（&lt;code>reactive&amp;lt;T&amp;gt;&lt;/code>与&lt;code>UnwrapNestedRefs&lt;/code>）&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>组合式API通过函数返回值类型显式声明类型系统路径。当开发者调用&lt;code>ref('value')&lt;/code>时：&lt;/p>
&lt;ol>
&lt;li>TS编译器自动推导&lt;code>value&lt;/code>参数为string类型&lt;/li>
&lt;li>&lt;code>ref&lt;/code>函数泛型参数&lt;code>T&lt;/code>被推断为string&lt;/li>
&lt;li>返回类型&lt;code>Ref&amp;lt;string&amp;gt;&lt;/code>携带类型元信息&lt;/li>
&lt;/ol>
&lt;p>在Options API中，类型声明分散在&lt;code>data&lt;/code>、&lt;code>methods&lt;/code>等独立配置项中，类型系统需通过&lt;code>ThisType&lt;/code>等机制重建上下文关联。而setup函数采用命令式编码，变量引用形成显式依赖链，TS可通过代码顺序准确推导箭头函数返回值类型。&lt;/p>
&lt;p>&lt;strong>类型扩展&lt;/strong>：当使用&lt;code>reactive({ user: { name: '' } })&lt;/code>时，TS会递归推导嵌套属性类型，而Options API的&lt;code>data&lt;/code>需要手动声明接口或使用类型断言。&lt;/p>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>混淆ref.value的类型（误判为包含value属性的普通对象）&lt;/li>
&lt;li>Options API中未使用Type声明导致方法内this类型丢失&lt;/li>
&lt;li>复杂类型场景过度依赖类型断言（应优先使用泛型参数）&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>组合式API通过函数式编程范式强化类型推导：&lt;/p>
&lt;ol>
&lt;li>&lt;code>ref&lt;/code>/&lt;code>reactive&lt;/code>等工厂函数通过泛型参数传递类型，TS根据初始值自动推断&lt;/li>
&lt;li>Setup函数上下文变量呈线性声明，类型推导链路完整，避免Options API的配置对象类型分裂&lt;/li>
&lt;li>响应式变量类型自动展开（如&lt;code>Ref&amp;lt;T&amp;gt;&lt;/code>访问时自动解包为T），而Options API依赖组件实例合并类型&lt;/li>
&lt;/ol>
&lt;p>对比示例：Options API需在data()显式声明返回类型并维护methods中的this类型，而组合式API通过变量定义自然携带类型信息。&lt;/p>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="c016c8d" class="language-typescript ">
 &lt;code>// 组合式API类型推导示例
import { defineComponent, ref, reactive } from &amp;#39;vue&amp;#39;

interface User {
 name: string
 age: number
}

export default defineComponent({
 setup() {
 // 基础类型自动推导为Ref&amp;lt;string&amp;gt;
 const username = ref(&amp;#39;&amp;#39;)
 
 // 复杂对象显式泛型
 const user = reactive&amp;lt;User&amp;gt;({
 name: &amp;#39;John&amp;#39;,
 age: 30
 })

 // 自动推导出( (e: Event) =&amp;gt; void
 const handleChange = (e: Event) =&amp;gt; {
 username.value = (e.target as HTMLInputElement).value
 }

 return { username, handleChange }
 }
})&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>&lt;strong>优化点&lt;/strong>：&lt;/p></description></item><item><title>defineProps/defineEmits类型声明</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-24/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-24/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Vue3组合式API的深度应用&lt;/strong>：考察对&lt;code>&amp;lt;script setup&amp;gt;&lt;/code>语法糖中类型声明机制的理解&lt;/li>
&lt;li>&lt;strong>TypeScript高级类型运用&lt;/strong>：评估接口继承、联合类型等特性在组件通信中的实际应用&lt;/li>
&lt;li>&lt;strong>类型系统与运行时行为的结合&lt;/strong>：验证类型定义如何影响组件API的设计与校验&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>泛型语法在defineProps/defineEmits中的正确使用&lt;/li>
&lt;li>接口继承实现类型扩展的能力&lt;/li>
&lt;li>字面量类型在组件属性校验中的应用&lt;/li>
&lt;li>默认值处理与类型系统的协同&lt;/li>
&lt;li>事件发射器的类型安全约束&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>组件Props类型声明（泛型 &amp;gt; 接口继承 &amp;gt; 字面量联合）&lt;/li>
&lt;li>事件发射器类型约束（函数重载 &amp;gt; 索引签名）&lt;/li>
&lt;li>默认值处理（withDefaults）&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>在&lt;code>&amp;lt;script setup&amp;gt;&lt;/code>中，&lt;code>defineProps&lt;/code>和&lt;code>defineEmits&lt;/code>是编译器宏，通过泛型参数传递类型信息。TypeScript编译器会解析这些类型参数并生成运行时类型校验逻辑。当使用接口继承时，类型系统会通过结构化类型检查实现类型兼容。&lt;/p>
&lt;p>事件发射器的类型定义采用函数调用签名形式，每个事件对应一个函数类型声明，参数列表需严格匹配发射时的参数结构。字面量联合类型则通过枚举约束实现编译时校验。&lt;/p>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>混淆运行时校验与编译时类型检查&lt;/li>
&lt;li>忘记使用withDefaults处理默认值导致类型不匹配&lt;/li>
&lt;li>错误使用函数参数解构破坏类型推断&lt;/li>
&lt;li>事件名采用非字面量类型导致类型失效&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>在&lt;code>&amp;lt;script setup&amp;gt;&lt;/code>中通过泛型定义类型化props/emits：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="38d0d63" class="language-typescript ">
 &lt;code>&amp;lt;script setup lang=&amp;#34;ts&amp;#34;&amp;gt;
// 基础接口
interface BaseProps {
 /** 组件唯一标识 */
 id: string
}

// 扩展接口 &amp;#43; 字面量类型
interface ComponentProps extends BaseProps {
 /** 用户姓名（必填） */
 name: string
 /** 用户年龄（默认25） */
 age?: number
 /** 状态标识 */
 status: &amp;#39;loading&amp;#39; | &amp;#39;success&amp;#39; | &amp;#39;error&amp;#39;
}

// 带默认值的类型化props
const props = withDefaults(defineProps&amp;lt;ComponentProps&amp;gt;(), {
 age: 25,
 status: &amp;#39;loading&amp;#39;
})

// 事件类型声明（函数重载方式）
interface EmitEvents {
 (e: &amp;#39;dataChange&amp;#39;, payload: { id: string }): void
 (e: &amp;#39;submit&amp;#39;): void
}

const emit = defineEmits&amp;lt;EmitEvents&amp;gt;()
&amp;lt;/script&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="编码示例">编码示例 &lt;a href="#%e7%bc%96%e7%a0%81%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="d1ba9e5" class="language-typescript ">
 &lt;code>// 复杂类型校验示例
interface AdvancedProps {
 /** 动态表单配置 */
 config: {
 fields: Array&amp;lt;{
 name: string
 inputType: &amp;#39;text&amp;#39; | &amp;#39;number&amp;#39; | &amp;#39;date&amp;#39;
 }&amp;gt;
 }
}

// 组合接口继承
interface FormProps extends AdvancedProps, BaseProps {
 /** 提交按钮文本 */
 submitText?: string
}

// 事件发射器扩展
type FormEmits = {
 (e: &amp;#39;formSubmit&amp;#39;, values: Record&amp;lt;string, unknown&amp;gt;): void
 (e: &amp;#39;validationFail&amp;#39;, errors: string[]): void
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="可扩展性建议">可扩展性建议 &lt;a href="#%e5%8f%af%e6%89%a9%e5%b1%95%e6%80%a7%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>&lt;strong>类型复用&lt;/strong>：通过类型导出实现跨组件复用类型定义&lt;/li>
&lt;li>&lt;strong>性能优化&lt;/strong>：复杂对象类型使用Readonly修饰符避免不必要的响应式转换&lt;/li>
&lt;li>&lt;strong>设备适配&lt;/strong>：对低端设备可分离基础类型和扩展类型按需加载&lt;/li>
&lt;/ol>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>如何实现嵌套对象的深度类型校验？&lt;/strong>&lt;/p></description></item><item><title>Vue3的IE11兼容性方案</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-25/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-25/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;strong>核心能力维度&lt;/strong>：Vue工程化配置能力、浏览器兼容性处理经验、构建工具链理解深度&lt;br>
&lt;strong>技术评估点&lt;/strong>：&lt;/p>
&lt;ol>
&lt;li>对ES6+特性向后兼容方案的掌握（Proxy/enerator-runtime）&lt;/li>
&lt;li>Babel配置与polyfill机制的实际运用能力&lt;/li>
&lt;li>对node_modules依赖转换策略的理解（transpileDeps工作原理）&lt;/li>
&lt;li>IE11特有兼容问题的处理经验（CSS变量/对象API）&lt;/li>
&lt;li>构建体积与兼容方案的权衡意识&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>&lt;code>core-js&lt;/code> &amp;gt; &lt;code>@babel/preset-env&lt;/code> &amp;gt; &lt;code>browserslist&lt;/code>配置优先级&lt;/li>
&lt;li>&lt;code>@vue/cli&lt;/code>构建链 &amp;gt; &lt;code>transpileDeps&lt;/code>实现机制 &amp;gt; &lt;code>useBuiltIns&lt;/code>配置策略&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3默认使用Proxy实现响应式，但IE11不支持且无法polyfill。兼容方案需：&lt;/p>
&lt;ol>
&lt;li>替换为&lt;code>@vue/composition-api&lt;/code> + &lt;code>reactivity&lt;/code>模块的非Proxy实现&lt;/li>
&lt;li>通过&lt;code>core-js&lt;/code>提供缺失的ES6+ API（Map/Set/Promise等）&lt;/li>
&lt;li>&lt;code>babel.config.js&lt;/code>配置&lt;code>presets&lt;/code>使用&lt;code>useBuiltIns: 'usage'&lt;/code>自动按需注入polyfill&lt;/li>
&lt;li>&lt;code>transpileDeps&lt;/code>通过白名单机制将node_modules中的ES6+依赖强制经过Babel转译&lt;/li>
&lt;/ol>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="52c3999" class="language-javascript ">
 &lt;code>// babel.config.js
module.exports = {
 presets: [
 [&amp;#39;@vue/cli-plugin-babel/preset&amp;#39;, {
 useBuiltIns: &amp;#39;usage&amp;#39;, // 按需注入polyfill
 corejs: 3 // 指定core-js版本
 }]
 ]
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>误认为&lt;code>proxy-polyfill&lt;/code>可完整实现Proxy（仅支持部分功能）&lt;/li>
&lt;li>未配置&lt;code>transpileDeps&lt;/code>导致第三方库ES6语法未转换&lt;/li>
&lt;li>&lt;code>core-js&lt;/code>全局污染与按需加载的配置混淆&lt;/li>
&lt;li>忽略CSS自定义属性的&lt;code>postcss-custom-properties&lt;/code>兼容处理&lt;/li>
&lt;/ol>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;strong>Polyfill配置步骤&lt;/strong>：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>安装&lt;code>core-js@3&lt;/code>、&lt;code>regenerator-runtime&lt;/code>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>入口文件顶部引入：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="cad32b3" class="language-javascript ">
 &lt;code>import &amp;#39;core-js/stable&amp;#39; 
import &amp;#39;regenerator-runtime/runtime&amp;#39;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;/li>
&lt;li>
&lt;p>使用&lt;code>@babel/plugin-transform-runtime&lt;/code>减少重复注入&lt;/p></description></item><item><title>Vue3移除API的替代方案</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-26/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-26/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>该题目主要考察以下核心能力维度：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>框架演进理解&lt;/strong>：是否掌握Vue3的设计理念与破坏性变更&lt;/li>
&lt;li>&lt;strong>API迁移能力&lt;/strong>：针对已废弃特性能否给出官方推荐替代方案&lt;/li>
&lt;li>&lt;strong>架构设计思维&lt;/strong>：理解不同状态管理方案的适用场景及优劣对比&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>过滤器（Filters）的现代化替代方案&lt;/li>
&lt;li>$children的替代实现方式&lt;/li>
&lt;li>事件总线（Event Bus）模式的问题分析&lt;/li>
&lt;li>状态管理方案的选型依据&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>Composition API &amp;gt; 过滤器替代&lt;/li>
&lt;li>ref/scoped slots &amp;gt; $children替代&lt;/li>
&lt;li>Provide/estore &amp;gt; 事件总线替代&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Vue3移除过滤器的核心逻辑在于提升模板的JavaScript表达能力。通过方法调用（{{ formatDate(date) }}）或计算属性，开发者可以获得类型安全与更好的TS支持。$children的移除源于其不可靠的组件树遍历特性，改用ref获取具体子组件实例可避免隐式依赖。&lt;/p>
&lt;p>事件总线的问题突出表现在响应式追踪失效和内存泄漏风险。基于Provide/Inject的依赖注入模式通过清晰的组件层级关系进行通信，而Pinia等状态库通过集中式store管理跨组件状态，配合Vue Devtools可实现完整的状态变更追溯。&lt;/p>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>错误地在组合式函数中尝试使用过滤器&lt;/li>
&lt;li>通过$parent逆向操作破坏组件封装性&lt;/li>
&lt;li>在大型项目中滥用事件总线导致调试困难&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>Vue3官方推荐的API替代方案如下：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>过滤器（Filter）&lt;/strong>：改用方法调用或计算属性。例如将&lt;code>{{ text | uppercase }}&lt;/code>改写为&lt;code>{{ uppercase(text) }}&lt;/code>，或在setup中使用computed处理复杂逻辑&lt;/li>
&lt;li>&lt;strong>$children&lt;/strong>：使用模板ref获取特定子组件引用，或通过作用域插槽传递数据。跨层级通信推荐provide/inject&lt;/li>
&lt;li>&lt;strong>事件总线&lt;/strong>：改用provide/inject传递回调函数，或采用Pinia进行状态管理。事件总线因缺乏响应式追踪、易引发内存泄漏，且不利于维护而被废弃&lt;/li>
&lt;/ol>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="事件总线替代示例">事件总线替代示例 &lt;a href="#%e4%ba%8b%e4%bb%b6%e6%80%bb%e7%ba%bf%e6%9b%bf%e4%bb%a3%e7%a4%ba%e4%be%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="4e4fad9" class="language-javascript ">
 &lt;code>// 使用Pinia状态管理
import { defineStore } from &amp;#39;pinia&amp;#39;

const eventStore = defineStore(&amp;#39;events&amp;#39;, {
 state: () =&amp;gt; ({
 listeners: {}
 }),
 actions: {
 on(event, callback) {
 (this.listeners[event] ||= []).push(callback)
 },
 emit(event, ...args) {
 this.listeners[event]?.forEach(fn =&amp;gt; fn(...args))
 }
 }
})

// 组件中使用
const store = eventStore()
store.on(&amp;#39;refresh&amp;#39;, () =&amp;gt; {...})
store.emit(&amp;#39;refresh&amp;#39;)&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="扩展建议">扩展建议 &lt;a href="#%e6%89%a9%e5%b1%95%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>低端设备：采用事件节流并及时清理监听器&lt;/li>
&lt;li>超大应用：结合Pinia的模块化store进行状态拆分&lt;/li>
&lt;li>SSR场景：使用Symbol作为provide的key避免命名冲突&lt;/li>
&lt;/ul>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;ol>
&lt;li>
&lt;p>&lt;strong>如何防止provide/inject的滥用导致组件耦合？&lt;/strong>
采用类型约束与接口声明，通过TS确保注入内容的契约性&lt;/p></description></item><item><title>组合式API+Teleport实现Modal</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-27/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-27/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="核心能力维度">核心能力维度 &lt;a href="#%e6%a0%b8%e5%bf%83%e8%83%bd%e5%8a%9b%e7%bb%b4%e5%ba%a6" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>组合式API应用&lt;/strong>：考察逻辑复用能力与响应式状态管理&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Teleport机制理解&lt;/strong>：评估对DOM挂载位置与样式作用域的掌握&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>可访问性实践&lt;/strong>：验证键盘交互与焦点管理的规范化实现&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>动画集成方案&lt;/strong>：测试过渡动画与组件生命周期的协调能力&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="技术评估点">技术评估点 &lt;a href="#%e6%8a%80%e6%9c%af%e8%af%84%e4%bc%b0%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>Teleport的DOM挂载策略及其对CSS层叠上下文的影响&lt;/li>
&lt;li>组合式API中状态管理与组件通信的合理抽象&lt;/li>
&lt;li>事件监听的绑定/解绑与内存泄漏防范&lt;/li>
&lt;li>符合WAI-ARIA标准的焦点控制实现&lt;/li>
&lt;li>CSS Transition与组件挂载/卸载时序的协同&lt;/li>
&lt;/ul>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Teleport &amp;gt; Composition API &amp;gt; Focus Trap &amp;gt; Keyboard Events &amp;gt; CSS Transition&lt;/p>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>
&lt;p>&lt;strong>Teleport机制&lt;/strong>：将模态框渲染至&lt;code>&amp;lt;body&amp;gt;&lt;/code>末端，避免父组件&lt;code>position: relative&lt;/code>导致的定位失效。通过&lt;code>to&lt;/code>属性指定目标容器，保持全局样式稳定性&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>响应式控制&lt;/strong>：使用&lt;code>ref&lt;/code>管理开闭状态，通过&lt;code>defineEmits&lt;/code>暴露&lt;code>open/close&lt;/code>事件。采用&lt;code>v-model&lt;/code>语法糖实现双向绑定&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>事件管理&lt;/strong>：组件挂载时注册&lt;code>keydown&lt;/code>监听，处理ESC关闭。卸载时通过&lt;code>removeEventListener&lt;/code>防止内存泄漏。使用&lt;code>tabindex=&amp;quot;-1&amp;quot;&lt;/code>与&lt;code>focus-trap&lt;/code>库实现焦点锁定&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>动画集成&lt;/strong>：&lt;code>&amp;lt;Transition&amp;gt;&lt;/code>组件配合&lt;code>enter-active-class&lt;/code>实现入场/离场动画。注意&lt;code>duration&lt;/code>属性与CSS动画时间的同步，防止DOM提前卸载&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>未在&lt;code>onUnmounted&lt;/code>清除事件监听导致内存泄漏&lt;/li>
&lt;li>直接修改props违反单向数据流原则&lt;/li>
&lt;li>使用&lt;code>setTimeout&lt;/code>处理动画导致时序错乱&lt;/li>
&lt;li>忽略&lt;code>role=&amp;quot;dialog&amp;quot;&lt;/code>等ARIA属性影响可访问性&lt;/li>
&lt;/ul>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>实现步骤如下：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Teleport挂载&lt;/strong>：将模态框内容传送至body末端，避免CSS层级问题&lt;/li>
&lt;li>&lt;strong>组合式状态&lt;/strong>：使用&lt;code>ref&lt;/code>控制显隐状态，通过&lt;code>defineEmits&lt;/code>触发状态变更&lt;/li>
&lt;li>&lt;strong>键盘监听&lt;/strong>：在&lt;code>onMounted&lt;/code>注册ESC键监听，&lt;code>onUnmounted&lt;/code>移除&lt;/li>
&lt;li>&lt;strong>焦点管理&lt;/strong>：使用&lt;code>autofocus&lt;/code>属性与&lt;code>focus-trap-vue&lt;/code>库实现焦点锁定&lt;/li>
&lt;li>&lt;strong>动画过渡&lt;/strong>：&lt;code>&amp;lt;Transition&amp;gt;&lt;/code>包裹模态内容，配置&lt;code>enter-active&lt;/code>等动画类&lt;/li>
&lt;/ol>
&lt;h2 id="解决方案">解决方案 &lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>


 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="0f4ed7c" class="language-javascript ">
 &lt;code>// Modal.vue
&amp;lt;template&amp;gt;
 &amp;lt;Teleport :to=&amp;#34;target&amp;#34;&amp;gt;
 &amp;lt;Transition name=&amp;#34;modal&amp;#34; @after-leave=&amp;#34;$emit(&amp;#39;close&amp;#39;)&amp;#34;&amp;gt;
 &amp;lt;div v-if=&amp;#34;isOpen&amp;#34; 
 role=&amp;#34;dialog&amp;#34;
 class=&amp;#34;modal-wrap&amp;#34;
 @keydown.esc=&amp;#34;handleClose&amp;#34;&amp;gt;
 &amp;lt;div class=&amp;#34;modal-content&amp;#34;&amp;gt;
 &amp;lt;slot /&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/Transition&amp;gt;
 &amp;lt;/Teleport&amp;gt;
&amp;lt;/template&amp;gt;

&amp;lt;script setup&amp;gt;
import { ref, onMounted, onUnmounted } from &amp;#39;vue&amp;#39;

const props = defineProps({
 modelValue: Boolean,
 target: { type: String, default: &amp;#39;body&amp;#39; }
})
const emit = defineEmits([&amp;#39;update:modelValue&amp;#39;])

const isOpen = ref(false)

// 控制显隐同步
watch(() =&amp;gt; props.modelValue, val =&amp;gt; isOpen.value = val)
watch(isOpen, val =&amp;gt; emit(&amp;#39;update:modelValue&amp;#39;, val))

// ESC关闭处理
const handleClose = () =&amp;gt; isOpen.value = false

// 键盘监听
const keyHandler = (e) =&amp;gt; {
 if (e.key === &amp;#39;Escape&amp;#39;) handleClose()
}

onMounted(() =&amp;gt; window.addEventListener(&amp;#39;keydown&amp;#39;, keyHandler))
onUnmounted(() =&amp;gt; window.removeEventListener(&amp;#39;keydown&amp;#39;, keyHandler))
&amp;lt;/script&amp;gt;

&amp;lt;style&amp;gt;
.modal-enter-active, .modal-leave-active {
 transition: opacity 0.3s ease;
}
.modal-enter-from, .modal-leave-to {
 opacity: 0;
}
&amp;lt;/style&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="可扩展性建议">可扩展性建议 &lt;a href="#%e5%8f%af%e6%89%a9%e5%b1%95%e6%80%a7%e5%bb%ba%e8%ae%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>&lt;strong>动态挂载点&lt;/strong>：通过&lt;code>target&lt;/code>prop支持自定义挂载容器&lt;/li>
&lt;li>&lt;strong>动画增强&lt;/strong>：集成&lt;code>animate.css&lt;/code>实现多样化过渡效果&lt;/li>
&lt;li>&lt;strong>全局状态&lt;/strong>：结合Pinia管理多模态框的叠加状态&lt;/li>
&lt;li>&lt;strong>性能优化&lt;/strong>：添加&lt;code>lazy&lt;/code>修饰符实现按需加载模态内容&lt;/li>
&lt;/ol>
&lt;h2 id="深度追问">深度追问 &lt;a href="#%e6%b7%b1%e5%ba%a6%e8%bf%bd%e9%97%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="追问1如何实现点击外部关闭">追问1：如何实现点击外部关闭？ &lt;a href="#%e8%bf%bd%e9%97%ae1%e5%a6%82%e4%bd%95%e5%ae%9e%e7%8e%b0%e7%82%b9%e5%87%bb%e5%a4%96%e9%83%a8%e5%85%b3%e9%97%ad" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>提示：使用&lt;code>@click.self&lt;/code>判断点击区域&lt;/p></description></item><item><title>组件库Tree shaking优化策略</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-28/</link><pubDate>Tue, 04 Mar 2025 07:00:31 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/vue3-28/</guid><description>&lt;h2 id="考察点分析">考察点分析 &lt;a href="#%e8%80%83%e5%af%9f%e7%82%b9%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>本题主要考察以下核心能力：&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Tree Shaking机制理解&lt;/strong>：能否准确阐述ES模块静态分析原理及其与打包工具的配合机制&lt;/li>
&lt;li>&lt;strong>组件库架构设计&lt;/strong>：是否掌握模块化导出方案，包括多入口、分包策略等工程化实践&lt;/li>
&lt;li>&lt;strong>构建工具配置能力&lt;/strong>：对Vite/Rollup配置项的掌握程度，特别是preserveModules等高级优化配置&lt;/li>
&lt;/ol>
&lt;p>具体技术评估点：&lt;/p>
&lt;ul>
&lt;li>ES模块导出规范与CommonJS差异&lt;/li>
&lt;li>Rollup的preserveModules模式工作原理&lt;/li>
&lt;li>副作用标注与package.json配置&lt;/li>
&lt;li>组件目录结构与构建输出的映射关系&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="技术解析">技术解析 &lt;a href="#%e6%8a%80%e6%9c%af%e8%a7%a3%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="关键知识点">关键知识点 &lt;a href="#%e5%85%b3%e9%94%ae%e7%9f%a5%e8%af%86%e7%82%b9" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ol>
&lt;li>ES Module静态结构 &amp;gt; Rollup模块保留 &amp;gt; 副作用标注&lt;/li>
&lt;li>组件独立分包 &amp;gt; 构建输出优化&lt;/li>
&lt;/ol>
&lt;h3 id="原理剖析">原理剖析 &lt;a href="#%e5%8e%9f%e7%90%86%e5%89%96%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>Tree Shaking依赖于ESM的静态语法特征，打包工具通过模块依赖图谱分析未被引用的导出。当组件库采用&lt;code>export const Component&lt;/code>形式导出时，Rollup能精准识别未使用代码。配合&lt;code>preserveModules: true&lt;/code>配置，会保留原始模块结构而非打包成单一chunk，保障按需引入的可行性。&lt;/p>
&lt;h3 id="常见误区">常见误区 &lt;a href="#%e5%b8%b8%e8%a7%81%e8%af%af%e5%8c%ba" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;ul>
&lt;li>误用&lt;code>export default&lt;/code>导致导出分析失效&lt;/li>
&lt;li>未配置&lt;code>sideEffects: false&lt;/code>阻碍优化&lt;/li>
&lt;li>组件耦合导致的隐性依赖（如全局样式）&lt;/li>
&lt;/ul>
&lt;hr>
&lt;h2 id="问题解答">问题解答 &lt;a href="#%e9%97%ae%e9%a2%98%e8%a7%a3%e7%ad%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>实现Tree Shaking需遵循以下步骤：&lt;/p>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>模块规范&lt;/strong>：组件使用具名导出&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="5cdf106" class="language-javascript ">
 &lt;code>// src/components/Button/index.ts
export const Button = defineComponent({...})&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>入口聚合&lt;/strong>：主文件二次导出&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="136f263" class="language-javascript ">
 &lt;code>// src/index.ts
export * from &amp;#39;./components/Button&amp;#39;
export * from &amp;#39;./components/Input&amp;#39;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Vite配置&lt;/strong>：&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="e02f57a" class="language-javascript ">
 &lt;code>// vite.config.js
export default defineConfig({
 build: {
 lib: {
 entry: &amp;#39;src/index.ts&amp;#39;,
 formats: [&amp;#39;es&amp;#39;]
 },
 rollupOptions: {
 external: [&amp;#39;vue&amp;#39;],
 output: {
 preserveModules: true, // 保留模块结构
 dir: &amp;#39;dist&amp;#39;, // 分包输出目录
 entryFileNames: &amp;#39;[name].js&amp;#39; // 按源文件名生成
 }
 }
 }
})&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>package.json声明&lt;/strong>：&lt;/p></description></item><item><title>composition api 与 options api 的区别</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/composition/</link><pubDate>Tue, 04 Mar 2025 05:09:42 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/composition/</guid><description>&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/8d6dd7b0-6048-11eb-85f6-6fac77c0c9b3_500289547022069739.png" alt="" width="798" height="333" loading="lazy">
 
 
&lt;/p>
&lt;h2 id="开始之前">开始之前 &lt;a href="#%e5%bc%80%e5%a7%8b%e4%b9%8b%e5%89%8d" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;code>Composition API&lt;/code> 可以说是&lt;code>Vue3&lt;/code>的最大特点，那么为什么要推出&lt;code>Composition Api&lt;/code>，解决了什么问题？&lt;/p>
&lt;p>通常使用&lt;code>Vue2&lt;/code>开发的项目，普遍会存在以下问题：&lt;/p>
&lt;ul>
&lt;li>代码的可读性随着组件变大而变差&lt;/li>
&lt;li>每一种代码复用的方式，都存在缺点&lt;/li>
&lt;li>TypeScript支持有限&lt;/li>
&lt;/ul>
&lt;p>以上通过使用&lt;code>Composition Api&lt;/code>都能迎刃而解&lt;/p>
&lt;h2 id="正文">正文 &lt;a href="#%e6%ad%a3%e6%96%87" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;h3 id="一options-api">一、Options Api &lt;a href="#%e4%b8%80options-api" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>&lt;code>Options API&lt;/code>，即大家常说的选项API，即以&lt;code>vue&lt;/code>为后缀的文件，通过定义&lt;code>methods&lt;/code>，&lt;code>computed&lt;/code>，&lt;code>watch&lt;/code>，&lt;code>data&lt;/code>等属性与方法，共同处理页面逻辑&lt;/p>
&lt;p>如下图：&lt;/p>
&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/9bf6d9d0-6048-11eb-85f6-6fac77c0c9b3_15302821252189520008.png" alt="" width="446" height="812" loading="lazy">
 
 
&lt;/p>
&lt;p>可以看到&lt;code>Options&lt;/code>代码编写方式，如果是组件状态，则写在&lt;code>data&lt;/code>属性上，如果是方法，则写在&lt;code>methods&lt;/code>属性上&amp;hellip;&lt;/p>
&lt;p>用组件的选项 (&lt;code>data&lt;/code>、&lt;code>computed&lt;/code>、&lt;code>methods&lt;/code>、&lt;code>watch&lt;/code>) 组织逻辑在大多数情况下都有效&lt;/p>
&lt;p>然而，当组件变得复杂，导致对应属性的列表也会增长，这可能会导致组件难以阅读和理解&lt;/p>
&lt;h3 id="二composition-api">二、Composition Api &lt;a href="#%e4%ba%8ccomposition-api" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>在 Vue3 Composition API 中，组件根据逻辑功能来组织的，一个功能所定义的所有 API 会放在一起（更加的高内聚，低耦合）&lt;/p>
&lt;p>即使项目很大，功能很多，我们都能快速的定位到这个功能所用到的所有 API&lt;/p>
&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/acee9200-6048-11eb-ab90-d9ae814b240d_14574544542324112622.png" alt="" width="633" height="465" loading="lazy">
 
 
&lt;/p>
&lt;h3 id="三对比">三、对比 &lt;a href="#%e4%b8%89%e5%af%b9%e6%af%94" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>下面对&lt;code>Composition Api&lt;/code>与&lt;code>Options Api&lt;/code>进行两大方面的比较&lt;/p>
&lt;ul>
&lt;li>逻辑组织&lt;/li>
&lt;li>逻辑复用&lt;/li>
&lt;/ul>
&lt;h4 id="逻辑组织">逻辑组织 &lt;a href="#%e9%80%bb%e8%be%91%e7%bb%84%e7%bb%87" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;h5 id="options-api">Options API &lt;a href="#options-api" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h5>&lt;p>假设一个组件是一个大型组件，其内部有很多处理逻辑关注点（对应下图不用颜色）&lt;/p>
&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/dc83d070-6048-11eb-ab90-d9ae814b240d_12528168000047516509.png" alt="" width="227" height="899" loading="lazy">
 
 
&lt;/p>
&lt;p>可以看到，这种碎片化使得理解和维护复杂组件变得困难&lt;/p>
&lt;p>选项的分离掩盖了潜在的逻辑问题。此外，在处理单个逻辑关注点时，我们必须不断地“跳转”相关代码的选项块&lt;/p>
&lt;h5 id="compostion-api">Compostion API &lt;a href="#compostion-api" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h5>&lt;p>而&lt;code>Compositon API&lt;/code>正是解决上述问题，将某个逻辑关注点相关的代码全都放在一个函数里，这样当需要修改一个功能时，就不再需要在文件中跳来跳去&lt;/p>
&lt;p>下面举个简单例子，将处理&lt;code>count&lt;/code>属性相关的代码放在同一个函数了&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="3656353" class="language-js ">
 &lt;code>function useCount() {
 let count = ref(10);
 let double = computed(() =&amp;gt; {
 return count.value * 2;
 });

 const handleConut = () =&amp;gt; {
 count.value = count.value * 2;
 };

 console.log(count);

 return {
 count,
 double,
 handleConut,
 };
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>组件上中使用&lt;code>count&lt;/code>&lt;/p></description></item><item><title>vue3 的设计目标是什么？做了哪些优化？</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/goal/</link><pubDate>Tue, 04 Mar 2025 05:09:42 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/goal/</guid><description>&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/b93b49c0-5c58-11eb-85f6-6fac77c0c9b3_18178961954897622608.png" alt="" width="586" height="446" loading="lazy">
 
 
&lt;/p>
&lt;h2 id="一设计目标">一、设计目标 &lt;a href="#%e4%b8%80%e8%ae%be%e8%ae%a1%e7%9b%ae%e6%a0%87" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>不以解决实际业务痛点的更新都是耍流氓，下面我们来列举一下&lt;code>Vue3&lt;/code>之前我们或许会面临的问题&lt;/p>
&lt;ul>
&lt;li>
&lt;p>随着功能的增长，复杂组件的代码变得越来越难以维护&lt;/p>
&lt;/li>
&lt;li>
&lt;p>缺少一种比较「干净」的在多个组件之间提取和复用逻辑的机制&lt;/p>
&lt;/li>
&lt;li>
&lt;p>类型推断不够友好&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;code>bundle&lt;/code>的时间太久了&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>而 &lt;code>Vue3&lt;/code> 经过长达两三年时间的筹备，做了哪些事情？&lt;/p>
&lt;p>我们从结果反推&lt;/p>
&lt;ul>
&lt;li>更小&lt;/li>
&lt;li>更快&lt;/li>
&lt;li>TypeScript支持&lt;/li>
&lt;li>API设计一致性&lt;/li>
&lt;li>提高自身可维护性&lt;/li>
&lt;li>开放更多底层功能&lt;/li>
&lt;/ul>
&lt;p>一句话概述，就是更小更快更友好了&lt;/p>
&lt;h3 id="更小">更小 &lt;a href="#%e6%9b%b4%e5%b0%8f" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>&lt;code>Vue3&lt;/code>移除一些不常用的 &lt;code>API&lt;/code>&lt;/p>
&lt;p>引入&lt;code>tree-shaking&lt;/code>，可以将无用模块“剪辑”，仅打包需要的，使打包的整体体积变小了&lt;/p>
&lt;h3 id="更快">更快 &lt;a href="#%e6%9b%b4%e5%bf%ab" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>主要体现在编译方面：&lt;/p>
&lt;ul>
&lt;li>diff算法优化&lt;/li>
&lt;li>静态提升&lt;/li>
&lt;li>事件监听缓存&lt;/li>
&lt;li>SSR优化&lt;/li>
&lt;/ul>
&lt;p>下篇文章我们会进一步介绍&lt;/p>
&lt;h3 id="更友好">更友好 &lt;a href="#%e6%9b%b4%e5%8f%8b%e5%a5%bd" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>&lt;code>vue3&lt;/code>在兼顾&lt;code>vue2&lt;/code>的&lt;code>options API&lt;/code>的同时还推出了&lt;code>composition API&lt;/code>，大大增加了代码的逻辑组织和代码复用能力&lt;/p>
&lt;p>这里代码简单演示下：&lt;/p>
&lt;p>存在一个获取鼠标位置的函数&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="b2ef61a" class="language-js ">
 &lt;code>import { toRefs, reactive } from &amp;#39;vue&amp;#39;;
function useMouse(){
 const state = reactive({x:0,y:0});
 const update = e=&amp;gt;{
 state.x = e.pageX;
 state.y = e.pageY;
 }
 onMounted(()=&amp;gt;{
 window.addEventListener(&amp;#39;mousemove&amp;#39;,update);
 })
 onUnmounted(()=&amp;gt;{
 window.removeEventListener(&amp;#39;mousemove&amp;#39;,update);
 })

 return toRefs(state);
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>我们只需要调用这个函数，即可获取&lt;code>x&lt;/code>、&lt;code>y&lt;/code>的坐标，完全不用关注实现过程&lt;/p></description></item><item><title>vue3 实现一个 Modal 组件设计思路与流程分析</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/modal_component/</link><pubDate>Tue, 04 Mar 2025 05:09:42 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/modal_component/</guid><description>&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/e294c660-6370-11eb-ab90-d9ae814b240d_4971991143697332478.png" alt="" width="686" height="332" loading="lazy">
 
 
&lt;/p>
&lt;h2 id="一组件设计">一、组件设计 &lt;a href="#%e4%b8%80%e7%bb%84%e4%bb%b6%e8%ae%be%e8%ae%a1" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>组件就是把图形、非图形的各种逻辑均抽象为一个统一的概念（组件）来实现开发的模式&lt;/p>
&lt;p>现在有一个场景，点击新增与编辑都弹框出来进行填写，功能上大同小异，可能只是标题内容或者是显示的主体内容稍微不同&lt;/p>
&lt;p>这时候就没必要写两个组件，只需要根据传入的参数不同，组件显示不同内容即可&lt;/p>
&lt;p>这样，下次开发相同界面程序时就可以写更少的代码，意义着更高的开发效率，更少的 &lt;code>Bug&lt;/code>和更少的程序体积&lt;/p>
&lt;h2 id="二需求分析">二、需求分析 &lt;a href="#%e4%ba%8c%e9%9c%80%e6%b1%82%e5%88%86%e6%9e%90" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>实现一个&lt;code>Modal&lt;/code>组件，首先确定需要完成的内容：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>遮罩层&lt;/p>
&lt;/li>
&lt;li>
&lt;p>标题内容&lt;/p>
&lt;/li>
&lt;li>
&lt;p>主体内容&lt;/p>
&lt;/li>
&lt;li>
&lt;p>确定和取消按钮&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>主体内容需要灵活，所以可以是字符串，也可以是一段 &lt;code>html&lt;/code> 代码&lt;/p>
&lt;p>特点是它们在当前&lt;code>vue&lt;/code>实例之外独立存在，通常挂载于&lt;code>body&lt;/code>之上&lt;/p>
&lt;p>除了通过引入&lt;code>import&lt;/code>的形式，我们还可通过&lt;code>API&lt;/code>的形式进行组件的调用&lt;/p>
&lt;p>还可以包括配置全局样式、国际化、与&lt;code>typeScript&lt;/code>结合&lt;/p>
&lt;h2 id="三实现流程">三、实现流程 &lt;a href="#%e4%b8%89%e5%ae%9e%e7%8e%b0%e6%b5%81%e7%a8%8b" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>首先看看大致流程：&lt;/p>
&lt;ul>
&lt;li>
&lt;p>目录结构&lt;/p>
&lt;/li>
&lt;li>
&lt;p>组件内容&lt;/p>
&lt;/li>
&lt;li>
&lt;p>实现 API 形式&lt;/p>
&lt;/li>
&lt;li>
&lt;p>事件处理&lt;/p>
&lt;/li>
&lt;li>
&lt;p>其他完善&lt;/p>
&lt;/li>
&lt;/ul>
&lt;h3 id="目录结构">目录结构 &lt;a href="#%e7%9b%ae%e5%bd%95%e7%bb%93%e6%9e%84" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>&lt;code>Modal&lt;/code>组件相关的目录结构&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="38f8f3c" class="language- ">
 &lt;code>├── plugins
│ └── modal
│ ├── Content.tsx // 维护 Modal 的内容，用于 h 函数和 jsx 语法
│ ├── Modal.vue // 基础组件
│ ├── config.ts // 全局默认配置
│ ├── index.ts // 入口
│ ├── locale // 国际化相关
│ │ ├── index.ts
│ │ └── lang
│ │ ├── en-US.ts
│ │ ├── zh-CN.ts
│ │ └── zh-TW.ts
│ └── modal.type.ts // ts类型声明相关&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>因为 Modal 会被 &lt;code>app.use(Modal)&lt;/code> 调用作为一个插件，所以都放在&lt;code>plugins&lt;/code>目录下&lt;/p></description></item><item><title>vue3 的性能提升主要体现在哪些方面？</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/performance/</link><pubDate>Tue, 04 Mar 2025 05:09:42 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/performance/</guid><description>&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/2aac1020-5ed0-11eb-ab90-d9ae814b240d_860186573834899124.png" alt="" width="599" height="335" loading="lazy">
 
 
&lt;/p>
&lt;h2 id="一编译阶段">一、编译阶段 &lt;a href="#%e4%b8%80%e7%bc%96%e8%af%91%e9%98%b6%e6%ae%b5" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>回顾&lt;code>Vue2&lt;/code>，我们知道每个组件实例都对应一个 &lt;code>watcher&lt;/code> 实例，它会在组件渲染的过程中把用到的数据&lt;code>property&lt;/code>记录为依赖，当依赖发生改变，触发&lt;code>setter&lt;/code>，则会通知&lt;code>watcher&lt;/code>，从而使关联的组件重新渲染&lt;/p>
&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/39066120-5ed0-11eb-85f6-6fac77c0c9b3_6751908681866011602.png" alt="" width="813" height="510" loading="lazy">
 
 
&lt;/p>
&lt;p>试想一下，一个组件结构如下图&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="f925dd8" class="language-html ">
 &lt;code>&amp;lt;template&amp;gt;
 &amp;lt;div id=&amp;#34;content&amp;#34;&amp;gt;
 &amp;lt;p class=&amp;#34;text&amp;#34;&amp;gt;静态文本&amp;lt;/p&amp;gt;
 &amp;lt;p class=&amp;#34;text&amp;#34;&amp;gt;静态文本&amp;lt;/p&amp;gt;
 &amp;lt;p class=&amp;#34;text&amp;#34;&amp;gt;{{ message }}&amp;lt;/p&amp;gt;
 &amp;lt;p class=&amp;#34;text&amp;#34;&amp;gt;静态文本&amp;lt;/p&amp;gt;
 ...
 &amp;lt;p class=&amp;#34;text&amp;#34;&amp;gt;静态文本&amp;lt;/p&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/template&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>可以看到，组件内部只有一个动态节点，剩余一堆都是静态节点，所以这里很多 &lt;code>diff&lt;/code> 和遍历其实都是不需要的，造成性能浪费&lt;/p>
&lt;p>因此，&lt;code>Vue3&lt;/code>在编译阶段，做了进一步优化。主要有如下：&lt;/p>
&lt;ul>
&lt;li>diff算法优化&lt;/li>
&lt;li>静态提升&lt;/li>
&lt;li>事件监听缓存&lt;/li>
&lt;li>SSR优化&lt;/li>
&lt;/ul>
&lt;h4 id="diff算法优化">diff算法优化 &lt;a href="#diff%e7%ae%97%e6%b3%95%e4%bc%98%e5%8c%96" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;p>&lt;code>vue3&lt;/code>在&lt;code>diff&lt;/code>算法中相比&lt;code>vue2&lt;/code>增加了静态标记&lt;/p>
&lt;p>关于这个静态标记，其作用是为了会发生变化的地方添加一个&lt;code>flag&lt;/code>标记，下次发生变化的时候直接找该地方进行比较&lt;/p>
&lt;p>下图这里，已经标记静态节点的&lt;code>p&lt;/code>标签在&lt;code>diff&lt;/code>过程中则不会比较，把性能进一步提高&lt;/p>
&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/c732e150-5c58-11eb-ab90-d9ae814b240d_14829205727065374514.png" alt="" width="930" height="306" loading="lazy">
 
 
&lt;/p>
&lt;p>关于静态类型枚举如下&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="f2bc194" class="language-js ">
 &lt;code>export const enum PatchFlags {
 TEXT = 1,// 动态的文本节点
 CLASS = 1 &amp;lt;&amp;lt; 1, // 2 动态的 class
 STYLE = 1 &amp;lt;&amp;lt; 2, // 4 动态的 style
 PROPS = 1 &amp;lt;&amp;lt; 3, // 8 动态属性，不包括类名和样式
 FULL_PROPS = 1 &amp;lt;&amp;lt; 4, // 16 动态 key，当 key 变化时需要完整的 diff 算法做比较
 HYDRATE_EVENTS = 1 &amp;lt;&amp;lt; 5, // 32 表示带有事件监听器的节点
 STABLE_FRAGMENT = 1 &amp;lt;&amp;lt; 6, // 64 一个不会改变子节点顺序的 Fragment
 KEYED_FRAGMENT = 1 &amp;lt;&amp;lt; 7, // 128 带有 key 属性的 Fragment
 UNKEYED_FRAGMENT = 1 &amp;lt;&amp;lt; 8, // 256 子节点没有 key 的 Fragment
 NEED_PATCH = 1 &amp;lt;&amp;lt; 9, // 512
 DYNAMIC_SLOTS = 1 &amp;lt;&amp;lt; 10, // 动态 solt
 HOISTED = -1, // 特殊标志是负整数表示永远不会用作 diff
 BAIL = -2 // 一个特殊的标志，指代差异算法
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h4 id="静态提升">静态提升 &lt;a href="#%e9%9d%99%e6%80%81%e6%8f%90%e5%8d%87" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h4>&lt;p>&lt;code>Vue3&lt;/code>中对不参与更新的元素，会做静态提升，只会被创建一次，在渲染时直接复用&lt;/p></description></item><item><title>proxy api 与 defineProperty API 比较</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/proxy/</link><pubDate>Tue, 04 Mar 2025 05:09:42 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/proxy/</guid><description>&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/57aa5c80-5f7f-11eb-ab90-d9ae814b240d_6851859592509317384.png" alt="" width="713" height="335" loading="lazy">
 
 
&lt;/p>
&lt;h2 id="一objectdefineproperty">一、Object.defineProperty &lt;a href="#%e4%b8%80objectdefineproperty" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>定义：&lt;code>Object.defineProperty()&lt;/code> 方法会直接在一个对象上定义一个新属性，或者修改一个对象的现有属性，并返回此对象&lt;/p>
&lt;h5 id="为什么能实现响应式">为什么能实现响应式 &lt;a href="#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%83%bd%e5%ae%9e%e7%8e%b0%e5%93%8d%e5%ba%94%e5%bc%8f" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h5>&lt;p>通过&lt;code>defineProperty&lt;/code> 两个属性，&lt;code>get&lt;/code>及&lt;code>set&lt;/code>&lt;/p>
&lt;ul>
&lt;li>get&lt;/li>
&lt;/ul>
&lt;p>属性的 getter 函数，当访问该属性时，会调用此函数。执行时不传入任何参数，但是会传入 this 对象（由于继承关系，这里的this并不一定是定义该属性的对象）。该函数的返回值会被用作属性的值&lt;/p>
&lt;ul>
&lt;li>set&lt;/li>
&lt;/ul>
&lt;p>属性的 setter 函数，当属性值被修改时，会调用此函数。该方法接受一个参数（也就是被赋予的新值），会传入赋值时的 this 对象。默认为 undefined&lt;/p>
&lt;p>下面通过代码展示：&lt;/p>
&lt;p>定义一个响应式函数&lt;code>defineReactive&lt;/code>&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="1034a29" class="language-js ">
 &lt;code>function update() {
 app.innerText = obj.foo
}

function defineReactive(obj, key, val) {
 Object.defineProperty(obj, key, {
 get() {
 console.log(`get ${key}:${val}`);
 return val
 },
 set(newVal) {
 if (newVal !== val) {
 val = newVal
 update()
 }
 }
 })
}&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>调用&lt;code>defineReactive&lt;/code>，数据发生变化触发&lt;code>update&lt;/code>方法，实现数据响应式&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="24c531f" class="language-js ">
 &lt;code>const obj = {}
defineReactive(obj, &amp;#39;foo&amp;#39;, &amp;#39;&amp;#39;)
setTimeout(()=&amp;gt;{
 obj.foo = new Date().toLocaleTimeString()
},1000)&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>在对象存在多个&lt;code>key&lt;/code>情况下，需要进行遍历&lt;/p></description></item><item><title>Vue3.0中Treeshaking特性</title><link>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/treeshaking/</link><pubDate>Tue, 04 Mar 2025 05:09:42 +0000</pubDate><guid>https://fe-interview.pangcy.cn/docs/framework/vue3/febobo/treeshaking/</guid><description>&lt;p>





 



 
 
 &lt;img src="https://fe-interview.pangcy.cn/5e8bf1d0-6097-11eb-ab90-d9ae814b240d_8526532960620440258.png" alt="" width="560" height="330" loading="lazy">
 
 
&lt;/p>
&lt;h2 id="一是什么">一、是什么 &lt;a href="#%e4%b8%80%e6%98%af%e4%bb%80%e4%b9%88" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;code>Tree shaking&lt;/code> 是一种通过清除多余代码方式来优化项目打包体积的技术，专业术语叫 &lt;code>Dead code elimination&lt;/code>&lt;/p>
&lt;p>简单来讲，就是在保持代码运行结果不变的前提下，去除无用的代码&lt;/p>
&lt;p>如果把代码打包比作制作蛋糕，传统的方式是把鸡蛋（带壳）全部丢进去搅拌，然后放入烤箱，最后把（没有用的）蛋壳全部挑选并剔除出去&lt;/p>
&lt;p>而&lt;code>treeshaking&lt;/code>则是一开始就把有用的蛋白蛋黄（import）放入搅拌，最后直接作出蛋糕&lt;/p>
&lt;p>也就是说 ，&lt;code>tree shaking&lt;/code> 其实是找出使用的代码&lt;/p>
&lt;p>在&lt;code>Vue2&lt;/code>中，无论我们使用什么功能，它们最终都会出现在生产代码中。主要原因是&lt;code>Vue&lt;/code>实例在项目中是单例的，捆绑程序无法检测到该对象的哪些属性在代码中被使用到&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="8451b28" class="language-js ">
 &lt;code>import Vue from &amp;#39;vue&amp;#39;
 
Vue.nextTick(() =&amp;gt; {})&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>而&lt;code>Vue3&lt;/code>源码引入&lt;code>tree shaking&lt;/code>特性，将全局 API 进行分块。如果您不使用其某些功能，它们将不会包含在您的基础包中&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="2991d4d" class="language-js ">
 &lt;code>import { nextTick, observable } from &amp;#39;vue&amp;#39;
 
nextTick(() =&amp;gt; {})&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h2 id="二如何做">二、如何做 &lt;a href="#%e4%ba%8c%e5%a6%82%e4%bd%95%e5%81%9a" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h2>&lt;p>&lt;code>Tree shaking&lt;/code>是基于&lt;code>ES6&lt;/code>模板语法（&lt;code>import&lt;/code>与&lt;code>exports&lt;/code>），主要是借助&lt;code>ES6&lt;/code>模块的静态编译思想，在编译时就能确定模块的依赖关系，以及输入和输出的变量&lt;/p>
&lt;p>&lt;code>Tree shaking&lt;/code>无非就是做了两件事：&lt;/p>
&lt;ul>
&lt;li>编译阶段利用&lt;code>ES6 Module&lt;/code>判断哪些模块已经加载&lt;/li>
&lt;li>判断那些模块和变量未被使用或者引用，进而删除对应代码&lt;/li>
&lt;/ul>
&lt;p>下面就来举个例子：&lt;/p>
&lt;p>通过脚手架&lt;code>vue-cli&lt;/code>安装&lt;code>Vue2&lt;/code>与&lt;code>Vue3&lt;/code>项目&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="893abcc" class="language-c ">
 &lt;code>vue create vue-demo&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;h3 id="vue2-项目">Vue2 项目 &lt;a href="#vue2-%e9%a1%b9%e7%9b%ae" class="anchor" aria-hidden="true">&lt;i class="material-icons align-middle">link&lt;/i>&lt;/a>&lt;/h3>&lt;p>组件中使用&lt;code>data&lt;/code>属性&lt;/p>



 
 
 

 
 
 
 

 

 &lt;div class="prism-codeblock ">
 &lt;pre id="c6e300f" class="language-vue ">
 &lt;code>&amp;lt;script&amp;gt;
 export default {
 data: () =&amp;gt; ({
 count: 1,
 }),
 };
&amp;lt;/script&amp;gt;&lt;/code>
 &lt;/pre>
 &lt;/div>
&lt;p>对项目进行打包，体积如下图&lt;/p></description></item></channel></rss>