前端面试专栏-主流框架:13.vue3组件通信与生命周期

🔥 欢迎来到前端面试通关指南专栏!从js精讲到框架到实战,渐进系统化学习,坚持解锁新技能,祝你轻松拿下心仪offer。
前端面试通关指南专栏主页
前端面试专栏规划详情在这里插入图片描述

Vue3组件通信与生命周期深度解析

在Vue3的开发体系中,组件通信与生命周期机制是构建高效、可维护应用的关键。掌握这些核心知识,能帮助开发者更好地组织代码结构,实现组件间的协同工作。接下来,我们将深入剖析Vue3组件通信的多种方式以及组件生命周期的各个阶段。

一、Vue3组件通信方式

1.1 Props与Emits

Props和Emits是Vue组件间通信的两个核心机制,构成了父子组件数据交互的基础模式。

Props详解

Props是单向数据流的实现方式,父组件通过属性绑定的方式将数据传递给子组件。在Vue 3的<script setup>语法中,使用defineProps宏来声明和验证props:

<template><div class="article-card"><h2>{{ title }}</h2><p v-if="description">{{ description }}</p><!-- 使用默认值 --><span class="views">{{ views }}次浏览</span></div>
</template><script setup>
const props = defineProps({// 必传的字符串类型title: {type: String,required: true,validator: value => value.length <= 50  // 自定义验证},// 可选的对象类型meta: {type: Object,default: () => ({})},// 带默认值的数字views: {type: Number,default: 0},// 可选描述description: String  // 简写形式
});
</script>
Emits详解

Emits允许子组件向父组件发送自定义事件,实现子到父的通信。在Vue 3中建议使用defineEmits进行明确的事件声明:

<template><div class="search-box"><input v-model="keyword" @keyup.enter="submitSearch"placeholder="请输入关键词..."/><button @click="clearInput">清空</button></div>
</template><script setup>
import { ref } from 'vue';const emit = defineEmits({// 带验证的事件search: (payload) => {if (!payload || payload.length < 2) {console.warn('搜索关键词至少2个字符');return false;}return true;},// 简单事件clear: null
});const keyword = ref('');const submitSearch = () => {emit('search', keyword.value.trim());
};const clearInput = () => {keyword.value = '';emit('clear');
};
</script>
完整交互示例

父组件完整使用示例:

<template><div class="app-container"><ArticleCard:title="article.title":description="article.desc":views="article.views"@read-more="handleReadMore"/><SearchBox@search="handleSearch"@clear="searchText = ''"/><p>当前搜索: {{ searchText }}</p></div>
</template><script setup>
import { ref } from 'vue';
import ArticleCard from './ArticleCard.vue';
import SearchBox from './SearchBox.vue';const article = ref({title: 'Vue 3组件通信指南',desc: '详细介绍各种组件通信方式',views: 1024
});const searchText = ref('');const handleReadMore = (articleId) => {console.log(':', articleId);// 导航到详情页...
};const handleSearch = (keyword) => {searchText.value = keyword;// 执行搜索逻辑...
};
</script>

最佳实践提示:

  1. 始终为props定义明确的类型和验证规则
  2. 复杂对象props建议使用函数返回默认值
  3. 事件名建议使用kebab-case命名
  4. 重要事件应该添加参数验证

1.2 依赖注入(provide/inject)

provideinject是Vue提供的一对API,用于实现组件树的跨层级通信,特别适合解决"prop逐层透传"的问题,让数据可以在祖先组件和后代组件之间直接传递,而不需要经过中间每一层的组件。

工作原理
  1. 提供数据(provide):在祖先组件中调用provide函数,可以提供一个键值对,键是一个字符串标识符,值是要传递的数据。
  2. 注入数据(inject):在后代组件中调用inject函数,通过相同的键名来获取祖先组件提供的数据。
基础用法示例

在祖先组件中使用provide提供数据:

<template><div><!-- 这是一个包含子组件的祖先组件 --><Children /></div>
</template><script setup>
import { provide } from 'vue';
import Children from './Children.vue';// 提供静态数据
provide('globalData', '这是全局数据');// 也可以提供响应式数据
const count = ref(0);
provide('countData', count);
</script>

在后代组件中通过inject获取数据:

