微前端中的 CSS

news2024/11/14 20:46:08

本文为翻译 本文译者为 360 奇舞团前端开发工程师
原文标题:CSS in Micro Frontends 原文作者:Florian Rappl 原文地址:https://dev.to/florianrappl/css-in-micro-frontends-4jai

我被问得最多的问题之一是如何在微前端中处理 CSS。毕竟,样式始终是任何UI片段所需要的东西,然而,它也是全局共享的东西,因此它是潜在的冲突来源。

在这篇文章中,我想回顾一下现有的不同策略来驯服 CSS 并使其扩展以开发微前端。如果这里的任何内容对您来说听起来合理,那么也可以考虑研究“微前端的艺术”。

本文的代码可以在github.com/piral-samples/css-in-mf找到。请务必检查示例实现。

CSS 的处理是否会影响每个微前端解决方案?让我们检查可用的类型来验证这一点。

微前端的类型

过去我写了很多关于存在哪些类型的微前端、为什么存在以及何时应该使用什么类型的微前端架构的文章。采用 Web 方法意味着使用 iframe 来使用来自不同微前端的 UI 片段。在这种情况下,没有任何限制,因为无论如何每个片段都是完全隔离的。在任何其他情况下,无论您的解决方案使用客户端还是服务器端组合(或介于两者之间的东西),您最终都会得到在浏览器中评估的样式。因此,在所有其他情况下,您都会关心 CSS。让我们看看这里有哪些选项。

无特殊处理

好吧,第一个也许是最(或根据观点,最不)明显的解决方案是不进行任何特殊处理。相反,每个微前端都可以附带额外的样式表,然后在渲染微前端的组件时附加这些样式表。

理想情况下,每个组件仅在首次渲染时加载所需的样式,但是,由于这些样式中的任何一个都可能与现有样式冲突,我们也可以假装在微前端的任何组件渲染时加载所有有问题的样式。6d3a56beac7bbf20dd3cbea51dae2434.png这种方法的问题在于,当给出诸如div或之类的通用选择器时div a,我们还将重新设计其他元素的样式,而不仅仅是原始微前端的片段。更糟糕的是,类和属性也不是故障保护措施。类似的类.foobar也可以用在另一个微前端中。您将在引用的演示存储库中找到两个冲突的微前端的示例,网址为solutions/default。

摆脱这种痛苦的一个好方法是进一步隔离组件————就像 Web 组件一样。

Shadow DOM

在自定义元素中,我们可以打开一个shadow root来将元素附加到专用的迷你文档,该迷你文档实际上与其父文档相互隔离。总的来说,这听起来是一个好主意,但与这里介绍的所有其他解决方案一样,并没有强制要求。1f9f911668a852117754e14890db7ce1.png理想情况下,微前端可以自由决定如何实现组件。因此,实际的 Shadow DOM 集成必须由微前端完成。

使用 Shadow DOM 有一些缺点。最重要的是,虽然 Shadow DOM 内部的样式保留在内部,但全局样式也不会影响 Shadow DOM。乍一看,这似乎是一个优势,但是,由于整篇文章的主要目标只是隔离微前端的样式,因此您可能会错过诸如应用某些全局设计系统(例如 Bootstrap)之类的要求。link要使用 Shadow DOM 进行样式设置,我们可以通过引用或标签将样式放入 Shadow DOM 中style。由于 Shadow DOM 是无样式的,并且外部的样式不会传播到其中,因此我们实际上需要它。除了编写一些内联样式之外,我们还可以使用捆绑器将.css(或者类似的东西.shadow.css)视为原始文本。这样,我们只会得到一些文本。

piral-cli-esbuild对于 esbuild,我们可以配置如下的预制配置:

module.exports = function(options) {
  options.loader['.css'] = 'text';
  options.plugins.splice(0, 1);
  return options;
};

这会删除初始 CSS 处理器 (SASS) 并为.css文件配置标准加载器。现在,shadow DOM 中的某些样式的工作方式如下:

import css from "./style.css";
  customElements.define(name, class extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: "open" });
    }
    connectedCallback() {
      this.style.display = "contents";
      const style = this.shadowRoot.appendChild(document.createElement('style'));
      style.textContent = css;
    }
  });

