微前端学习以及分享
微前端学习以及分享
注:本次分享demo的源码github地址:https://github.com/rondout/micro-frontend
什么是微前端
微前端的概念是由ThoughtWorks
在2016年提出的,它借鉴了微服务的架构理念,核心在于将一个庞大的前端应用拆分成多个独立灵活的小型应用,每个应用都可以独立开发、独立运行、独立部署,再将这些小型应用融合为一个完整的应用,或者将原本运行已久、没有关联的几个应用融合为一个应用。微前端既可以将多个项目融合为一,又可以减少项目之间的耦合,提升项目扩展性,相比一整块的前端仓库,微前端架构下的前端仓库倾向于更小更灵活。
它主要解决了两个问题:
- 随着项目迭代应用越来越庞大,难以维护。
- 跨团队或跨部门协作开发项目导致效率低下的问题。
微前端架构有以下特点:
-
技术栈无关
主框架不限制接入应用的技术栈,微应用具备完全自主权 -
独立开发、独立部署
微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 -
增量升级
在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
-
独立运行时
每个微应用之间状态隔离,运行时状态不共享
现有的微前端解决方案
现在主流的微前端解决方案有以下几种:
-
qiankun
:qiankun
孵化自蚂蚁金融科技基于微前端架构的云产品统一接入平台,在经过一批线上应用的充分检验及打磨后,我们将其微前端内核抽取出来并开源,希望能同时帮助社区有类似需求的系统更方便的构建自己的微前端系统。 -
MicroApp:
micro-app
是由京东前端团队推出的一款微前端框架,它借鉴了WebComponent
的思想,通过js沙箱
、样式隔离
、元素隔离
、路由隔离
模拟实现了隔离特性,从而实现微前端的组件化渲染,旨在降低上手难度、提升工作效率。micro-app
和技术栈无关,也不和业务绑定,可以用于任何前端框架。 -
Wujie
:无界微前端方案基于 webcomponent 容器 + iframe 沙箱,能够完善的解决适配成本、样式隔离、运行性能、页面白屏、子应用通信、子应用保活、多应用激活、vite 框架支持、应用共享等用户的核心诉求。
目前而言,这三种方案都是不错的微前端解决方案,但是目前而言qiankun
对vite的支持仍然不友好,qiankun
本身是不支持vite构建的应用的,还需要使用社区的插件,而且我也有去做demo,然后觉得坑太多了,就选择了 MicroApp
方案来做微前端技术调研学习的方案。
学习目标
本次学习目标有以下几个:
-
设计微前端架构
-
实现基座应用和子应用之间的通信
-
不同子应用之间的通信
-
数据共享以及数据私有
-
部署整个微前端架构以及有关应用
基座和子应用
微前端架构中很重要的一个概念就是基座和子应用
,基座就是整个应用的基础,所有的子应用就是一个个单独的前端应用(工程)。在微前端架构中,子应用是可以单独开发然后适配基座的,最终整个应用运行后,子应用是挂载在基座上的。
我这边设计的整个微前端架构的目录结构如下:
- assets
- base-app
- child-vue3-app
- child-react-app
- child-native-app
- servers
- package.json
- tsconfig.json
这其中 base-app
、 child-vue3-app
、 child-react-app
、 child-native-app
都是一个单独的应用,可独立运行,也可和微前端架构一起整体运行。
在 package.json
中配置启动脚本:
"install:main": "cd base-app && pnpm install","install:vue": "cd child-vue3-app && pnpm install","install:react": "cd child-react-app && pnpm install","install:native": "cd child-native-app && pnpm install","install:server": "cd servers && pnpm install","dev:main": "cd base-app && pnpm dev","dev:vue": "cd child-vue3-app && pnpm dev","dev:react": "cd child-react-app && pnpm dev","dev:native": "cd child-native-app && pnpm dev","dev:server": "cd servers && pnpm dev","install": "pnpm install:main && pnpm install:vue && pnpm install:react && pnpm install:native && pnpm install:server","dev": "concurrently \"pnpm dev:main\" \"pnpm dev:vue\" \"pnpm dev:react\" \"pnpm dev:native\"",
我们在运行项目的时候可以先通过pnpm install
命令安装所有的依赖(包括每一个子应用),然后通过pnpm dev
命令启动项目。
这里大致解释一下 concurrently
这个工具,就是用来同时启动多个命令,比如我们这里启动了基座应用和子应用,因此我们可以通过pnpm dev
命令同时启动基座应用和子应用。
搭建基座和子应用
我们可以用任意的技术栈来搭建基座应用。由于我们现在目前以及后续的技术栈是 vue3 + ts + vite
这套。因此这里我也就以该技术栈搭建基座。
子应用我们可以使用各种技术栈搭建不同的子应用来进行技术实践,我这边准备了一下几种技术栈:
vue3 + ts + vite
react + ts + vite
- 原生
native app (使用nodejs搭建静态资源服务器)
搭建基座应用和子应用的流程这里就无需多讲了。也不是本次分享的重点,因此这里略过。
我们设想的整个应用的结构如下:
我们把整个应用分为3个部分:
- 头部 headers
- 侧边 aside
- 内容区域 Content
我们期望的是头部和侧边区域是基座应用,内容区域是子应用。比如我们的 demo
里面的,侧边栏有首页
、VUE APP
、 REACT APP
以及 NATIVE APP
,首页是基座应用,VUE APP 和 REACT APP 以及 NATIVE APP
是子应用。
初始化基座
首先是安装依赖:
npm i @micro-zoe/micro-app --save
// 或者
pnpm add @micro-zoe/micro-app
// 或者
yarn add @micro-zoe/micro-app
然后根据官方文档操作步骤,初始化基座的 MicroApp
有关的配置代码:
import microApp from "@micro-zoe/micro-app";export function startMicro() {console.log("MicroApp start!");microApp.start();
}
这样子,我们的基座应用就初始化完成了,非常简单。
加载子应用
在基座应用中直接使用 <micro-app>
标签加载子应用:
<template><!-- name:应用名称, url:应用地址 --><micro-app name='my-app' url='http://localhost:3000/'></micro-app>
</template>
这里是以 vue
子应用为例,后续完整代码会有react
版本的。这里注意name
和url
只是这个标签的属性之二,该标签还支持多种属性,后续我们遇到一个说一个。比如我们在加载 vite
构建的子应用就需要加上iframe
属性。因为目前vite
构建的子应用目前只支持 iframe
沙箱。
子应用TS配置
由于子应用无需安装 micro-app
依赖,并且子应用通过window对象实现微前端功能以及和基座应用之间的通信,因此我们最好是给子应用声明一下window对象上面的有关属性和方法:
env.d.ts
:
/** @Author: shufei.han* @Date: 2024-08-02 09:29:40* @LastEditors: shufei.han* @LastEditTime: 2024-08-29 12:05:55* @FilePath: \micro-frontend\child-vue3-app\env.d.ts* @Description: */
/// <reference types="vite/client" />
import type { MicroMessageType } from '@/models/base.model';
import 'ant-design-vue/typings/global'declare global {interface MicroMessage<T = any> {type: MicroMessageType;value?: T;}interface Window {microApp: {addDataListener:(dataListener: (data: MicroMessage) => any, autoTrigger?: boolean) => void;removeDataListener:(dataListener: (data: MicroMessage) => any, autoTrigger?: boolean) => void;removeGlobalDataListener:(dataListener: (data: MicroMessage) => any, autoTrigger?: boolean) => void;addGlobalDataListener:(dataListener: (data: MicroMessage) => any, autoTrigger?: boolean) => void;clearDataListener: () => void;getData: () => MicroMessage;dispatch: <T extends MicroMessage = MicroMessage, C extends Function>(data:T, cb?: C) => void;getGlobalData: () => MicroMessage;setGlobalData: <T extends MicroMessage = MicroMessage, C extends Function>(data:T, cb?: C) => void;};/** 应用名称 */__MICRO_APP_NAME__: string;/** 判断应用是否在微前端环境中 */__MICRO_APP_ENVIRONMENT__: boolean;/** 子应用的静态资源前缀 */__MICRO_APP_PUBLIC_PATH__: string;/** 子应用的基础路径 */__MICRO_APP_BASE_ROUTE__: string;/** 判断当前应用是否是主应用 */__MICRO_APP_BASE_APPLICATION__: string;/** 获取真实window(即主应用window) */rawWindow: Window;/** 获取真实document(即主应用document) */rawDocument: Document;}
}export {}
子应用跨域配置
如果我们直接像上述配置一样直接接入子应用,由于浏览器的同源策略,如果子应用不支持跨域,则会报跨域错误。因此我们需要在子应用所在的 web server
进行跨域配置:
vite
配置:
export default defineConfig({server: {headers: {'Access-Control-Allow-Origin': '*',}}
})
nodejs
配置(我的 native app
是使用express
搭建的静态资源服务,因此这里以该技术栈举例):
private setCors() {this.instance.use((req, res, next) => {res.header("Access-Control-Allow-Origin", "*");res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With,Content-Type, Accept");next();});}
环境变量
Micro App
提供了一下环境变量,用于我们开发过程中的某些环境有关的逻辑判断,这些环境变量大多都通过绑定为 window
对象的属性的方式来使用,因此如果我们使用Typescript
开发子应用的话,就要进行这些全局变量的变量声明,我们在我们子应用中的声明文件(vite
构建的应用的默认声明文件就是根目录下面的env.d.ts
):
/// <reference types="vite/client" />declare global {interface Window {/** 应用名称 */__MICRO_APP_NAME__: string;/** 判断应用是否在微前端环境中 */__MICRO_APP_ENVIRONMENT__: boolean;/** 子应用的静态资源前缀 */__MICRO_APP_PUBLIC_PATH__: string;/** 子应用的基础路径 */__MICRO_APP_BASE_ROUTE__: string;/** 判断当前应用是否是主应用 */__MICRO_APP_BASE_APPLICATION__: string;/** 获取真实window(即主应用window) */rawWindow: Window;/** 获取真实document(即主应用document) */rawDocument: Document;}
}export {}
生命周期
micro-app
通过CustomEvent
定义生命周期,在组件渲染过程中会触发相应的生命周期事件。
生命周期列表
-
created:
<micro-app>
标签初始化后,加载资源前触发。 -
beforemount:
加载资源完成后,开始渲染之前触发。 -
mounted:
子应用渲染结束后触发。 -
unmount:
子应用卸载时触发。 -
error:
子应用加载出错时触发,只有会导致渲染终止的错误才会触发此生命周期。
监听方式
Vue
:
<micro-appname='xx'url='xx'onCreated={() => console.log('micro-app元素被创建')}onBeforemount={() => console.log('即将渲染')}onMounted={() => console.log('已经渲染完成')}onUnmount={() => console.log('已经卸载')}onError={() => console.log('加载出错')}
/>
React
:
因为React不支持自定义事件,所以我们需要引入一个polyfill
。
在标签所在的文件顶部
添加polyfill
,注释也要复制。
/** @jsxRuntime classic */
/** @jsx jsxCustomEvent */
import jsxCustomEvent from '@micro-zoe/micro-app/polyfill/jsx-custom-event'<micro-appname='xx'url='xx'onCreated={() => console.log('micro-app元素被创建')}onBeforemount={() => console.log('即将渲染')}onMounted={() => console.log('已经渲染完成')}onUnmount={() => console.log('已经卸载')}onError={() => console.log('加载出错')}
/>
数据通信
数据通信这一节的内容在微前端的领域非常重要,这关乎着各个子应用之间,以及子应用与主应用之间如何进行数据通信。
数据通信主要分为以下几种:
- 主应用向子应用发送数据
- 子应用向主应用发送数据
- 各个子应用之间的互相通信
主应用向子应用发送数据
主应用给子应用传递数据有两种方式:
- 通过data属性发送数据
- 通过方法手动发送数据
通过data属性发送数据
data作为 micro-app
标签的属性,用该属性作为主应用向子应用传递数据的中介:
<micro-app :name="SubApps.REACT" @created="created" :data="data" keep-alive url="http://localhost:4003/" iframe @datachange="handleChange"></micro-app>const data = ref<MicroMessage>({type: MicroMessageType.TEXT_MSG,value: 'This is a initial TextMessage'
})onMounted(() => {setInterval(() => {data.value.value = 'new value'}, 1000)
})
这种方式类似于我们平时组件中的父子组件传参,区别就是,在子应用中需要通过getData
方法区手动获取数据,该数据不是全响应式的(基座中绑定的数据如果发生变化会动态更改传给子应用的值,但是子应用需要通过getData
方法手动获取更改后的值。)。
子应用:
const data = window.microApp.getData()
通过microApp.setData
方法发送数据
除了通过data属性传递数据,还可以通过microApp.setData
方法动态发送数据:
microApp.setData(name, message)
这两种方法是有区别的,第一种方法只能通过getData
方法去手动的获取数据,数据更新时子应用是无感知的。而第二种方法类似于发布订阅机制,子应用可以随时监听到数据变化。
子应用通过注册事件监听数据
子应用可以使用window.microApp.addDataListener
方法监听来自主应用的事件消息:
window.microApp.addDataListener((data: MicroMessage) => {handleMessage(data)
})
我们在收到消息后通过handleMessage
方法来统一处理消息。
这里建议:虽然microApp
只要求我们的消息格式是 Object
就可以,但是我这边建议,我们需要对消息进行一个统一的格式管理,方便维护。
比如我这边利用TS
的特性,对基座和子应用之间的消息进行枚举,然后再定义接口来约束消息的格式,这样基座和子应用之间处理消息的时候根据消息类型来去做对应的处理逻辑:
// 对消息类型进行枚举
export enum MicroMessageType {CHANGE_THEME = 'change_theme',SET_COUNT = 'set_count',TEXT_MSG = 'text_msg',
}// 约束来基座和子应用之间通信的消息格式
interface MicroMessage<T = any> {type: MicroMessageType;value?: T;
}
总的来说:通过data属性传递数据和通过发布订阅的模式(消息事件监听)传递数据是有区别的,在实际场景中根据自己需要选取使用。
子应用向主应用发送数据
在微前端种,不仅有主应用向子应用发送消息的场景,通常也可能会有子应用向主应用发送消息的场景,在
micro-app
中,子应用通过 window.microApp.dispatch
方法发送数据,这里同样为了约束子应用向主应用发送的数据的格式,我们可以在声明文件中约定子应用推送消息的格式:
dispatch: <T extends MicroMessage = MicroMessage, C extends Function>(data:T, cb?: C) => void
然后我们就可以定义一个公用的方法用来向主应用发送数据:
export const sendMessageToBase = (message: MicroMessage) => {window.microApp.dispatch(message)
}// 使用
const handleSend = () => {sendMessageToBase({type: MicroMessageType.TEXT_MSG,value: {value},});
};
全局数据通信
全局数据通信会向主应用和所有子应用发送数据,在跨应用通信的场景中适用。
主应用发送数据:
import microApp from "@micro-zoe/micro-app";export const sendGlobalData = (message: MicroMessage) => {microApp.setGlobalData(message)
}
子应用发送数据:
// setGlobalData只接受对象作为参数
window.microApp.setGlobalData({type: '全局数据'})
主应用获取数据:
microApp.addGlobalDataListener((msg) => {Modal.info({title:`BaseApp收到全局数据`, content: JSON.stringify(msg), centered:true})mainStore.setGlobalMessages(msg)
}// 或者使用getGlobalData手动获取数据
const data = microApp.getGlobalData()
子应用获取数据:
window.microApp.addGlobalDataListener((data) => {handleGlobalMessage(data)
})// 或者使用getGlobalData手动获取数据
const data = window.microApp.getGlobalData()
虚拟路由系统
MicroApp
通过拦截浏览器路由事件以及自定义的location
、history
,实现了一套虚拟路由系统,子应用运行在这套虚拟路由系统中,和主应用的路由进行隔离,避免相互影响。建议全局配置路由模式:
microApp.start({'router-mode':'native'
});
MicroApp
提供一下这几种路由模式:
- search模式
- native模式
- native-scope模式
- pure模式
- state模式
这里就不详细说明这些路由模式了,这里只说常用的两种:
search模式路由
search是默认模式,通常不需要特意设置,search模式下子应用的路由信息会作为query参数同步到浏览器地址上。这种模式最简单也不需要去做其他的配置。
但是这种模式的路由,在页面上看起来会很奇怪,不建议使用。
native模式路由
native模式是指放开路由隔离,子应用和主应用共同基于浏览器路由进行渲染,它拥有更加直观和友好的路由体验,但配置方式更加复杂。需要基于vue-router
的base
配置或者react-router
的basename
配置:
Vue3
中的配置方法:
我们使用4.x版本的vue-router
,在生成路由的方法createWebHashHistory
中传入base
配置:
history: createWebHashHistory(import.meta.env.VITE_BASE_URL)
这里需要注意这里配置的base
需要和主应用中的该子应用的routerPath
保持一致,因此推荐使用另一种方法来设置而非通过环境变量:
<micro-app :name="SubApps.VUE" @created="created" url="http://192.168.8.125:4002/" baseroute="/vue/" iframe @datachange="handleChange"></micro-app>// router/index.ts
const router = createRouter({..............history: createWebHashHistory(window.__MICRO_APP_BASE_ROUTE__ || '/'),..............
}
React中使用
可以根据官方文档进行配置。
注意:根据子应用和主应用不同的路由模式,我们可能需要进行不同的配置或者不需要配置,具体查阅官方文档。
native模式的路由看着就比较清晰了:
总结
本次分享是对自己学习MicroApp
的过程的一个分享,本次demo也只是一个非常基础的demo,微前端架构需要考虑的内容还很多,需要再实战中遇到问题再积累总结。
最后:本次demo的源码放在了https://github.com/rondout/micro-frontend,个人认为这个demo还是有一定的参考价值,不光是微前端,还包含了一些前端工程化的内容,大家有兴趣的话可以clone下来参考,后续如果有时间我也会继续维护和补充优化该demo。
相关文章:

微前端学习以及分享
微前端学习以及分享 注:本次分享demo的源码github地址:https://github.com/rondout/micro-frontend 什么是微前端 微前端的概念是由ThoughtWorks在2016年提出的,它借鉴了微服务的架构理念,核心在于将一个庞大的前端应用拆分成多…...

【Linux-进程间通信】vscode使用通信引入匿名管道引入
一、新系统,新软件 1.新系统 哈喽宝子们,从今以后我们不再使用风靡一时的CentOS系统了,因为CentOS已经不在维护了,各大公司几乎也都从CentOS转入其他操作系统了;我们现在由原来的CentOS系统切换到最新的Ubuntu系统&a…...
nerd bug:VPG多次计算vnetloss的计算图报错的解决
待更 Reference https://www.cnblogs.com/StarZhai/p/15495292.htmlhttps://github.com/huggingface/transformers/issues/12613https://discuss.pytorch.org/t/inplace-operation-errors-when-implementing-a2c-algorithm/145406/6...

BigDecimal类Date类JDK8日期
一、BigDecimal类是什么?它有什么用?先看一段代码,看这个代码有什么问题再说BigDeimal这个类是干什么用的,这样会好理解一些。 public class Test {public static void main(String[] args) {System.out.println(0.1 0.2);Syste…...

MybatisWebApp
如何构建一个有关Mybatis的Web? 在这里给出我自己的一些配置。我的TomCat版本:10.1.28 ,IDEA版本:2024.1.4 Pom.XML文件 <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/200…...

第十五章 RabbitMQ延迟消息之延迟插件
目录 一、引言 二、延迟插件安装 2.1. 下载插件 2.2. 安装插件 2.3. 确认插件是否生效 三、核心代码 四、运行效果 五、总结 一、引言 上一章我们讲到通过死信队列组合消息过期时间来实现延迟消息,但相对而言这并不是比较好的方式。它的代码实现相对来说比…...

OpenAI 公布了其新 o1 模型家族的元提示(meta-prompt)
每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…...

Java基础14-网络编程
十四、网络编程 java.net.*包下提供了网络编程的解决方案! 基本的通信架构 基本的通信架构有2种形式: CS架构( Client客户端/Server服务端)、BS架构(Browser浏 览器/Server服务端)。无论是CS架构,还是BS架构的软件都必须依赖网络编程!。 1、网络通信的三要素 网络通…...
sed命令详解
sed命令详解 sed(stream editor,流编辑器)是 Linux 和 Unix 系统中功能强大的文本处理工具,它能够对输入流(如文件、管道输入等)进行逐行处理,从而实现多种多样的文本编辑操作。 基本语法 se…...

Linux高阶——1013—正则表达式练习
1、正则表达式匹配机制 问号放在或者*后面,表示切换成非贪婪模式 [^>]表示非右尖括号的都能匹配,直到找到href"为止 [^"]表示向右匹配,到"为止 因此,三个都能匹配 2、 正则函数 寻找结果 源文件 正则函数运…...
【CMake】为可执行程序或静态库添加 Qt 资源文件,静态库不生效问题
【CMake】添加静态库中的 Qt 资源 文章目录 可执行程序1. 创建资源文件(.qrc)2. 修改 CMakeLists.txt3. 使用资源文件 静态库1. 修改 CMakeLists.txt2. 使用资源2.1 初始化资源文件2.2 可执行程序中调用 这里介绍的不是使用 Qt 创建工程时默认的 CMakeLi…...
服务器、jvm、数据库的CPU飙高怎么处理
服务器 CPU 飙高处理 排查步骤: 监控工具:使用操作系统自带的监控工具,比如 top、htop、sar、vmstat 等,查看哪些进程占用了大量的 CPU 资源。进程排查:通过 top 等工具找到消耗 CPU 最高的进程,确定是哪…...
自适应过滤法—初级
#课本P144例题 """ Python 简单的自适应过滤移动平均预测方法 """ import numpy as np import matplotlib.pyplot as plt#用于迭代的函数 def self_adaptive( seq, N, k, maxsteps ):## 初始化序列seq_ada = np.zeros( len(seq) ) # 设置预测…...
UML图有用吗?真正厉害的软件开发,有用的吗?什么角色用?
UML(Unified Modeling Language,统一建模语言)图在软件开发中是有用的,但其使用取决于项目的规模、复杂度以及开发团队的实践习惯。真正厉害的开发者并非一定要依赖UML图,但在某些情况下,UML图确实能够提升…...

基于Java+Springboot+Vue开发的酒店客房预订管理系统
项目简介 该项目是基于JavaSpringbootVue开发的酒店客房预订管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java…...

OpenCV高级图形用户界面(5)获取指定滑动条(trackbar)的当前位置函数getTrackbarPos()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 返回滑动条的位置。 该函数返回指定滑动条的当前位置。 cv::getTrackbarPos() 函数用于获取指定滑动条(trackbar)的当前…...

拓扑排序在实际开发中的应用
1. 拓扑排序说明 简单解释:针对于有向无环图(DAG),给出一个可行的节点排序,使节点之间的依赖关系不冲突。 复杂解释:自行搜索相关资料。 本次应用中的解释:给出一个可行的计算顺序࿰…...

【CTF-SHOW】Web入门 Web27-身份证日期爆破 【关于bp intruder使用--详记录】
1.点进去 是一个登录系统,有录取名单和学籍信息 发现通过姓名和身份证号可以进行录取查询,推测录取查询可能得到学生对应学号和密码,但是身份证号中的出生日期部分未知,所以可以进行爆破 2.打开bp抓包 这里注意抓的是学院录取查…...
Windows 添加右键以管理员身份运行 PowerShell
在 Windows 系统中添加一个右键菜单选项,以便可以使用管理员权限打开 PowerShell,可以通过编辑注册表来实现。 打开注册表编辑器: 按 Win R 打开运行对话框。输入 regedit 并按回车,这将打开注册表编辑器。 导航到文件夹背景键&…...

数学建模算法与应用 第15章 预测方法
目录 15.1 微分方程模型 Matlab代码示例:求解简单的微分方程 15.2 灰色预测模型(GM) Matlab代码示例:灰色预测模型 15.3 自回归模型(AR) Matlab代码示例:AR模型的预测 15.4 指数平滑法 M…...

React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
MySQL中【正则表达式】用法
MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现(两者等价),用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例: 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

技术栈RabbitMq的介绍和使用
目录 1. 什么是消息队列?2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...

【Linux系统】Linux环境变量:系统配置的隐形指挥官
。# Linux系列 文章目录 前言一、环境变量的概念二、常见的环境变量三、环境变量特点及其相关指令3.1 环境变量的全局性3.2、环境变量的生命周期 四、环境变量的组织方式五、C语言对环境变量的操作5.1 设置环境变量:setenv5.2 删除环境变量:unsetenv5.3 遍历所有环境…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文通过代码驱动的方式,系统讲解PyTorch核心概念和实战技巧,涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...