<template><div><!-- 显示从祖先组件注入的数据 --><p>注入的数据: {{ globalData }}</p><p>注入的响应式数据: {{ countData }}</p><button @click="countData++">增加计数</button></div>
</template><script setup>
import { inject } from 'vue';// 注入静态数据
const globalData = inject('globalData');// 注入响应式数据
const countData = inject('countData');
</script>
高级用法
  1. 默认值设置
const value = inject('someKey', '默认值');
  1. 工厂函数
const value = inject('someKey', () => new ExpensiveClass());
  1. 修改权限控制(建议配合readonly使用):
provide('readOnlyData', readonly(someData));
使用场景
  1. 全局配置(如主题、语言)
  2. 共享用户登录状态
  3. 表单组件中传递表单实例
  4. 复杂组件库的实现(如Tree、Menu组件)
注意事项
  1. 尽量使用Symbol作为键名避免命名冲突
  2. 响应式数据需要保持引用一致
  3. 过度使用可能导致组件间耦合度增加

1.3 Vuex与Pinia

在Vue.js应用开发中,随着项目规模扩大,组件间的状态共享和通信会变得复杂。这时候就需要使用状态管理工具来集中管理应用状态。Vuex是Vue的官方状态管理库,而Pinia则是最新的推荐解决方案,具有更简洁的API和TypeScript支持。

主要特点对比
  1. Vuex
  • 核心概念:state、mutations、actions、getters
  • 严格的同步修改流程(必须通过mutation修改state)
  • 适用于复杂的应用场景
  • 需要定义modules来组织大型应用
  1. Pinia
  • 更简单的API设计
  • 支持组合式API
  • 天然支持TypeScript
  • 不需要mutations,可以直接修改state
  • 自动代码分割
Pinia使用详解

Pinia的基本使用分为三个步骤:

  1. 定义Store
import { defineStore } from 'pinia';// 使用defineStore定义store
// 第一个参数是store的唯一ID
export const useCounterStore = defineStore('counter', {// state使用函数返回初始状态state: () => ({count: 0,title: 'My Counter'}),// actions定义业务逻辑actions: {increment() {this.count++;  // 直接修改state},async fetchData() {// 可以包含异步操作const response = await fetch('/api/data');// ...}},// getters相当于计算属性getters: {doubleCount: (state) => state.count * 2}
});
  1. 在组件中使用Store
<template><div><h2>{{ counterStore.title }}</h2><p>当前计数: {{ counterStore.count }}</p><p>双倍计数: {{ counterStore.doubleCount }}</p><button @click="counterStore.increment">增加</button><button @click="resetCounter">重置</button></div>
</template><script setup>
import { useCounterStore } from '@/stores/counter';
import { storeToRefs } from 'pinia';// 使用store
const counterStore = useCounterStore();// 如果需要解构,使用storeToRefs保持响应性
const { title } = storeToRefs(counterStore);// 可以直接调用action
function resetCounter() {counterStore.$reset();  // 重置state
}
</script>
  1. 在main.js中安装Pinia
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';const app = createApp(App);
app.use(createPinia());
app.mount('#app');
实际应用场景
  1. 用户信息管理
// stores/user.js
export const useUserStore = defineStore('user', {state: () => ({userInfo: null,token: ''}),actions: {login(userData) {this.userInfo = userData;this.token = 'generated_token';localStorage.setItem('token', this.token);},logout() {this.userInfo = null;this.token = '';localStorage.removeItem('token');}}
});
  1. 购物车管理
// stores/cart.js
export const useCartStore = defineStore('cart', {state: () => ({items: [],total: 0}),actions: {addItem(product) {const existingItem = this.items.find(item => item.id === product.id);if (existingItem) {existingItem.quantity++;} else {this.items.push({...product, quantity: 1});}this.calculateTotal();},calculateTotal() {this.total = this.items.reduce((sum, item) => sum + (item.price * item.quantity), 0);}}
});

Pinia的这些特性使它成为Vue 3应用中管理状态的首选方案,特别是在需要处理复杂状态逻辑、跨组件共享数据或需要良好TypeScript支持的项目中。

1.4 事件总线(mitt或tiny-emitter)

对于非父子组件之间的复杂通信场景(如跨多级组件、兄弟组件等),可以引入轻量级的第三方事件总线库如mitt或tiny-emitter。这种方法通过发布订阅模式实现解耦通信。下面以mitt为例详细介绍:

安装

首先通过npm安装mitt库:

npm install mitt
# 或者使用yarn
yarn add mitt
初始化事件总线

创建独立的eventBus.js文件作为事件中心:

// src/utils/eventBus.js
import mitt from 'mitt';// 创建mitt实例
const emitter = mitt();// 可选:定义全局事件类型常量
export const EventTypes = {CUSTOM_EVENT: 'customEvent',USER_LOGIN: 'userLogin'
};export default emitter;
事件触发(发布)

在组件A中发布事件,可传递任意数据:

<template><button @click="sendEvent">发送全局事件</button><button @click="sendUserInfo">发送用户信息</button>
</template><script setup>
import emitter, { EventTypes } from '@/utils/eventBus';const sendEvent = () => {// 触发普通事件emitter.emit(EventTypes.CUSTOM_EVENT, {timestamp: new Date(),message: '来自组件A的重要通知'});
};const sendUserInfo = () => {// 触发带用户数据的事件emitter.emit(EventTypes.USER_LOGIN, {userId: 'U123456',username: '张三'});
};
</script>
事件监听(订阅)

在组件B中订阅事件:

<template><div><p>收到消息: {{ message }}</p><p>用户状态: {{ userStatus }}</p></div>
</template><script setup>
import { ref, onUnmounted } from 'vue';
import emitter, { EventTypes } from '@/utils/eventBus';const message = ref('');
const userStatus = ref('未登录');// 监听自定义事件
const eventHandler = (data) => {message.value = `${data.message} (${new Date(data.timestamp).toLocaleTimeString()})`;
};// 监听用户登录事件
const loginHandler = (user) => {userStatus.value = `${user.username}已登录(ID:${user.userId})`;
};// 组件挂载时注册监听
emitter.on(EventTypes.CUSTOM_EVENT, eventHandler);
emitter.on(EventTypes.USER_LOGIN, loginHandler);// 组件卸载时移除监听
onUnmounted(() => {emitter.off(EventTypes.CUSTOM_EVENT, eventHandler);emitter.off(EventTypes.USER_LOGIN, loginHandler);
});
</script>
其他用法
  1. 一次性事件
emitter.once('one-time-event', () => {console.log('只会触发一次');
});
  1. 清除所有事件
emitter.all.clear();
  1. 类型安全(TypeScript)
type Events = {search: stringchange: number
};const emitter = mitt<Events>();
emitter.emit('search', 'query'); // OK
emitter.emit('change', 123); // OK
注意事项
  1. 建议在组件卸载时移除事件监听,避免内存泄漏
  2. 对于大型项目,建议按模块划分不同的事件总线实例
  3. 事件名称最好使用常量管理,避免拼写错误
  4. 复杂场景可以考虑使用Vuex或Pinia替代

相比Vue2的EventBus,mitt更轻量(200b),且不依赖Vue实例,适合简单的跨组件通信场景。

二、Vue3组件生命周期

2.1 组件初始化阶段

  • setup:在组件创建之前执行,是Composition API的核心入口点。它取代了Vue 2.x中的datamethodscomputed等选项,统一在一个函数内进行组件逻辑的组织。主要功能包括:
    1. 初始化响应式数据(使用ref/reactive)
    2. 定义组件方法
    3. 设置计算属性
    4. 注册生命周期钩子
    5. 返回模板需要访问的数据和方法

特性说明:

  • 没有this上下文,所有操作都通过导入的Vue API实现
  • 只能同步执行,不可使用async/await
  • 接受两个参数:props和context(包含attrs/slots/emit等)
  • 必须返回一个对象,其属性将暴露给模板使用

典型应用场景:

  • 组合可复用的逻辑代码
  • 类型Script支持更好的类型推断
  • 更清晰的逻辑组织方式

示例扩展:

<template><div><p>{{ count }}</p><button @click="increment">+1</button><p>{{ doubledCount }}</p></div>
</template><script setup>
import { ref, computed } from 'vue';// 响应式数据
const count = ref(0);// 计算方法
const doubledCount = computed(() => count.value * 2);// 组件方法
function increment() {count.value++;
}// 暴露给模板
defineExpose({count,increment
})
</script>

注意事项:

  1. <script setup>语法糖中,所有顶层绑定自动暴露给模板
  2. 需要暴露给父组件的内容需使用defineExpose
  3. 生命周期钩子需使用专门API(如onMounted)在setup内注册
  4. 与Options API混用时需注意执行顺序问题