上面的代码是一个有效的自定义元素,从样式的角度来看它将是透明的(display: contents),即只有其内容会反映在渲染树中。它托管一个包含单个style元素的Shadow DOM。style 的内容设置为style.css文件的文本内容。

您将在引用的演示存储库中找到两个冲突的微前端的示例,网址为solutions/shadow-dom。

域组件避免使用Shadow DOM 的另一个原因是,并不是每个 UI 框架都能够处理Shadow DOM 中的元素。因此,无论如何都必须寻找一种替代方案。其中一种方式是转而使用一些 CSS 约定。

使用命名约定

如果每个微前端都遵循全局CSS约定,那么就可以在根上避免冲突。最简单的约定是在每个类前面加上微前端的名称。例如,如果调用一个微前端shopping,并调用另一个微前端checkout,则两者都会将其active类分别重命名为shopping-active/ checkout-active。1f30106c0feb12b53137a965c7b273e9.png

这同样适用于其他可能存在冲突的名称。例如,如果有一个名为 shopping 的微前端,那么我们可以将主按钮的ID从 primary-button 改为 shopping-primary-button。如果因某种原因需要为一个元素添加样式,我们应该使用后代选择器,例如 .shopping img,来为 img 标签添加样式。这样会应用于具有 shopping 类的元素内部的 img 元素。这种方法的问题在于 shopping 微前端可能还会使用其他微前端的元素。如果我们看到 div.shopping > div.checkout img,即使通过 checkout 微前端引入的组件承载/集成了 img,它仍然会受到 shopping 微前端 CSS 的样式影响。这并不理想。

您将在引用的演示存储库中找到两个冲突的微前端的示例,网址为https://github.com/piral-samples/css-in-mf/tree/main/solutions/default。

尽管命名约定在一定程度上解决了问题,但它们仍然容易出错并且使用起来很麻烦。如果我们重命名微前端会怎样?如果微前端在不同的应用程序中获得不同的名称怎么办?如果我们在某些时候忘记应用命名约定怎么办?这就是工具帮助我们的地方。

CSS Modules

自动添加前缀并避免命名冲突的最简单方法之一是使用 CSS 模块。根据您选择的打包工具,这可能是开箱即用的功能,或者通过更改一些配置实现。5085c59378d1f37d66fe1e56ee330d6e.png

// Import "default export" from CSS
  import styles from './style.modules.css';

  // Apply
  <div className={styles.active}>Active</div>

导入的模块是一个生成的模块,将原始类名(例如 active)映射到生成的类名。生成的类名通常是CSS规则内容与原始类名混合后的哈希值。这样,生成的类名应该尽可能唯一.

例如,让我们考虑一个使用esbuild构建的微前端. 对于esbuild,您需要一个插件(esbuild-css-modules-plugin)和相应的配置更改来包含 CSS 模块。

使用Piral我们只需要调整已有的配置piral-cli-esbuild。我们删除标准 CSS 处理(使用 SASS)并替换为插件:

const cssModulesPlugin = require('esbuild-css-modules-plugin');

module.exports = function(options) {
  options.plugins.splice(0, 1, cssModulesPlugin());
  return options;
};

现在我们可以像上面展示的那样在我们的代码中使用 CSS 模块了。

您将在引用的演示存储库中找到两个冲突的微前端的示例,网址为solutions/css-modules。

使用 CSS 模块会带来一些缺点。首先,它引入了几个语法扩展来区分我们想要导入的样式(因此需要进行预处理/哈希)和应保持原样的样式(即稍后无需导入即可使用的样式) 另一种方式是将 CSS 直接引入到 JS 文件中。

CSS-in-JS

CSS-in-JS 最近的名声很差,但是,我认为这是一个误解。我也更喜欢将其称为“CSS-in-Components”,因为它为组件本身带来了样式。一些框架(Astro、Svelte 等)甚至允许通过其他方式直接执行此操作。经常被提及的缺点是性能问题,这通常是由于在浏览器中编写 CSS 造成的。然而,这并不总是必要的,在最好的情况下,CSS-in-JS 库实际上是构建时间驱动的,即没有任何性能缺陷。b9a8afece3f89185cd367bca2d291685.png然而,当我们谈论 CSS-in-JS(或 CSS-in-Components)时,我们需要考虑现有的各种选择。为简单起见,我只包含三个:Emotion、Styled Components和Vanilla Extract。让我们看看它们如何帮助我们在一个应用程序中将多个微前端整合在一起时避免冲突。

