微前端中的 CSS

本文为翻译 本文译者为 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 CSSimport 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.rhkb.cn/news/76622.html

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

相关文章

键入网址到网页显示,期间发生了什么

HTTP 浏览器做的第一步工作是解析URL 首先浏览器做的第一步工作就是要对URL进行解析&#xff0c;从而生成发送给 web 服务器的请求信息。 所以图中长长的URL实际上是请求服务器里的文件资源。 如果图中的蓝色部分URL元素省略了&#xff0c;那应该请求哪个文件呢&#xff1f; 当…

HTML5注册页面

分析 注册界面实际上是一个表格&#xff08;对齐&#xff09;&#xff0c;一行有两个单元格。 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewport" content"widthdevic…

Linux:在使用UEFI固件的计算机上内核是如何被启动的

前言 启动计算机通常不是一件难事&#xff1a;按下电源键&#xff0c;稍等片刻&#xff0c;你就能看到一个登录界面&#xff0c;再输入正确的密码&#xff0c;就可以开启一天的网上冲浪之旅了。 但偶尔这件事没那么顺利&#xff0c;有时候迎接你的不是熟悉的登录界面&#xf…

java 数组的使用

数组 基本介绍 数组可以存放多个同一类型的数据&#xff0c;数组也是一种数据类型&#xff0c;是引用类型。 即&#xff1a;数组就是一组数据。 数组的使用 1、数组的定义 方法一 -> 单独声明 数据类型[] 数组名 new 数据类型[大小] 说明&#xff1a;int[] a new int…

上海亚商投顾:沪指震荡微涨 金融、地产午后大幅走强

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数早盘震荡&#xff0c;午后集体拉升反弹&#xff0c;创业板指涨超1%。券商等大金融板块午后再度走强&#…

学习线性表:掌握基本操作和应用

线性表 前言 欢迎来到本博客的线性表部分&#xff01;&#x1f604;&#x1f389;在这篇博文中&#xff0c;我将带您深入探索数据结构中的线性表&#xff0c;这是计算机科学中最基础也是最重要的数据结构之一。 线性表是一种线性数据结构&#xff0c;它由一组连续的元素组成…

socket server服务器开发常见的并发模型

两种高效的事件处理模式 服务器程序通常需要处理三类事件&#xff1a;I/O 事件、信号及定时事件。有两种高效的事件处理模式&#xff1a;Reactor和 Proactor&#xff0c;同步 I/O 模型通常用于实现Reactor 模式&#xff0c;异步 I/O 模型通常用于实现 Proactor 模式。 无论是 …

Flink开发环境准备: centos-jdk8

linux-jdk8 - Flink开发环境准备 一、基本介绍二、环境准备1.1 JDK环境1.2 开发工具1.3 Maven环境 三、flink下载安装配置3.1 Flink下载3.2 flink本地模式安装 - linux3.3 常用配置3.4 日志的查看和配置 四、单机 Standalone 的方式运行 Flink 一、基本介绍 Flink底层源码是基于…

python+django+mysql项目实践二(前端及数据库)

python项目实践 环境说明&#xff1a; Pycharm 开发环境 Django 前端 MySQL 数据库 Navicat 数据库管理 前端模板 添加模板 在templates下创建 views文件中添加 创建数据库 连接数据库 在setting文件中进行配置 创建表

Redis持久化机制

AOF 把对redis的写操作记录下来&#xff0c;先执行命令&#xff0c;再执行写入&#xff0c;优势在于&#xff1a; 当然也有风险&#xff1a;丢失和对下一个命令造成阻塞 丢失的原因是执行写操作和记录日志是两个过程 下一个命令造成阻塞的原因是两个过程是同步的 第二个问…

python GUI nicegui初识一(登录界面创建)

最近尝试了python的nicegui库&#xff0c;虽然可能也有一些不足&#xff0c;但个人感觉对于想要开发不过对ui设计感到很麻烦的人来说是很友好的了&#xff0c;毕竟nicegui可以利用TailwindCSS和Quasar进行ui开发&#xff0c;并且也支持定制自己的css样式。 这里记录一下自己利…

【在英伟达nvidia的jetson-orin-nx上使用调试can基础收发-硬件连接-开机自启动can-初步调试】

【在英伟达nvidia的jetson-orin-nx上使用调试can基础收发-硬件连接-开机自启动can-初步调试】 1、概述2、实验环境3、自我学习4-1、实验过程1、硬件原理图焊接连接模块2、输入命令3、测试过程 4-2、目前遗留问题# 1-1、发送可以发送&#xff0c;但是PC发送数据收不到。# 1-2、接…

Maven项目中Lifecycle和Plugins下的install的区别

在Maven中&#xff0c;如果你的web和service在不同的模块下&#xff0c;如果直接用用tomcat插件运行web层&#xff0c;那么运行时会报错 Failed to execute goal org.apache.maven.plugins:maven-install-plugin:2.5.2:install (default-cli) on project springboot: The pack…

ResNet-残差网络二

文章目录 残差结构的一般表达形式残差结构中的信息传播clean path propagation前向传播反向传播 h(x)为恒等映射的重要性h(x)的实验证明 激活层的位置 和其他网络的对比 上一篇讲了 ResNet 论文中的第一篇&#xff1a;Deep Residual Learning for Image Recognition&#xff0c…

每日一题——反转单链表

反转单链表 题目链接 下面主要介绍两种方法&#xff1a; 方法一&#xff1a; 利用三个指针变量进行反转 具体过程如图所示&#xff1a; 注意&#xff1a;循环的结束的条件为cur NULL而不是next NULL 实现代码&#xff1a; struct ListNode* reverseList(struct ListNode* …

【C++】——内存管理

目录 回忆C语言内存管理C内存管理方式new deleteoperator new与operator delete函数new和delete的实现原理定位new表达式(placement-new)malloc/free和new/delete的区别 回忆C语言内存管理 void Test() {int* p1 (int*)malloc(sizeof(int));free(p1);int* p2 (int*)calloc(4…

解决Linux下PyCharm无法新建文件

一、问题描述 如图&#xff0c;在Ubuntu Linux系统中使用pycharm管理项目时&#xff0c;提示无法新建.py源文件&#xff1a; 二、问题解决 将问题定性为文件夹&#xff08;目录&#xff09;权限问题&#xff0c;在终端中打开项目文件夹的上级目录&#xff0c;将整个项目目录的…

mysql按照日期分组统计数据

目录 前言按天统计按周统计按月统计按年统计date_format参数 前言 mysql的date_format函数想必大家都使用过吧&#xff0c;一般用于日期时间转化 # 例如 select DATE_FORMAT(2023-01-01 08:30:50,%Y-%m-%d %H:%i:%s) # 可以得出 2023-01-01 08:30:50# 或者是 select DATE_FOR…

【vue】vue-image-lazy图片懒加载使用与介绍【超详细+npm包源代码】

简介 当前插件是基于vue3&#xff0c;写的一个图片懒加载&#xff0c;文章最下方是npm包的源码&#xff0c;你可以自己拿去研究和修改&#xff0c;如有更好的想法可以留言&#xff0c;如果对你有帮助&#xff0c;可以点赞收藏和关注&#xff0c;谢谢。 后续会添加图片放大和切…

98. Python基础教程:try...except...finally语句

【目录】 文章目录 1. try...except...finally语法介绍2. try...except...finally执行顺序3. 捕获特定类型的异常4. 捕获所有类型的异常5. 实操练习-打开txt文件并输出文件内容 【正文】 在今天的课程中&#xff0c;我们将学习Python中的异常处理语句try...except...finally。 …