2.2 组件挂载阶段

onBeforeMount

在组件即将挂载到DOM之前调用,此阶段具有以下特点:

  1. 模板编译已完成,但尚未转换为实际的DOM节点
  2. 组件的$el属性尚未生成,无法访问DOM元素
  3. 适合执行一些与渲染无关的准备工作,如:
    • 数据预处理
    • 计算属性的最终计算
    • 配置初始化

典型应用场景:

  • 准备渲染所需的数据
  • 设置初始状态变量
  • 执行不依赖DOM的初始化逻辑
onMounted

在组件挂载到DOM之后调用,此阶段具有以下特点:

  1. 组件已经生成真实的DOM结构
  2. 可以安全地访问和操作DOM元素
  3. 常用于以下操作:
    • 初始化需要DOM的第三方库(如图表库、地图插件等)
    • 手动操作DOM元素(添加事件监听器、修改样式等)
    • 发送异步请求获取数据
    • 执行需要测量DOM尺寸的逻辑

实际开发中的典型用法示例:

<template><div id="app"><canvas ref="chartCanvas"></canvas></div>
</template><script setup>
import { onMounted, ref } from 'vue';
import Chart from 'chart.js';const chartCanvas = ref(null);onMounted(() => {// 初始化图表new Chart(chartCanvas.value, {type: 'bar',data: {/*...*/},options: {/*...*/}});// 获取DOM元素尺寸const dimensions = {width: chartCanvas.value.offsetWidth,height: chartCanvas.value.offsetHeight};// 添加事件监听window.addEventListener('resize', handleResize);
});
</script>

注意事项:

  1. onBeforeMount中不要尝试访问DOM,因为此时DOM还不存在
  2. 在服务器端渲染(SSR)时,onMounted不会在服务器端执行
  3. 如果需要在组件卸载时清理资源(如事件监听器),应该在onUnmounted生命周期钩子中进行

2.3 组件更新阶段

组件更新阶段是Vue响应式系统中重要的生命周期环节,当组件依赖的响应式数据发生变化时,会触发更新流程。这一阶段主要包含两个关键钩子函数:

  • onBeforeUpdate:在组件数据更新之前调用。此时Vue已经检测到数据变化并准备更新DOM,但DOM尚未实际更新。这个钩子常用于获取更新前的DOM状态或执行更新前的准备工作。

    典型应用场景:

    • 记录组件更新前的滚动位置
    • 保存当前表单的验证状态
    • 执行数据变更前的最后校验
  • onUpdated:在组件数据更新之后调用,此时DOM已经根据更新后的数据完成了重新渲染。这个钩子适合执行依赖新DOM的操作,但要注意避免在此修改响应式数据,否则可能导致无限更新循环。

    常见使用场景:

    • 更新后自动聚焦表单元素
    • 集成第三方DOM库(如图表库)
    • 执行DOM相关的测量操作
<template><div><p>当前计数:{{ count }}</p><button @click="increment">增加计数</button><div ref="messageBox" style="height:100px;overflow:auto;border:1px solid #ccc;margin-top:10px"><p v-for="msg in messages" :key="msg">{{ msg }}</p></div></div>
</template><script setup>
import { ref, onBeforeUpdate, onUpdated } from 'vue';const count = ref(0);
const messages = ref(['初始消息']);
const messageBox = ref(null);// 记录更新前的滚动位置
let prevScrollHeight = 0;const increment = () => {count.value++;messages.value.push(`新消息 ${count.value}`);
};onBeforeUpdate(() => {console.log('[BeforeUpdate] 组件即将更新');if (messageBox.value) {prevScrollHeight = messageBox.value.scrollHeight;}
});onUpdated(() => {console.log('[Updated] 组件已完成更新');// 保持滚动位置不变if (messageBox.value) {messageBox.value.scrollTop = messageBox.value.scrollHeight - prevScrollHeight;}// 更新后自动聚焦到按钮document.querySelector('button')?.focus();
});
</script>

示例说明:

  1. 当点击"增加计数"按钮时,会触发count和messages数据的变更
  2. onBeforeUpdate钩子会在数据变更后、DOM更新前执行,这里记录消息容器的滚动高度
  3. Vue完成DOM更新后,onUpdated钩子触发,调整滚动位置保持用户体验一致
  4. 每次更新后自动聚焦按钮,提升可访问性