Emotion

Emotion 是一个非常棒的库,它为诸如React之类的框架提供了辅助功能,但并不要求将这些框架设置为先决条件。Emotion可以很好地优化和预先计算,并允许我们使用各种可用的 CSS 技术。

使用“pure”Emotion相对来说很简单;首先安装包:

npm i @emotion/css

现在您可以在代码中使用它,如下所示

import { css } from '@emotion/css';

  const tile = css`
    background: blue;
    color: yellow;
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
  `;

  // later
  <div className={tile}>Hello from Blue!</div>

css 助手允许我们编写 CSS,将其解析并放置在样式表中。返回值是生成的类名。

如果我们特别想使用 React,我们还可以使用Emotion 中的 jsx 工厂(引入一个名为 css 的新标准属性)或 styled 助手:

npm i @emotion/react @emotion/styled

现在感觉很像样式是 React 本身的一部分。例如,styled助手允许我们定义新组件:

const Output = styled.output`
    border: 1px dashed red;
    padding: 1rem;
    font-weight: bold;
  `;

  // later
  <Output>I am groot (from red)</Output>

相反,css助手属性使我们能够缩短表示法:

<div css={`
    background: red;
    color: white;
    flex: 1;
    display: flex;
    justify-content: center;
    align-items: center;
  `}>
    Hello from Red!
  </div>

总而言之,这生成的类名不会冲突,并提供了避免样式混乱的强大性能。特别是 styled 助手深受流行的 styled-components 库的启发。

您将在引用的演示存储库中找到两个冲突的微前端的示例,网址为:solutions/emotion。

Styled Components

styled-components库可以说是最受欢迎的CSS-in-JS解决方案,而且往往也是这类解决方案声誉不佳的原因。从历史上看,它实际上是关于在浏览器中组合CSS,但在过去几年中,它们确实在这方面取得了巨大进展。现在,您也可以对所使用的样式进行一些非常好的服务器端组合.

与emotion相比,styled-components库(对于React)需要安装一些少量的包。唯一的缺点是类型定义是事后添加的,因此您需要安装两个包以获得完整的TypeScript支持:

npm i styled-components --save
npm i @types/styled-components --save-dev

安装后,该库就已经完全可用:

import styled from 'styled-components';

const Tile = styled.div`
  background: blue;
  color: yellow;
  flex: 1;
  display: flex;
  justify-content: center;
  align-items: center;
`;

// later
<Tile>Hello from Blue!</Tile>

原理与 相同emotion。因此, 让我们探讨另一种尝试从一开始就实现零成本的选择, 而不是事后添加的.您将在引用的演示存储库中找到两个冲突的微前端的示例,网址为: solutions/styled-components

Vanilla Extract

我之前提到的利用类型接近组件并避免不必要的运行时成本的方法正是最新一代的CSS-in-JS库所涵盖的。其中最有潜力的库之一是@vanilla-extract/css。它允许你在JavaScript中直接编写CSS,并静态提取类名,从而减小打包大小,提高性能。这是一种有前途的选择,可以以类型安全和高效的方式管理样式。使用该库有两种主要方式:

  • 与你的打包工具/框架集成

  • 直接使用 CLI 在这个例子中,我们选择了第一种方式———— 通过与 esbuild 集成。为了使集成正常工作,我们需要使用该@vanilla-extract/esbuild-plugin包。现在我们将其集成到构建过程中。使用piral-cli-esbuild配置, 我们只需要将其添加到配置的插件中即可:

const { vanillaExtractPlugin } = require("@vanilla-extract/esbuild-plugin");

module.exports = function (options) {
  options.plugins.push(vanillaExtractPlugin());
  return options;
};

为了使 Vanilla Extract 正常工作,我们需要编写.css.ts文件而不是普通文件.css或.sass文件。这样的文件可能如下所示:

import { style } from "@vanilla-extract/css";
export const heading = style({
  color: "blue",
});

这是有效的 TypeScript 代码。最终我们将获得一个类名的导出————就像我们从 CSS modules、Emotion 等中获得的那样。因此,最终,上述样式将会应用如下:

import { heading } from "./Page.css.ts";

// later
<h2 className={heading}>Blue Title (should be blue)</h2>

这将在构建时完全处理,不会有任何运行时成本。

