Vue 生命周期全解析:从创建到销毁的完整旅程

Vue 生命周期是每个 Vue 开发者必须深入理解的核心概念之一。它定义了组件从创建、挂载、更新、销毁的整个过程,以及在这个过程中各个阶段提供的钩子函数。掌握生命周期不仅能帮助你理解 Vue 的工作原理,还能让你在合适的时机执行特定的操作,优化应用性能,避免常见陷阱。本文将从源码实现到实际应用,全面解析 Vue 生命周期的各个阶段。

一、生命周期概览

Vue 组件的生命周期可以分为四个主要阶段:

  1. 初始化与挂载:创建组件实例,初始化数据,挂载 DOM
  2. 数据更新:响应式数据变更时触发更新流程
  3. 销毁:清理组件并释放资源
  4. 特殊场景:错误处理、服务器端渲染等

每个阶段都提供了相应的钩子函数,开发者可以在这些钩子中注入自定义逻辑。生命周期钩子的执行顺序是固定的,理解这个顺序对于编写正确的代码至关重要。

二、生命周期阶段详解

2.1 初始化与挂载阶段

这个阶段从组件实例创建开始,到 DOM 挂载完成结束。

2.1.1 beforeCreate
  • 触发时机:实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
  • 特性
    • 此时 this 指向实例,但数据和方法均未初始化。
    • 无法访问 datamethodscomputed
    • 通常用于初始化非响应式数据或全局插件。
  • 示例
    export default {beforeCreate() {// 初始化全局事件总线this.$bus = new Vue();// 记录组件创建时间this._createdAt = Date.now();}
    }
    
2.1.2 created
  • 触发时机:实例已经创建完成之后被调用。在这一步,实例已经完成了数据观测、propertymethod 的计算、watch/event 事件回调的配置。然而,挂载阶段还没有开始,$el 属性目前不可用。
  • 特性
    • 可以访问 datamethodscomputed,但 DOM 尚未挂载。
    • 适合进行数据获取(如 API 请求)或初始化依赖数据的操作。
  • 示例
    export default {data() {return {users: []};},async created() {try {const response = await fetch('/api/users');this.users = await response.json();} catch (error) {console.error('Failed to fetch users', error);}}
    }
    
2.1.3 beforeMount
  • 触发时机:挂载开始之前被调用。
  • 特性
    • 模板编译/渲染函数已经完成,但尚未挂载到 DOM。
    • $el 是虚拟 DOM,不可访问实际 DOM 元素。
    • 适合在渲染前对模板进行最后的修改。
  • 源码关键点
    // Vue 源码简化版
    vm.$el = vm.$options.el;
    callHook(vm, 'beforeMount');// 编译模板生成 render 函数
    const updateComponent = () => {vm._update(vm._render(), hydrating);
    };
    
2.1.4 mounted
  • 触发时机:挂载完成后被调用。此时模板已经编译完成并挂载到 DOM 上。
  • 特性
    • 可以访问 $el 和实际 DOM 元素。
    • 子组件已经完成挂载(但不保证所有异步子组件都已完成)。
    • 适合进行 DOM 操作、初始化第三方插件(如 Chart.js、Leaflet)或订阅事件。
  • 示例
    export default {mounted() {// 初始化图表this.chart = new Chart(this.$el.querySelector('#chart'), {type: 'bar',data: this.chartData});// 添加 DOM 事件监听器this.$el.addEventListener('click', this.handleClick);},beforeDestroy() {// 清理图表实例和事件监听器this.chart.destroy();this.$el.removeEventListener('click', this.handleClick);}
    }
    
2.2 数据更新阶段

这个阶段在组件数据发生变化时触发,包含虚拟 DOM 重新渲染和打补丁的过程。

2.2.1 beforeUpdate
  • 触发时机:数据更新时调用,发生在虚拟 DOM 打补丁之前。
  • 特性
    • 数据已经变更,但 DOM 尚未更新。
    • 可以访问更新前的 DOM 状态。
    • 适合在更新前保存当前 DOM 状态或执行一些预处理。
  • 示例
    export default {data() {return {list: [1, 2, 3]};},beforeUpdate() {// 保存更新前的列表高度this.prevListHeight = this.$el.offsetHeight;}
    }
    
2.2.2 updated
  • 触发时机:由于数据更改导致的虚拟 DOM 重新渲染和打补丁之后调用。
  • 特性
    • 数据和 DOM 都已经更新。
    • 可以访问更新后的 DOM 状态。
    • 注意:不要在这个钩子中修改数据,否则可能导致无限循环更新。
  • 示例
    export default {updated() {// 对比更新前后的列表高度,执行动画if (this.prevListHeight !== this.$el.offsetHeight) {this.animateListHeightChange();}}
    }
    
2.3 销毁阶段

这个阶段在组件实例销毁时触发,用于清理资源和事件监听器。

2.3.1 beforeDestroy (Vue 2) / beforeUnmount (Vue 3)
  • 触发时机:实例销毁之前调用。此时实例仍然完全可用。
  • 特性
    • 组件仍然完全正常工作。
    • 适合进行资源清理(如定时器、事件监听器、WebSocket 连接等)。
  • 示例
    export default {created() {this.timer = setInterval(() => {console.log('定时任务');}, 1000);this.$bus.$on('some-event', this.handleEvent);},beforeDestroy() {// 清理定时器clearInterval(this.timer);// 取消事件订阅this.$bus.$off('some-event', this.handleEvent);}
    }
    
2.3.2 destroyed (Vue 2) / unmounted (Vue 3)
  • 触发时机:实例已经完全销毁之后调用。
  • 特性
    • 所有的事件监听器和子实例已经被销毁。
    • 组件实例完全不可用。
    • 通常用于确认资源是否已经正确释放。
  • 源码关键点
    // Vue 源码简化版
    callHook(vm, 'beforeDestroy');// 递归销毁子组件
    vm.$children.forEach(child => {child.$destroy();
    });// 移除所有事件监听器
    vm._events = Object.create(null);callHook(vm, 'destroyed');
    
2.4 特殊场景钩子
2.4.1 activated / deactivated
  • 触发时机
    • activated:被 <keep-alive> 缓存的组件激活时调用。
    • deactivated:被 <keep-alive> 缓存的组件停用时调用。
  • 特性
    • 只在使用 <keep-alive> 包裹的组件中触发。
    • 适合处理缓存组件的特殊逻辑(如恢复滚动位置、刷新数据)。
  • 示例
    <keep-alive><router-view />
    </keep-alive>
    
    export default {activated() {// 组件被激活时刷新数据this.fetchData();},deactivated() {// 保存组件状态this.saveScrollPosition();}
    }
    
2.4.2 errorCaptured (Vue 2) / errorCaptured + renderTracked + renderTriggered (Vue 3)
  • 触发时机
    • errorCaptured:捕获来自子孙组件的错误时调用。
    • renderTracked / renderTriggered(Vue 3):用于调试响应式依赖的追踪和触发。
  • 特性
    • 可以阻止错误继续向上传播。
    • 适合实现全局错误处理或日志记录。
  • 示例
    export default {errorCaptured(err, vm, info) {// 记录错误日志console.error('Error captured:', err, info);// 可以返回 false 阻止错误继续向上传播return false;}
    }
    
2.4.3 serverPrefetch (Vue 3 仅 SSR)
  • 触发时机:在服务器端渲染(SSR)期间,组件实例在服务器上被创建时调用。
  • 特性
    • 仅在 SSR 模式下有效。
    • 用于在服务器端预取数据,避免客户端重复请求。
  • 示例
    export default {async serverPrefetch() {// 在服务器端预取数据this.data = await fetchData();}
    }
    

三、生命周期流程图与执行顺序

3.1 Vue 2 生命周期流程图
创建实例↓
beforeCreate↓
初始化 data/methods↓
created↓
是否有 el 选项?↓├─ 否 → 等待 vm.$mount(el)↓├─ 是 → 是否有 template 选项?↓├─ 是 → 编译 template 为 render 函数↓└─ 否 → 使用 el 的 outerHTML 作为 template↓
beforeMount↓
创建 vm.$el 并替换 el↓
mounted↓
数据变更↓
beforeUpdate↓
虚拟 DOM 重新渲染 & 打补丁↓
updated↓
调用 vm.$destroy()↓
beforeDestroy↓
销毁所有子实例、事件监听器和子组件↓
destroyed
3.2 Vue 3 生命周期变更

Vue 3 对生命周期钩子进行了一些重命名,以更准确地反映其用途:

  • beforeDestroybeforeUnmount
  • destroyedunmounted

新增钩子:

  • setup():替代 beforeCreatecreated,是 Composition API 的入口点。
  • renderTracked / renderTriggered:用于调试响应式依赖。

四、生命周期钩子的实际应用场景

4.1 数据获取
  • 最佳位置createdmounted
  • 选择依据
    • 如果数据获取不依赖 DOM 操作,使用 created(稍早执行)。
    • 如果需要访问 DOM 元素,使用 mounted
  • 示例
    export default {data() {return {posts: [],loading: true,error: null};},async created() {try {const response = await fetch('/api/posts');this.posts = await response.json();} catch (error) {this.error = error.message;} finally {this.loading = false;}}
    }
    
4.2 DOM 操作与第三方插件集成
  • 最佳位置mounted
  • 示例:初始化 Chart.js 图表
    export default {mounted() {const ctx = this.$el.querySelector('#myChart').getContext('2d');this.chart = new Chart(ctx, {type: 'line',data: this.chartData,options: this.chartOptions});},beforeUnmount() {// 销毁图表实例this.chart.destroy();}
    }
    
4.3 状态恢复与保存
  • 最佳位置activated / deactivated(配合 <keep-alive>
  • 示例:保存和恢复滚动位置
    export default {data() {return {scrollPosition: 0};},deactivated() {// 保存当前滚动位置this.scrollPosition = window.scrollY;},activated() {// 恢复滚动位置window.scrollTo(0, this.scrollPosition);}
    }
    
4.4 资源清理
  • 最佳位置beforeDestroy / beforeUnmount
  • 示例:清理定时器、取消订阅、关闭网络连接
    export default {created() {this.socket = new WebSocket('ws://example.com');this.interval = setInterval(this.updateData, 5000);},beforeUnmount() {// 清理 WebSocket 连接this.socket.close();// 清除定时器clearInterval(this.interval);}
    }
    
4.5 全局状态初始化
  • 最佳位置beforeCreate
  • 示例:初始化全局事件总线或配置
    export default {beforeCreate() {// 初始化全局事件总线this.$bus = new Vue();// 配置全局 API 基地址this.$apiBaseUrl = process.env.VUE_APP_API_BASE_URL;}
    }
    

五、生命周期钩子的性能考虑

5.1 避免在钩子中执行耗时操作
  • 问题:在 mountedupdated 等钩子中执行大量计算或同步 API 请求会阻塞 UI 渲染。
  • 解决方案
    • 使用异步操作(如 async/await)处理 API 请求。
    • 将复杂计算移至 computed 属性或 watch 中。
    export default {async mounted() {// 错误:同步执行大量计算// this.result = heavyCalculation(this.data);// 正确:异步执行setTimeout(() => {this.result = heavyCalculation(this.data);}, 0);// 或使用 Web Workerthis.worker.postMessage(this.data);this.worker.onmessage = (e) => {this.result = e.data;};}
    }
    
5.2 避免在 updated 中修改数据
  • 问题:在 updated 中修改数据会触发新的更新周期,可能导致无限循环。
  • 解决方案
    • 仅在数据满足特定条件时才修改,且确保不会再次触发更新。
    export default {updated() {// 错误:可能导致无限循环// if (this.value < 10) this.value++;// 正确:使用 nextTick 避免立即触发更新if (this.value < 10 && !this.updating) {this.updating = true;this.$nextTick(() => {this.value++;this.updating = false;});}}
    }
    
5.3 合理使用生命周期钩子
  • 问题:在不需要的钩子中添加逻辑会增加组件复杂度和执行时间。
  • 解决方案
    • 只在真正需要的钩子中添加代码。
    • 使用 Composition API 将相关逻辑组织在一起,减少对生命周期钩子的依赖。

六、Vue 3 Composition API 中的生命周期

Vue 3 的 Composition API 提供了与生命周期钩子等效的函数,使逻辑复用更加灵活:

6.1 等效钩子映射
选项式 APIComposition API
beforeCreatesetup()
createdsetup()
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeDestroyonBeforeUnmount
destroyedonUnmounted
errorCapturedonErrorCaptured
renderTrackedonRenderTracked (仅开发模式)
renderTriggeredonRenderTriggered (仅开发模式)
6.2 示例:使用 Composition API 访问生命周期
import { onMounted, onBeforeUnmount, ref } from 'vue';export default {setup() {const count = ref(0);let timer;// 等效于 mountedonMounted(() => {timer = setInterval(() => {count.value++;}, 1000);});// 等效于 beforeUnmountonBeforeUnmount(() => {clearInterval(timer);});return {count};}
};
6.3 Composition API 的优势
  • 逻辑复用:可以将相关生命周期逻辑封装到可复用的函数中。
  • 代码组织:将同一功能的代码集中在一起,提高可读性。
  • 类型安全:更好地支持 TypeScript,提供更准确的类型推导。

七、生命周期钩子的常见误区与解决方案

7.1 误区:在 mounted 中直接操作子组件 DOM
  • 问题:子组件可能尚未完全挂载,直接访问子组件 ref 会失败。
  • 解决方案
    • 使用 nextTick 确保子组件已挂载。
    • 使用事件或 props 进行组件间通信。
    export default {mounted() {// 错误:子组件可能尚未挂载// this.$refs.child.doSomething();// 正确:使用 nextTickthis.$nextTick(() => {this.$refs.child.doSomething();});}
    }
    
7.2 误区:在 destroyed 中访问组件实例
  • 问题:在 destroyed 钩子中,组件实例已经完全销毁,访问 this 可能导致错误。
  • 解决方案
    • beforeDestroy 中进行所有清理操作。
    export default {beforeDestroy() {// 正确:此时组件仍然可用this.cleanupResources();},destroyed() {// 错误:不要在这里访问 this// this.cleanupResources(); // 可能导致错误}
    }
    
7.3 误区:过度使用生命周期钩子
  • 问题:在多个生命周期钩子中重复相同的逻辑,导致代码冗余。
  • 解决方案
    • 使用 Composition API 将相关逻辑封装到一个函数中。
    • 使用 watchcomputed 处理数据变化逻辑。
    // 坏:重复逻辑
    export default {mounted() {this.initData();},activated() {this.initData();},methods: {initData() {// 初始化逻辑}}
    };// 好:使用 Composition API 封装
    import { onMounted, onActivated } from 'vue';export function useInitData(initFn) {onMounted(initFn);onActivated(initFn);
    }// 在组件中使用
    export default {setup() {useInitData(() => {// 初始化逻辑});}
    };
    

八、生命周期源码解析(简化版)

Vue 的生命周期实现主要涉及以下几个核心模块:

  1. 实例初始化src/core/instance/init.js
  2. 生命周期钩子src/core/instance/lifecycle.js
  3. 渲染流程src/core/instance/render.js
  4. 更新流程src/core/observer/watcher.js
8.1 关键源码片段
// src/core/instance/init.js
Vue.prototype._init = function(options) {const vm = this;// 初始化生命周期状态initLifecycle(vm);// 初始化事件系统initEvents(vm);// 初始化渲染initRender(vm);// 调用 beforeCreate 钩子callHook(vm, 'beforeCreate');// 初始化注入initInjections(vm);// 初始化 data、props、computed 等initState(vm);// 初始化 provideinitProvide(vm);// 调用 created 钩子callHook(vm, 'created');if (vm.$options.el) {// 挂载组件vm.$mount(vm.$options.el);}
};// src/core/instance/lifecycle.js
Vue.prototype.$mount = function(el) {// 编译模板并生成 render 函数const mount = Vue.prototype._mount;const vm = this;// 调用 beforeMount 钩子callHook(vm, 'beforeMount');// 执行渲染const vnode = vm._render();vm._update(vnode, hydrating);// 调用 mounted 钩子callHook(vm, 'mounted');return vm;
};// 数据更新触发的更新流程
Watcher.prototype.update = function() {const vm = this.vm;// 调用 beforeUpdate 钩子callHook(vm, 'beforeUpdate');// 执行虚拟 DOM 更新vm._update(vm._render(), hydrating);// 调用 updated 钩子callHook(vm, 'updated');
};// 组件销毁流程
Vue.prototype.$destroy = function() {const vm = this;// 调用 beforeDestroy 钩子callHook(vm, 'beforeDestroy');// 执行销毁操作:移除事件监听器、销毁子组件等vm._isBeingDestroyed = true;// 递归销毁子组件vm.$children.forEach(child => {child.$destroy();});// 移除所有事件监听器vm._events = Object.create(null);// 调用 destroyed 钩子callHook(vm, 'destroyed');vm._isDestroyed = true;
};

九、总结与最佳实践

9.1 生命周期关键要点总结
  1. 初始化与挂载

    • beforeCreate:实例初始化后,数据和事件系统尚未初始化。
    • created:数据观测、propertymethod 计算完成,可进行数据获取。
    • beforeMount:模板编译完成,但尚未挂载到 DOM。
    • mounted:DOM 挂载完成,可进行 DOM 操作和第三方插件初始化。
  2. 数据更新

    • beforeUpdate:数据变更后,DOM 更新前。
    • updated:DOM 更新完成,避免在此修改数据。
  3. 销毁阶段

    • beforeDestroy/beforeUnmount:实例销毁前,可进行资源清理。
    • destroyed/unmounted:实例完全销毁,不可访问组件状态。
  4. 特殊场景

    • activated/deactivated<keep-alive> 缓存组件的激活/停用。
    • errorCaptured:捕获子孙组件的错误。
9.2 最佳实践建议
  1. 数据获取:优先在 created 中进行,避免阻塞 DOM 渲染。
  2. DOM 操作:仅在 mounted 或之后进行,确保 DOM 已渲染。
  3. 资源清理:在 beforeDestroy/beforeUnmount 中清理定时器、事件监听器等。
  4. 避免重复逻辑:使用 Composition API 或 mixins 复用生命周期相关逻辑。
  5. 调试工具:利用 Vue DevTools 监控生命周期钩子的执行情况。
  6. 性能优化:避免在生命周期钩子中执行耗时操作,使用异步处理。

掌握 Vue 生命周期是成为一名优秀 Vue 开发者的基础。通过合理利用生命周期钩子,你可以更精确地控制组件行为,优化应用性能,避免常见的开发陷阱。在实际开发中,结合 Composition API 的强大功能,你可以更灵活地组织和复用代码,打造出高质量的 Vue 应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/news/908099.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Rust 高级trait】Rust trait的一些高级用法解密

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

联想电脑护眼卫士与系统颜色配置(X-Rite)冲突 | 显示设置频繁变换色阶 - 解决方案

联想电脑护眼卫士与系统颜色配置X-Rite冲突 | 显示设置频繁变换色阶 - 解决方案 前言方案1&#xff1a;解决联想护眼卫士方案2&#xff1a;解决系统颜色配置(X-Rite) 前言 自带X-Rite软件的联想电脑&#xff08;以拯救者Y9000P&#xff0c;Win11系统为例&#xff09;&#xff…

MySQL中SELECT查询的执行顺序

MySQL中SELECT查询的执行顺序 在日常的数据库开发中&#xff0c;我们经常会写各种复杂的SELECT查询语句。然而&#xff0c;很多开发者对于MySQL实际执行这些查询的顺序并不完全了解。理解查询的执行顺序不仅有助于编写更高效的SQL语句&#xff0c;还能帮助我们更好地优化查询性…

es 的字段类型(text和keyword)

Text 当一个字段是要被全文检索时&#xff0c;比如 Email 内容、产品描述&#xff0c;这些字段应该使用 text 类型。设置 text 类型以后&#xff0c;字段内容会被分析&#xff0c;在生成倒排索引之前&#xff0c;字符串会被分析器分词。text类型的字段不用于排序&#xff0c;很…

MySQL安装及启用详细教程(Windows版)

MySQL安装及启用详细教程&#xff08;Windows版&#xff09; &#x1f4cb; 概述 本文档将详细介绍MySQL数据库在Windows系统下的下载、安装、配置和启用过程。 &#x1f4e5; MySQL下载 官方下载地址 官方网站: https://dev.mysql.com/downloads/社区版本: https://dev.my…

Linux下使用nmcli连接网络

Linux下使用nmcli连接网络 介绍 在使用ubuntu系统的时候&#xff0c;有时候不方便使用桌面&#xff0c;使用ssh远程连接&#xff0c;可能需要使用nmcli命令来连接网络。本文将介绍如何使用nmcli命令连接网络。nmcli 是 NetworkManager 的命令行工具&#xff0c;用于管理网络连…

Python----循环神经网络(BiLSTM:双向长短时记忆网络)

一、LSTM 与 BiLSTM对比 1.1、LSTM LSTM&#xff08;长短期记忆网络&#xff09; 是一种改进的循环神经网络&#xff08;RNN&#xff09;&#xff0c;专门解决传统RNN难以学习长期依赖的问题。它通过遗忘门、输入门和输出门来控制信息的流动&#xff0c;保留重要信息并丢弃无关…

U盘挂载Linux

在 只能使用 Telnet 的情况下&#xff0c;如果希望通过 U盘 传输文件到 Linux 系统&#xff0c;可以按照以下步骤操作&#xff1a; &#x1f4cc; 前提条件 U盘已插入 Linux 主机的 USB 接口。Linux 主机支持自动挂载 U盘&#xff08;大多数现代发行版默认支持&#xff09;。T…

QuickBASIC QB64 支持 64 位系统和跨平台Linux/MAC OS

QuickBASIC 的现代继任者 QB64 已发展成为一个功能强大的开源项目&#xff0c;支持 64 位系统和跨平台开发。以下是详细介绍&#xff1a; 项目首页 - QB64pe:The QB64 Phoenix Edition Repository - GitCode https://gitcode.com/gh_mirrors/qb/QB64pe 1. QB64 概述 官网&am…

【C++高级主题】命令空间(五):类、命名空间和作用域

目录 一、实参相关的查找&#xff08;ADL&#xff09;&#xff1a;函数调用的 “智能搜索” 1.1 ADL 的核心规则 1.2 ADL 的触发条件 1.3 ADL 的典型应用场景 1.4 ADL 的潜在风险与规避 二、隐式友元声明&#xff1a;类与命名空间的 “私密通道” 2.1 友元声明的基本规则…

免费开源Umi-OCR,离线使用,批量精准!

Umi-OCR&#xff08;Windows端&#xff09; Umi-OCR 是一款在 GitHub 上开源的免费 OCR 识别软件&#xff0c;它最大的亮点就是免费、开源、支持批量处理&#xff0c;而且识别准确度很高。这款软件不需要联网就能用&#xff0c;非常值得推荐&#xff01; 在 OCR 识别功能方面&…

深入剖析 Docker 容器化原理与实战应用,开启技术新征程!

文章目录 前言一、为什么 是Docker &#xff1f;二、Docker 容器化原理分析2.1 镜像&#xff08;Image&#xff09;2.2 容器&#xff08;Container&#xff09;2.3 仓库&#xff08;Registry&#xff09; 三、Docker 容器化实践3.1 Docker安装3.2 创建一个 Docker 镜像3.3 运行…

黑马程序员TypeScript课程笔记—class篇

class的基本使用 class的构造函数&#xff08;实现实例属性的初始化&#xff09; 在使用构造函数的时候&#xff0c;小括号的后面不要指定类型&#xff0c;否则就会报错&#xff0c;因为构造函数没有返回值 class实例方法 class继承&#xff08;extends&#xff09; class继承…

PDF.js无法显示数字签名

问题 pdfjs加载pdf文件时无法显示数字签名 PDF.js 从 v2.9.359 版本开始正式支持数字签名的渲染与显示&#xff0c;此前版本需通过修改源代码实现基础兼容。 建议升级pdfjs组件大于等于v2.9.359 pdfjs历史版本&#xff1a;https://github.com/mozilla/pdf.js/releases pdfjs…

解决VS Code误报Java问题的终极方法

使用vscode写java&#xff0c;发现很多Problems&#xff0c;如下图&#xff0c;实际上并没有问题&#xff0c;是误报&#xff0c;怎么解决&#xff1f; 解决方案&#xff1a;disable下面这个插件&#xff0c;它和vscode-java插件冲突了导致。

【WPF】从普通 ItemsControl 到支持筛选的 ItemsControl:深入掌握 CollectionViewSource 用法

✨ 从普通 ItemsControl 到支持筛选的 ItemsControl&#xff1a;深入掌握 CollectionViewSource 用法 在日常 WPF 开发中&#xff0c;我们经常需要对数据进行筛选、排序、分组等操作&#xff0c;而原生的 ItemsControl 并不直接支持这些功能。本文将介绍如何通过 CollectionVi…

Mybatis Plus JSqlParser解析sql语句及JSqlParser安装步骤

MyBatis Plus与JSqlParser&#xff1a;SQL语句解析与实战指南 在现代Java开发中&#xff0c;SQL解析和动态SQL生成是数据库操作中不可或缺的一部分。MyBatis Plus作为MyBatis的增强工具&#xff0c;通过JSqlParser库实现了对SQL语句的深度解析和修改能力。本文将详细介绍如何在…

学习路之PHP--easyswoole使用视图和模板

学习路之PHP--easyswoole使用视图和模板 一、安装依赖插件二、 实现渲染引擎三、注册渲染引擎四、测试调用写的模板五、优化六、最后补充 一、安装依赖插件 composer require easyswoole/template:1.1.* composer require topthink/think-template相关版本&#xff1a; "…

设计模式——享元设计模式(结构型)

摘要 享元设计模式是一种结构型设计模式&#xff0c;旨在通过共享对象减少内存占用和提升性能。其核心思想是将对象状态分为内部状态&#xff08;可共享&#xff09;和外部状态&#xff08;不可共享&#xff09;&#xff0c;并通过享元工厂管理共享对象池。享元模式包含抽象享…

互联网大厂Java求职面试:云原生微服务架构设计与AI大模型集成实战

互联网大厂Java求职面试&#xff1a;云原生微服务架构设计与AI大模型集成实战 面试场景设定 人物设定&#xff1a; 李明&#xff08;技术总监&#xff09;&#xff1a;拥有15年分布式系统架构经验&#xff0c;主导过多个亿级用户系统的重构&#xff0c;对云原生和AI融合有深…