注意事项:

  • 更新钩子可能在父/子组件间多次触发,可通过条件判断避免重复操作
  • 在onUpdated中修改数据需谨慎,可能导致无限循环
  • 对于复杂DOM操作,建议配合nextTick使用确保DOM更新完成

2.4 组件卸载阶段

  • onBeforeUnmount:在组件即将卸载之前调用,主要用于执行清理工作。这是最后的机会来处理组件相关的资源释放,常见应用场景包括:

    • 清除定时器(如setTimeout/setInterval)
    • 移除DOM事件监听器
    • 取消网络请求(如axios请求)
    • 关闭WebSocket连接
    • 清理第三方库实例
      不及时清理这些资源可能导致内存泄漏,影响应用性能。
  • onUnmounted:在组件完全卸载之后调用,此时组件实例及其所有子组件都已被销毁。通常用于:

    • 执行最终的日志记录
    • 触发分析事件
    • 确认资源已完全释放
      注意此时已无法访问DOM元素或组件实例。
<template><div v-if="show"><p>这是一个组件</p><div id="chart-container"></div>  <!-- 假设这里使用了Echarts图表 --></div><button @click="hideComponent">隐藏组件</button>
</template><script setup>
import { ref, onBeforeUnmount, onUnmounted } from 'vue';
import * as echarts from 'echarts';  // 引入Echarts库const show = ref(true);
const chartInstance = ref(null);  // 存储图表实例
const hideComponent = () => {show.value = false;
};// 模拟一个定时器
let timer = setInterval(() => {console.log('定时器运行中...');
}, 1000);// 模拟一个事件监听
const handleResize = () => console.log('窗口大小改变');
window.addEventListener('resize', handleResize);// 初始化图表
const initChart = () => {chartInstance.value = echarts.init(document.getElementById('chart-container'));chartInstance.value.setOption({/* 图表配置 */});
};
initChart();onBeforeUnmount(() => {// 清理定时器clearInterval(timer);console.log('定时器已清除');// 移除事件监听window.removeEventListener('resize', handleResize);console.log('事件监听已移除');// 销毁图表实例if(chartInstance.value) {chartInstance.value.dispose();console.log('图表实例已销毁');}console.log('组件即将卸载,资源清理完成');
});onUnmounted(() => {console.log('组件已完全卸载');// 可以在这里发送组件卸载的埋点数据// analytics.track('ComponentUnmounted');
});
</script>

2.5 错误处理阶段

onErrorCaptured 钩子详解

当组件树中的任意后代组件抛出错误时,该钩子会被触发。它是 Vue 3 中用于构建组件级错误边界的重要机制。

核心功能:

  1. 捕获后代组件传递的所有错误(包括渲染错误、生命周期钩子错误等)
  2. 提供错误对象、组件实例和错误来源信息
  3. 可以通过返回值控制是否继续向上传播错误

典型应用场景:

  • 全局错误日志收集
  • 优雅降级UI展示
  • 错误信息上报系统
  • 开发环境调试辅助

参数详解:

onErrorCaptured((error, instance, info) => {// error: 错误对象// instance: 触发错误的组件实例 // info: 错误来源信息字符串(如:'render function')
})

示例扩展:

<template><div><!-- 安全边界组件 --><ErrorBoundary><ChildComponent /></ErrorBoundary><!-- 备用渲染 --><div v-if="error">组件加载失败,请<a @click="retry">重试</a></div></div>
</template><script setup>
import { ref } from 'vue';const error = ref(null);
const retry = () => location.reload();onErrorCaptured((err) => {error.value = err;// 阻止错误继续冒泡return false; // 如需继续传播则返回true
});
</script>

最佳实践建议:

  1. 生产环境应配合Sentry等监控工具使用
  2. 重要业务组件建议单独设置错误边界
  3. 异步错误需结合async/await处理
  4. 注意避免在错误处理中触发新的错误

错误传播控制:
通过返回布尔值决定是否阻止错误继续冒泡:

  • return false:阻止传播
  • return true:允许继续传播
  • 未返回值:默认等同于return true

调试技巧:
在开发环境中,可以利用该钩子快速定位组件问题:

onErrorCaptured((err, vm, info) => {console.group('[ErrorCaptured]');console.log('Component:', vm.type.__name);console.log('Info:', info); console.error(err);console.groupEnd();
});