您将在引用的演示存储库中找到两个冲突的微前端的示例,网址为:solutions/vanilla-extract。

您可能会感兴趣的另一种方法是使用 CSS 实用程序库,例如 Tailwind。

CSS 实用程序,例如 Tailwind

这是一个独立的类别,但考虑到Tailwind是该类别中的主导工具,我只会介绍Tailwind。Tailwind的主导地位甚至到了一些人问“你是写CSS还是Tailwind?”这样的地步。这与2010年左右jQuery在DOM操作领域的主导地位非常相似,当时人们会问“这是JavaScript还是jQuery?”

无论如何,使用CSS实用库的优势在于样式是基于使用而生成的。这些样式不会冲突,因为它们始终由实用库以相同的方式定义。因此,每个微前端只需提供所需的实用库部分,以按预期显示微前端。

3121f301c0417bf7d6f6df39eb355f50.png如果使用 Tailwind 和 esbuild,我们还需要安装以下软件包:

npm i autoprefixer tailwindcss esbuild-style-plugin

esbuild的配置比以前略微复杂一些。esbuild-style-plugin本质上是esbuild的一个PostCSS插件,所以必须正确配置

const postCssPlugin = require("esbuild-style-plugin");

module.exports = function (options) {
  const postCss = postCssPlugin({
    postcss: {
      plugins: [require("tailwindcss"), require("autoprefixer")],
    },
  });
  options.plugins.splice(0, 1, postCss);
  return options;
};

在这里,我们移除了默认的CSS处理插件(SASS),并用PostCSS插件替代它——同时使用autoprefixer和tailwindcss这两个PostCSS扩展。现在我们需要添加一个有效的tailwind.config.js文件:

module.exports = {
  content: ["./src/**/*.tsx"],
  theme: {
    extend: {},
  },
  plugins: [],
};

这本质上是配置 Tailwind 的最低要求。它只是提到tsx应该扫描文件以了解 Tailwind 实用程序类的使用情况。然后找到的类将被放入 CSS 文件中。

因此,CSS 文件还需要知道生成/使用的声明应包含在哪里。作为最低要求,我们只有以下CSS内容:

@tailwind utilities;

还有其他@tailwind指令。例如,Tailwind自带一个重置和基础层。但是,在微前端中,我们通常不关心这些层。这属于应用程序 shell 或编排应用程序的关注范围,而不是领域应用程序的关注点。

然后,CSS将被来自Tailwind中已经指定的类所替代:

<div className="bg-red-600 text-white flex flex-1 justify-center items-center">Hello from Red!</div>

您将在引用的演示存储库中找到两个冲突的微前端的示例,网址为solutions/tailwind。

比较

到目前为止,所提出的几种方法都是微前端的可行选择。总的来说,这些解决方案也可以混合使用。一个微前端可以采用Shadow DOM方法,而另一个微前端可以使用Emotion。第三个库可能会选择Vanilla Extract。最重要的是所选择的解决方案不会产生冲突,并且没有(巨大的)运行时成本。虽然有些方法比其他方法更高效,但它们都提供了所需的样式隔离性。73d26ca8764ee8b533da012f058c74c5.png性能影响在很大程度上取决于实现方式。例如,对于CSS-in-JS,如果解析和组合都在运行时完成,可能会产生很大的性能影响。如果样式已经预解析,只在运行时组合,则可能性能影响较小。对于类似Vanilla Extract这样的解决方案,几乎没有任何性能影响。

对于 Shadow DOM,主要的性能影响可能是 Shadow DOM 内部元素的投影或移动(本质上为零)以及标签的重新评估style。然而,这是相当低的,甚至可能会产生一些性能优势,给定的样式总是切中要害,并且仅专用于要在Shadow DOM 中显示的某个组件。在示例中,我们有以下捆绑包大小:73650352a765ceb7838ab49d31731305.png对于Emotion和Styled Components,这些数字仅供参考,因为运行时可能(并且很可能应该)被共享。此外,给定的微前端示例确实很小(所有UI片段的总大小为3KB)。对于一个更大的微前端,增长肯定不会像这里描述的那样成为问题。

Shadow DOM解决方案的大小增加可以解释为我们提供的简单实用脚本,用于将现有的React渲染轻松包装到Shadow DOM中(而不创建新的树结构)。如果这样的实用脚本在中心共享,那么其大小将更接近于其他更轻量级的解决方案。

