微前端--qiankun(3)

微前端–qiankun(3)

微前端的运行原理

  • 监听路由变化
  • 匹配子应用
  • 加载子应用
  • 渲染子应用

监听路由变化

window.onhashchangewindow.addEventListener('popstate',() => {})等等,下篇文章我写个

匹配子应用

const currentApp = apps.find(app => window.location.pathname.startWith(app.activeRule))

加载子应用

function handleRouter = async () => {// 匹配子应用// 加载资源const html = await fetch(currentApp.entry.then(res => res.text())// 将 html 渲染到指定的容器内const container = document.querySelector(currentApp.container)
}

渲染子应用

export const importHTML = url => {const html = await fetch(currentApp.entry).then(res => res.text()const template = document.createElement('div')template.innerHTML = htmlconst scripts = template.querySelectAll('script')const getExternalScripts = () => {console.log('解析所有脚本: ', scripts)}const execScripts = () => {}return {template, // html 文本getExternalScripts, // 获取 Script 脚本execScripts, // 执行 Sript 脚本}
}
const getExternalScripts = async () => {return Promise.all(Array.from(scripts).map(script => {// 获取 scr 属性const src = script.getAttribute('src')if (!src) {return Promise.resolve(script.innerHTML)} else {return fetch(src.startWith('http') ? src : `${url}${src}`).then(res => res.text())}}))
}
const execScripts = async () => {const scripts = await getExternalScripts() scripts.forEach(code => {eval(code)})
}

qiankun实现

qiankun的核心理念
  • 子应用的注册和加载
  • 应用间通信
  • 样式隔离和共享
  • 状态管理: 支持主应用和子应用之间的共享状态管理,保持数据的一致性
安装依赖并引入主项目

在主应用目录中新建一个micro-app.js

const microApps = [{name: 'sub-react',entry: '//localhost:9001/',activeRule: '/sub-react',container: '#subapp-viewport', // 子应用挂载的divprops: {routerBase: '/sub-react'}},{name: 'sub-vue',entry: '//localhost:9002/',activeRule: '/sub-vue',container: '#subapp-viewport', // 子应用挂载的divprops: {routerBase: '/sub-vue'}},{name: 'sub-vue3',entry: '//localhost:9003/',activeRule: '/sub-vue3',container: '#subapp-viewport', // 子应用挂载的divprops: {routerBase: '/sub-vue3'}}
]
export default microApps;

这里其实和状态管理工具结合起来,代码实例如下

# 主应用
export const microApps = [{name: 'micro-clouds',entry: process.env.VUE_APP_CLOUDS,activeRule: '/micro-clouds',container: '#subapp2', // 子应用挂载的divprops: {routerBase: '/micro-clouds',// 父应用的store传递给子应用mainStore: store,// 父应用传递给子应用的登录信息user: utils.getStorage('user')}}
]
# 子应用接受父应用传过来的登录信息并写入storage中
export async function mount(props) {// 父级传过来的登录信息写进子系统缓存中utils.setStorage("user", props.user);// 标记当前启动形式为微服务启动store.commit("app/microChange", true);await render(props);
}

对于子应用:子应用的vue.config.js应该设置跨域。将子应用打包输出格式为UMD【后面写这个】

module.exports = {outputDir: 'dist',assetsDir: 'static',filenameHashing: true,devServer: {hot: true,disableHostCheck: true,port,overlay: {warnings: false,errors: true,},headers: {'Access-Control-Allow-Origin': '*',},},// 自定义webpack配置configureWebpack: {resolve: {alias: {'@': resolve('src'),},},output: {// 把子应用打包成 umd 库格式library: `${name}-[name]`,libraryTarget: 'umd',jsonpFunction: `webpackJsonp_${name}`,},},
};

在app.vue文件中配置

export default {mounted () {registerMicroApps(microApps);start();}
}

当微应用信息注册完之后,一旦浏览器url发生变化,便会自动触发qiankun的匹配逻辑,所有的activeRule规则规则上的微应用就会加载到指定的container上,同时依次调用微应用暴露出来的钩子。

微应用

微应用需要在自己的入口js中导出bootstrap, mount, unmount三个生命周期钩子。

  • bootstrap: 只会再微应用初始胡的时候调用一次,下次微应用重新进入的时候会直接调用mount钩子,不会重复触发bootstrap,这李可以做一些全局变量的初始化
  • mount: 应用每次进入都会调用mount方法,这里触发应用的渲染方法
  • unmount: 每次应用切出/卸载都会调用的方法
  • update: 可选生命周期钩子,仅仅使用loadMicroApp方法的时候加载微应用的时候生效。
    子应用的main.js
import './public-path';
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import App from './App.vue';
import routes from './router';let router = null;
let instance = null;
let history = null;function render(props = {}) {const { container } = props;history = createWebHistory(window.__POWERED_BY_QIANKUN__ ? '/sub-vue3' : '/');router = createRouter({history,routes,});instance = createApp(App);instance.use(router);instance.mount(container ? container.querySelector('#sub-vue3') : '#sub-vue3');
}if (!window.__POWERED_BY_QIANKUN__) {render();
}export async function bootstrap() {console.log('%c ', 'color: green;', 'vue3.0 app bootstraped');
}function storeTest(props) {props.onGlobalStateChange &&props.onGlobalStateChange((value, prev) => console.log(`[onGlobalStateChange - ${props.name}]:`, value, prev),true,);props.setGlobalState &&props.setGlobalState({ignore: props.name,user: {name: props.name,},});
}export async function mount(props) {storeTest(props);render(props);instance.config.globalProperties.$onGlobalStateChange = props.onGlobalStateChange;instance.config.globalProperties.$setGlobalState = props.setGlobalState;
}export async function unmount() {instance.unmount();instance._container.innerHTML = '';instance = null;router = null;history.destroy();
}

子应用的public-path.js

if (window.__POWERED_BY_QIANKUN__) {// eslint-disable-next-line no-undef__webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
}
面包屑融合父子应用的路由

这里用的是vuex

const actions = {// 处理父应用的to.matchgetBreadcrumb({ commit }, matched) {const levelList = matched.filter((item) => item.meta && item.meta.title && item.meta.breadcrumb !== false);commit('setBreadcrumb', JSON.parse(JSON.stringify(levelList)));},// 处理微应用的to.matchgetMicroBreadcrumb({ commit }, matchedList) {const microLevel = matchedList.filter((ele) => ele.meta && ele.meta.title && ele.meta.breadcrumb !== false);/** 为了解决这个告警采用 JSON.parse(JSON.stringify(microLevel))   vue3.0需要注意的地方* runtime-core.esm-bundler.js:198 [Vue warn]: Avoid app logic that relies on enumerating keys on a component instance.* The keys will be empty in production mode to avoid performance overhead.*/commit('setMicroBreadcrumb', JSON.parse(JSON.stringify(microLevel)));}
}
# 主应用面包屑组件中
const getBreadcrumb = async () => {// 判断是微应用就去微应用上报的to.matchif (route.path.startsWith('/micro')) {// 这里需要做一个vuex异步处理,否则取不到子应用上报的to.matchstore.subscribe((mutation, state) => {if (mutation.type === 'app/setMicroBreadcrumb') {levelList.value = store.state.app.microBreadcrumbs}})} else {await store.dispatch('app/getBreadcrumb', route.matched)levelList.value = store.state.app.breadcrumbs}
}
# 主应用面包屑组件中
const getBreadcrumb = async () => {// 判断是微应用就去微应用上报的to.matchif (route.path.startsWith('/micro')) {// 这里需要做一个vuex异步处理,否则取不到子应用上报的to.matchstore.subscribe((mutation, state) => {if (mutation.type === 'app/setMicroBreadcrumb') {levelList.value = store.state.app.microBreadcrumbs}})} else {await store.dispatch('app/getBreadcrumb', route.matched)levelList.value = store.state.app.breadcrumbs}
}
qiankun样式隔离
  • shadow dom
  • scoped css => start({ sanbox: true})
  • strictStylelsolation=> 乾坤为每个微应用的容器包裹一个shadow dom节点,所有的子节点都会被#shadow-root包裹,从而保证微应用的让是不会对全局产生影响。
  • exprimentalStylelsolation=> experimentalstyleIsolation被设置为true,qiankun会改写子应用所添加的样式队则增加一个特殊的选择器规则来限定其影响的范围。
Vue Scoped

在vue的单文件组件中使用< style scoped>,vue会自动将改样式应用于当前组件的元素,并在编译的过程中为css规则添加要给唯一的属性选择器。

h3 {background-color: pink;color: blue;
}// ======= 使用 style scoped 后 ====>h3[data-v-469af010] {background-color: pink;color: blue;
}
CSS Modules

这个使用webpack配置一下就可以了,这种方法也能实现组件级别样式隔离,能够设置子组件和全局样式。

CSS 沙箱

单实例场景下的子应用和子应用的样式隔离
单实例场景下的子应用和主应用的样式隔离
多实例场景下的子应用与子应用的样式隔离
多实例场景下的子应用和主应用的样式隔离

命名约定

通过给特定范围内的元素添加特定的类型或者命名前缀,然后再css中通过类选择器或者属性选择器来应用相应的样式。

CSS Modules
// webpack.config.js
{test: /\.(le|c)ss$/,use: ['style-loader', {loader: 'css-loader',options: {modules: true // 开启 css modules}}, 'less-loader'],
}
// webpack.config.js
{test: /\.(le|c)ss$/,use: ['style-loader', {loader: 'css-loader',options: {modules: true // 开启 css modules}}, 'less-loader'],
}
import React from 'react';
import styles from './Button.module.css';interface ButtonProps {disabled?: boolean;onClick: () => void;
}const Button: React.FC<ButtonProps> = ({ disabled, onClick, children }) => {const buttonClasses = `${styles.button} ${disabled ? styles['button--disabled'] : ''}`;return (<button className={buttonClasses} onClick={onClick} disabled={disabled}>{children}</button>);
};export default Button;
CSS-in-js

将css样式卸载JavaScript代码中的方式,通过将样式与组件绑定在一起,实现了样式的局部化和杀向话。

import React from 'react';
import styled from 'styled-components';const Button = styled.button`background-color: blue;color: white;padding: 10px 20px;border: none;border-radius: 4px;cursor: pointer;&:hover {background-color: darkblue;}&:disabled {opacity: 0.5;cursor: not-allowed;}
`;const ExampleComponent = () => {return (<div><Button onClick={() => console.log('Button clicked')}>Click me</Button><Button disabled>Disabled Button</Button></div>);
};export default ExampleComponent;
Shadow DOM

创建一个隔离的dom子树,其中的样式和脚本不会影响外部的dom,通过再元素上应用shadow dom,可以将样式限定再shadow dom内部,实现样式的沙箱化

  1. 兼容性问题
  2. 可能会用到第三方UI库,将这些组件挂载到全局document.body时, 由于子应用的样式只能作用于shadow dom中,所以这些组件的样式是无法作用于shadow dom,这样就会导致样式丢失的问题。
experimentalStyleIsolation样式隔离

当experimentalStyleIsolation 被设置为 true 时,qiankun 会改写子应用所添加的样式为所有样式规则增加一个特殊的选择器规则来限定其影响范围,官方文档中的例子如下:

// 假设应用名是 react16
.app-main {font-size: 14px;
}div[data-qiankun-react16] .app-main {font-size: 14px;
}

微前端框架

  • qiankun: function + proxy + with
  • micro-app: web components
  • wujin: web components 和 iframe

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

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

相关文章

FPGA教程|零基础到实战的全方位指导

在数字化时代&#xff0c;FPGA&#xff08;现场可编程门阵列&#xff09;作为一种灵活的硬件编程平台&#xff0c;正逐渐成为电子工程师和计算机科学家必备的技能之一。无论你是电子专业的学生&#xff0c;还是职场中的工程师&#xff0c;掌握FPGA开发技术&#xff0c;都将为你…

前端与HTML

前端与HTML 什么是前端&#xff1f; 解决GUI人机交互问题跨终端&#xff08;PC/移动浏览器&#xff09;&#xff08;客户端小程序&#xff09;&#xff08;VR/AR等&#xff09;Web技术栈 前端工程师&#xff1a;利用web技术栈解决多端图形界面用户交互的工程师 前端技术栈 …

CDGA|数据治理:安全如何贯穿数据供给、流通、使用全过程

随着信息技术的飞速发展&#xff0c;数据已经成为企业运营、社会管理和经济发展的核心要素。然而&#xff0c;数据在带来巨大价值的同时&#xff0c;也伴随着诸多安全风险。因此&#xff0c;数据治理的重要性日益凸显&#xff0c;它不仅仅是对数据的简单管理&#xff0c;更是确…

Lua 类管理器

Lua 类管理器 -- ***** Class Manager 类管理*****‘local ClassManager {}local this ClassManagerfunction ClassManager.Class(className, ...)print(ClassManager::Class)--print(className)-- 构建类local cls {__className className}--print(cls)-- 父类集合local …

rv1126物体检测 rkmedia、opencv……

整体码流流向&#xff1a; 因此代码也分为这几部分&#xff1a; VI&#xff1a;采集视频 配置视频采集信息 模型推理线程&#xff1a;获取VI码流、载入模型、进行模型推理、保存推理结果 画框线程&#xff1a;获取VI码流、获取推理结果、显示推理结果、输出码流到VENC VENC…

LeetCode-day25-2844. 生成特殊数字的最少操作

LeetCode-day25-2844. 生成特殊数字的最少操作 题目描述示例示例1&#xff1a;示例2&#xff1a;示例3&#xff1a; 思路代码 题目描述 给你一个下标从 0 开始的字符串 num &#xff0c;表示一个非负整数。 在一次操作中&#xff0c;您可以选择 num 的任意一位数字并将其删除…

如何使用C#快速创建定时任务

原文链接&#xff1a;https://www.cnblogs.com/zhaotianff/p/17511040.html 使用Windows的计划任务功能可以创建定时任务。 使用schtasks.exe可以对计划任务进行管理&#xff0c;而不需要编写额外代码 这里掌握schtasks /CREATE 的几个核心参数就可以快速创建计划任务 /SC …

vue3响应式转换常用API

响应式常用API ref 相关&#xff1a;toRef、toRefs、unRef只读代理&#xff1a;readonly判断相关&#xff1a;isRef、isReactive、isProxy、isReadonly3.3新增API&#xff1a;toValue ref相关 toRef&#xff1a;基于响应式对象的某一个属性&#xff0c;将其转换为 ref 值 i…

必修-场景题

场景题 1. 树遍历二叉树三叉树 2. 并发问题架构设计前端后端NginxSpring Cloud Gateway和限流的依赖&#xff1a; 处理优惠券的缓存逻辑&#xff1a;处理优惠卷HTTP请求&#xff1a;实现令牌桶算法请求限流一秒 用Resilience4j实现降级策略在 application.yml 或 application.p…

论文总结:A Survey on Evaluation of Large Language Models-鲁棒性相关内容

A Survey on Evaluation of Large Language Models 只取了鲁棒性相关的内容 LLMs&#xff1a;《A Survey on Evaluation of Large Language Models大型语言模型评估综述》理解智能本质(具备推理能力)、AI评估的重要性(识别当前算法的局限性设 3.2.1 Robustness鲁棒性&#xf…

Gitlab以及分支管理

一、概述 Git 是一个分布式版本控制系统&#xff0c;用于跟踪文件的变化&#xff0c;尤其是源代码的变化。它由 Linus Torvalds 于 2005 年开发&#xff0c;旨在帮助管理大型软件项目的开发过程。 二、Git 的功能特性 Git 是关注于文件数据整体的变化&#xff0c;直接会将文件…

php将数字转为中文汉字

记录&#xff1a;php将数字转为中文汉字 if (!function_exists(num_to_cn_money)) {// 金额数字转汉字function num_to_cn_money($num, $mode true, $sim false){if (!is_numeric($num)) return 含有非数字非小数点字符&#xff01;;$char $sim ? array(零, 一, 二, 三, 四…

HTTP模块(二)

HTTP 设置 HTTP 响应报文 HTTP报文常见属性&#xff1a; const http require(http);const server http.createServer((request, response) > {// 设置请求状态码 2xx 4xx 5xxresponse.statusCode 200;// 设置请求描述 了解即可response.statusMessage hello// 指定响…

谷粒商城实战笔记-59-商品服务-API-品牌管理-使用逆向工程的前后端代码

文章目录 一&#xff0c; 使用逆向工程生成的代码二&#xff0c;生成品牌管理菜单三&#xff0c;几个小问题 在本次的技术实践中&#xff0c;我们利用逆向工程的方法成功地为后台管理系统增加了品牌管理功能。这种开发方式不仅能快速地构建起功能模块&#xff0c;还能在一定程度…

uni-app声生命周期

应用的生命周期函数在App.vue页面 onLaunch:当uni-app初始化完成时触发&#xff08;全局触发一次&#xff09; onShow:当uni-app启动&#xff0c;或从后台进入前台时显示 onHide:当uni-app从前台进入后台 onError:当uni-app报错时触发,异常信息为err 页面的生命周期 onLoad…

如何使用RESTful API构建 web 应用程序。

RESTful API&#xff08;Representational State Transferful Application Programming Interface&#xff09;是一种架构风格&#xff0c;用于设计网络应用程序的 API。它基于 HTTP 协议&#xff0c;使用不同的 HTTP 动词&#xff08;GET、POST、PUT、DELETE&#xff09;执行不…

rust 初探 -- 枚举和模式匹配

rust 初探 – 枚举和模式匹配 定义枚举 enum IpAddrKind {// 将数据附加到枚举的变体中// - 不需要额外使用 struct// - 每个变体可以拥有不同的类型以及关联的数据量V4(String), V6(String), }可以使用 impl 为枚举定义方法 enum IpAddrKind {a,b(String),c{x: i32, y: i32}…

Linux-安装VMware-01

一、认识linux Linux 是一个开源的类 Unix 操作系统&#xff0c;由林纳斯托瓦兹&#xff08;Linus Torvalds&#xff09;于1991年首次发布。Linux 是许多计算机硬件的底层操作系统&#xff0c;特别是服务器、嵌入式系统和个人电脑。它支持多种架构&#xff0c;包括 x86、x64、A…

算法学习笔记(8.8)-多重背包

目录 Question: 思路解析&#xff1a; 代码示例 多重背包的优化问题&#xff1a; 1.二进制优化 代码示例&#xff1a; 2.单调队列优化(滑动窗口) 代码示例 Question: 4. 多重背包问题 I - AcWing题库https://www.acwing.com/problem/content/description/4/ 多重背包简单来说其…

eqmx上读取数据处理以后添加到数据库中

目录 定义一些静态变量 定时器事件的处理器 订阅数据的执行器 处理json格式数据和将处理好的数据添加到数据库中 要求和最终效果 总结一下 定义一些静态变量 // 在这里都定义成全局的 一般都定义成静态的private static MqttClient mqttClient; // mqtt客户端 private s…