Vue3的组件通信与生命周期机制为开发者提供了丰富且灵活的工具。通过合理运用各种通信方式,结合组件生命周期钩子函数,能够构建出结构清晰、交互流畅的前端应用,满足不同业务场景的需求。在实际开发过程中,开发者应根据项目的具体情况,选择最合适的通信和生命周期处理方式,提升开发效率与应用质量。

📌 下期预告:Vue Router与Vuex核心应用
❤️❤️❤️:如果你觉得这篇文章对你有帮助,欢迎点赞、关注本专栏!后续解锁更多功能,敬请期待!👍🏻 👍🏻 👍🏻
更多专栏汇总:
前端面试专栏
Node.js 实训专栏

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

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

相关文章

自动化交易优化网格策略

一、动态参数调整 1. 网格间距优化 - 波动率自适应&#xff1a;使用平均真实波幅&#xff08;ATR&#xff09;指标动态调整间距。例如&#xff0c;当ATR值上升20%时&#xff0c;将间距从原定的1%扩大至1.5%&#xff1b;ATR下降时则缩小间距至0.8%。可通过Python的TA-Lib库实时计…

测试平台ui自动化demo说明

1. 要启动celery worker windows 开发时&#xff0c;用第二行 。&#xff08;试过&#xff0c;可以&#xff09;&#xff0c;第一行的没试过。 celery -A myproject worker --loglevelinfo # windows电脑用下面的&#xff0c;并且settings中还要加那个solo celery -A your_p…

五大主要Token类型之字符标记Token

如大家所了解的&#xff0c;在数字化时代&#xff0c;我们每天都会与Token&#xff08;令牌&#xff09;打交道——无论是在线支付、登录社交媒体&#xff0c;还是调用API接口&#xff0c;都离不开这一关键技术。 今天我们主要来学习&#xff1a;字符标记Token 在自然语言处理…

可理解性输入:洗澡习惯

一、开场与淋浴准备 Today we’re going to learn bathroom English. Let’s get started. So the first thing we want to do. Make sure we have our towel and we’ll hang it on the towel rack before we have a shower. Because if we have a shower and then forget ou…

GO Echo框架面试题及参考答案

目录 Echo 框架的核心结构是什么?Echo 和 Context 分别扮演什么角色? 如何创建一个 Echo 实例?简述常见配置项。 e.Start () 与 e.StartServer () 的区别是什么? Echo 如何实现基于先后顺序路由匹配? 如何注册 GET、POST、PUT、DELETE 等不同 HTTP 方法的路由? Echo…

Java 中LinkedList 总结

406.根据身高重建队列 力扣题目链接(opens new window) 假设有打乱顺序的一群人站成一个队列&#xff0c;数组 people 表示队列中一些人的属性&#xff08;不一定按顺序&#xff09;。每个 people[i] [hi, ki] 表示第 i 个人的身高为 hi &#xff0c;前面 正好 有 ki 个身高…

大模型微调:从零到实践,掌握AI大模型的核心技能

大模型微调&#xff1a;从零到实践&#xff0c;掌握AI大模型的核心技能 引言 大规模语言模型&#xff08;如DeepSeek、通义千问&#xff09;的出现&#xff0c;彻底改变了自然语言处理的格局。这些模型不仅在学术界取得了突破性进展&#xff0c;在工业界也得到了广泛应用。 …

Flutter - 原生交互 - 相册

环境 Flutter 3.29 macOS Sequoia 15.4.1 Xcode 16.3 iOS 13.4.1 iOS 18.5 集成image_picker 在Flutter中可以使用image_picker插件实现从相册中获取图片 添加插件 flutter中访问相册image_picker插件 flutter pub add image_pickerflutter pub getXcode工程的GenerateP…

node.js在vscode的配置

文章目录 概要1. 使用和webstrom一样的快捷键2. 让vscode的主题变成webstrom3. 如何在 Node.js 环境下写代码3.1 使用 ESLint配置规则3.2 配置.vscode/settings.json 4. Prettier安装5. 其它问题解决 概要 node.js在webstrom编辑器中可以完美使用代码提示、错误提示等功能&…

Android14音频子系统-Audio HAL分析

文章目录 1&#xff09;概述2&#xff09;HAL的打开流程3&#xff09;HAL库的实现(Qualcomm)4&#xff09;tinyalsa5&#xff09;数据结构6&#xff09;代码流程 1&#xff09;概述 1、回顾HAL、tinyalsa与linux driver的关系 2、与AudioFlinger的关系 3、 1、如何判断当前…