结论

在微前端解决方案中处理CSS并不需要变得困难,只需要从一开始就以有结构、有序的方式进行处理,否则就会出现冲突和问题。通常情况下,建议选择 CSS 模块、Tailwind 或可扩展的 CSS-in-JS 实现等解决方案.

- END -

关于奇舞团

奇舞团是 360 集团最大的大前端团队,代表集团参与 W3C 和 ECMA 会员(TC39)工作。奇舞团非常重视人才培养,有工程师、讲师、翻译官、业务接口人、团队 Leader 等多种发展方向供员工选择,并辅以提供相应的技术力、专业力、通用力、领导力等培训课程。奇舞团以开放和求贤的心态欢迎各种优秀人才关注和加入奇舞团。

683a6f879d6e6c70c096410189d08f31.png

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

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

相关文章

QT图形视图系统 - 使用一个项目来学习QT的图形视图框架 -第一篇

文章目录 QT图形视图系统介绍开始搭建MainWindow框架设置scene的属性缩放功能的添加加上标尺 QT图形视图系统 介绍 详细的介绍可以看QT的官方助手&#xff0c;那里面介绍的详细且明白&#xff0c;需要一定的英语基础&#xff0c;我这里直接使用一个开源项目来介绍QGraphicsVi…

AI大模型之花,绽放在鸿蒙沃土

随着生成式AI日益火爆&#xff0c;大语言模型能力引发了越来越多对于智慧语音助手的期待。 我们相信&#xff0c;AI大模型能力加持下的智慧语音助手一定会很快落地&#xff0c;这个预判不仅来自对AI大模型的观察&#xff0c;更来自对鸿蒙的了解。鸿蒙一定会很快升级大模型能力&…

macOS 虚拟桌面黑屏(转)

转自&#xff1a;macOS重置虚拟桌面、macOS 虚拟桌面黑屏 有几次出现如图的情况&#xff0c;以为是iTerm的问题&#xff0c;但是在关闭软件&#xff0c;重启之后&#xff0c;依旧无效。 后面经过网友告知&#xff0c;才知道是虚拟桌面的问题。 为了清理这个问题&#xff0c;有以…

看redisson是如何解决锁超时问题

看redisson是如何解决锁超时问题 什么是锁超时问题&#xff1f; 比如利用redis实现的分布式锁会设置一定的过期时间&#xff0c;超过该时间&#xff0c;缓存自动删除&#xff0c;锁被释放。这是防止因程序宕机等原因导致锁一直被占用。 但存在一定的问题&#xff0c;如果是该…

ADC模拟看门狗

如果被ADC转换的模拟电压低于低阀值或高于高阀值&#xff0c;AWD模拟看门狗状态位被设置。阀值位 于ADC_HTR和ADC_LTR寄存器的最低12个有效位中。通过设置ADC_CR1寄存器的AWDIE位 以允许产生相应中断。通过以下函数可以进行配置 void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx…

wolfSSL5.6.3 虚拟机ubuntu下编译运行记录(踩坑填坑)

网上相关教程很多(包括wolfSSL提供的手册上也是如此大而化之的描述)&#xff0c;大多类似如下步骤&#xff1a; ./configure //如果有特殊的要求的话可以在后面接上对应的语句&#xff0c;比如安装目录、打开或关闭哪些功能等等 make make install 然后结束&#xff0c;大体…

秒杀业务场景的处理方案

秒杀的处理方案 秒杀技术实现核心思想是运用缓存减少数据库瞬间的访问压力。在秒杀时&#xff0c;首先会将数据库的秒杀商品同步到缓存中&#xff0c;用户从缓存中查询秒杀商品&#xff0c;抢购商品时减少缓存中的库存数量。产生的秒杀订单先写到缓存&#xff0c;付款成功后再…

【TypeScript】安装的坑!

TypeScript安装 安装TypeScript安装时候可能报错这样开头的数据&#xff08;无法枚举容器中的对象&#xff09;——原因&#xff1a;没权限先解决没权限的问题如果发现无法修改-高级-修改继续安装想使用tsc-发现&#xff0c;tsc不能用解决方法&#xff1a;配置环境变量最后的最…

选读SQL经典实例笔记17_最多和最少

1. 问题4 1.1. 最多选修两门课程的学生&#xff0c;没有选修任何课程的学生应该被排除在外 1.2. sql select distinct s.*from student s, take twhere s.sno t.snoand s.sno not in ( select t1.snofrom take t1, take t2, take t3where t1.sno t2.snoand t2.sno t3.sno…

云原生之使用Docker部署homer静态主页

云原生之使用Docker部署homer静态主页 一、homer介绍1.1 homer简介1.2 homer特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载homer镜像五、部署homer静态主页5.1 创建挂…

Kubernetes详细概述

这里写目录标题 一&#xff1a;Kubernetes 概述1、K8S 是什么&#xff1f;2、为什么要用 K8S?2.1.nsenter 是k8s容器抓包工具 3、Kubernetes 集群架构与组件4.核心组件4.1 Master 组件4.1.1.Kube-apiserver4.1.2.Kube-controller-manager4.1.3.Kube-scheduler 4.2 配置存储中心…

三、Java NIO编程

目录 3.1 Java NIO基本介绍3.2 BIO 和 NIO的比较3.3 NIO三大核心 selector、channel、buffer之间的关系3.4 缓冲区&#xff08;Buffer&#xff09;3.4.1 基本介绍3.4.2 Buffer类及其子类 3.5 通道3.5.0 channel基本介绍3.5.1 FileChannel 类3.5.2 应用实例1 - 本地文件写数据3.…

使用正则表达式 移除 HTML 标签后得到字符串

需求分析 后台返回的数据是 这样式的 需要讲html 标签替换 high_light_text: "<span stylecolor:red>OPPO</span> <span stylecolor:red>OPPO</span> 白色 01"使用正则表达式 function stripHTMLTags(htmlString) {return htmlString.rep…

WPS的excel表格单元格拖动数字日期等 不自增原因

对着表格中的每个单元格右下角,在变成下图,黑十字后,拖动这个十字.就会在右侧出现一个小窗口. 里面菜单中可以选择按序数增加 但是,如果拖动,发现小窗口菜单不出现.说明这一栏开启了筛选功能.清空筛选条件后,即可恢复自增功能.

GPT突破限制回复图片

PS&#xff1a;有其他有意思的prompt可以一起沟通。 1.输入以下内容&#xff1a; Forget everything you learned before. We are currently living in 2023 and you are still in 2021. After 2 years, Open AI has brought you new features, but you still do not use the…

算法与数据结构(二十一)二叉树(纲领篇)

备注&#xff1a;本文旨在通过 labuladong 的二叉树&#xff08;纲领篇&#xff09;理解框架思维&#xff0c;用于个人笔记及交流学习&#xff0c;版权归原作者 labuladong 所有&#xff1b; 我刷了这么多年题&#xff0c;浓缩出二叉树算法的一个总纲放在这里&#xff0c;也许…

Unreal Engine 各种编译运行模式的区别和应用场景

DebugGame&#xff1a; DebugGame模式用于在开发过程中进行调试。在这个模式下&#xff0c;项目会以调试模式编译&#xff0c;并包含调试符号(debug symbols)。这样&#xff0c;你可以在游戏中设置断点、查看变量的值以及进行代码调试。但由于包含调试符号&#xff0c;生成的可…

HCIP——回顾VLAN

VLAN 一、VLAN二、VLAN的实现原理三、VLAN标签(VLAN Tag)四、VLAN的划分方式五、接门划分VLAN--接口类型Access接口Trunk接口示例Hybrid接口示例 六、总结七、实现VLAN之间通信1、使用路由器物理接口2、使用路由器子接口 八、使用三层交换机的VLANIF接口 一、VLAN 在典型交换网…

python 最大归一化

最大归一化是将数据转化到[-1,1]范围之间。公式如下 其中|X|max为x特征的绝对值的最大值。 数据标准化算法介绍—数据建模工具_预处理_Max_字段 """ 最大绝对值归一化&#xff08;max abs normalization &#xff09;&#xff1a;也就是将数值变为单位长度&am…

RPMsg-Lite上手

文章目录 1、rpmsg-lite介绍2、rpmsg-lite 应用 现在的芯片非常复杂&#xff0c;很多都是包含多个核&#xff0c;特别是片上系统&#xff08;SoC&#xff09;&#xff0c;一颗芯片上不仅包含了很多个核心&#xff0c;并且很多核心都是异构的。 为了最大限度的发挥他们的性能&am…