前端与 Spring Boot 后端无感 Token 刷新 - 从原理到全栈实践

&#x1f337; 古之立大事者&#xff0c;不惟有超世之才&#xff0c;亦必有坚忍不拔之志 &#x1f390; 个人CSND主页——Micro麦可乐的博客 &#x1f425;《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程&#xff0c;入门到实战 &#x1f33a;《RabbitMQ》…

【AI智能体】新手教程-通过 Chat SDK 搭建网页在线客服

通过扣子搭建的智能体可以一键发布为 Chat SDK&#xff0c;快速部署到你的自建网站中&#xff0c;作为在线智能客服面向网站的用户提供 AI 答疑服务。本文档介绍通过 Chat SDK 搭建网页版在线客服的详细操作步骤。 场景说明 网站作为企业和组织与用户互动的重要平台&#xff…

flask静态资源与模板页面、模板用户登录案例

案例代码 import flask# template_folder 模板文件夹(静态页面 html页面渲染) # static_folder 静态资源文件夹主要存放的是类似静态数据、音频、视频、图片等 app flask.Flask(__name__, static_folderstatic, template_foldertemplate)app.route(/) def index():# render_t…

【工具教程】识别PDF中文字内容,批量识别文字并保存到Excel表格中的操作步骤和方法

在日常办公和文件管理中&#xff0c;我们常常会遇到需要处理大量 PDF 文件的情况。有时&#xff0c;为了更好地管理和查找这些文件&#xff0c;需要根据 PDF 文件中特定区域的文字内容对文件进行重命名。例如&#xff0c;在企业档案管理中&#xff0c;合同文件可能需要根据合同…

重生学AI第十三集:初识神经网络之Conv2d

终于该学习神经网络的搭建了&#xff0c;开心&#xff0c;嘻嘻 学习神经网络离不开torch.nn&#xff0c;先把他印在脑子里&#xff0c;什么是torch.nn?他是Pytorch的一个模块&#xff0c;包含了大量构建神经网络需要的类和方法&#xff0c;就像前面学习的torch.utils&#xf…

学习C++、QT---07(C++的权限、C++的引用)

每日一言 你解决的每一个难题&#xff0c;都是在为未来的自己解锁新技能。 权限的讲解 这边呢我们利用银行的一个案例来讲解权限的奥秘 权限指的是public、private 、protected 就是这三种权限&#xff0c;因此有这一张表进行分清他们之间的区别和联系 但是我们在平时的话会因…

全球化短剧平台全栈技术架构白皮书:多区域部署、智能分发与沉浸式体验的完整解决方案

一、全球化基础架构深度设计 全球网络基础设施构建 采用多活数据中心部署模式&#xff0c;在北美&#xff08;弗吉尼亚&#xff09;、欧洲&#xff08;法兰克福&#xff09;、亚太&#xff08;新加坡&#xff09;建立三大核心枢纽节点 构建混合CDN网络&#xff0c;整合AWS Clo…

深入剖析 LGM—— 开启高分辨率 3D 内容创作新时代

一、引言 在当今数字化时代&#xff0c;3D 内容创作的需求如井喷般增长&#xff0c;从游戏开发中绚丽多彩的虚拟世界&#xff0c;到影视制作里震撼人心的特效场景&#xff0c;再到工业设计中精准无误的产品原型&#xff0c;3D 技术无处不在。然而&#xff0c;传统 3D 内容创作…

从用户到社区Committer:小米工程师隋亮亮的Apache Fory成长之路

Apache Fory 是一个基于JIT和零拷贝的高性能多语言序列化框架&#xff0c;实现了高效紧凑的序列化协议&#xff0c;提供极致的性能、压缩率和易用性。在多语言序列化框架技术领域取得了重大突破&#xff0c;推动序列化技术步入高性能易用新篇章&#xff01;这一切&#xff0c;都…

【Koa系列】10min快速入门Koa

简介 koa是基于node开发的一个服务端框架&#xff0c;功能同express&#xff0c;但更小巧简单。 官方仓库地址&#xff1a;https://github.com/koajs/koa 创建项目 创建文件夹nodeKoa&#xff0c;执行以下脚本 npm init -y npm i koa npm i nodemon 基础示例 创建一个服…