React学习笔记(番外二)——列表多选批量处理复合组件
React学习笔记(番外二)——列表多选批量操作复合组件
- 前言
- 〇、Show you the code
- 一、 任务分析及拆解
- 表头行的Checkbox——总开关
- 记录行的Checkbox——行级开关
- 二、 基础实现
- 表头行的文件——header-row.js
- 记录行的文件——record-row.js
- 页面的文件App.js
- 阶段效果
- 三、 完善控制逻辑
- custom-hooks.js——自定义React Hook
- 4处useState
- 4处useCallback
- 1处useMemo
- App.js——部分改造
- header-row.js——部分改造
- record-row.js——部分改造
- 阶段效果
- 四、 最后一步
- 后记
前言
近期有需求需要实现如题的列表多选批量处理复合组件。因为是两部分组件互相控制,对于初次实现的我来说还是有一定困难的。经过几天的实现、Bugfix,现对这种比较常见的复合组件的实现作以记录。
〇、Show you the code
成熟的程序猿讲究【Talk is cheap, show me the code】,如果你只想看代码:
本篇文章中,最终的完整代码已托管在CodeSandBox,点击前往,查看代码及编译、渲染结果
一、 任务分析及拆解
先来看一下上面说的到底是什么。如下图,当我们有一个比较长的列表时,有时希望一次性多选几行,进行批量操作。

我们可以很轻松地将所需的复合组件拆分为以下几部分子组件:
- 表头行的Checkbox——总开关
- 记录行的Checkbox——行级开关
- 右上方的操作按钮
表头行的Checkbox——总开关
这个Checkbox比较特殊,有3个状态,如下图:

- 未选中状态: 点击后变为
全部选中状态。此状态下,列表中的记录都是未选中状态。表头行Checkbox由于点击达到该状态时所有记录行Checkbox都变为未选中状态,所有记录行Checkbox由于点击都达到未选中状态时,表头行Checkbox也受控变为未选中状态。 - 部分选中状态: 点击后变为
全部选中状态。此状态下,列表中有部分记录([1, n-1])为选中状态。该状态只能由部分记录行Checkbox受到点击变为选中状态而达到。 - 全部选中状态: 点击后变为
未选中状态。此状态下,列表中的记录都是选中状态。表头行Checkbox由于点击达到该状态时所有记录行Checkbox都变为选中状态,所有记录行Checkbox由于点击都达到选中状态时,表头行Checkbox也受控变为全部选中状态。
记录行的Checkbox——行级开关
记录行前的就是常规的Checkbox,只有两种状态,如下图:

- 未选中状态: 点击后变为
选中状态。此状态下,当前行的记录是未选中状态。所有记录行Checkbox都为该状态时表头行Checkbox受控变为未选中状态。 - 选中状态: 点击后变为
未选中状态。此状态下,当前行的记录是选中状态。部分记录行Checkbox为该状态时表头行Checkbox受控变为部分选中状态。所有记录行Checkbox都为该状态时表头行Checkbox受控变为全部选中状态。
二、 基础实现
我们将一个包含列表的页面分为三个部分:
- 表头行的文件——header-row.js
- 记录行的文件——record-row.js
- 页面的文件——App.js
接下来分别实现三个部分
表头行的文件——header-row.js
import "./index.css";
import React from "react";
import { Checkbox } from "antd";const HeaderRow = () => {return (<div className="header-row"><div className="column0"><Checkbox /></div><div className="column1">Id</div><div className="column2">Title</div><div className="column3">Desc</div></div>);
};export default HeaderRow;
记录行的文件——record-row.js
import "./index.css";
import React from "react";
import { Checkbox } from "antd";const RecordRow = (props) => {let { record } = props;let { id, title, desc } = record;return (<div className="record-row"><div className="column0"><Checkbox /></div><div className="column1">{id}</div><div className="column2">{title}</div><div className="column3">{desc}</div></div>);
};export default RecordRow;
页面的文件App.js
import "./styles.css";
import React, { useMemo } from "react";
import HeaderRow from "./components/header-row";
import RecordRow from "./components/record-row";const MainPage = (props) => {// 生成要显示的记录数据,现实中应该通过后台请求获得let records = useMemo(() => {let _records = [];for (let i = 0; i < 10; i++) {_records.push({id: i + 1,title: `这是测试标题${i + 1}`,desc: `这是测试描述${i + 1}`});}return _records;}, []);// 记录行的组件列表let recordRowViews = useMemo(() => {return records.map((item) => {return <RecordRow key={`record-${item.id}`} record={item} />;});}, [records]);return (<div><HeaderRow />{recordRowViews}</div>);
};export default MainPage;
阶段效果
基础实现比较简单,当然功能也不完善。我们还没有写Checkbox之间的控制逻辑,先看看目前的效果:

三、 完善控制逻辑
因为实现中涉及到多个页面具有同样的控件和逻辑需要,因此实现中尽可能地考虑代码的复用性。这里的代码实现拆分为以下几个部分:
- custom-hooks.js——包含几个自定义React Hook,最主要的Checkbox互相控制算法逻辑部分
- App.js——前文中已有的文件,做部分改造
- header-row.js——前文中已有的文件,做部分改造
- record-row.js——前文中已有的文件,做部分改造
custom-hooks.js——自定义React Hook
import { useState, useMemo, useCallback } from "react";/*** 列表多选,批量处理的逻辑Hook* @param showedRecords 经过过滤后页面需要显示的列表项* @returns {[[string],boolean,boolean,boolean,function,function]}*/
const useBatchOperation = (allRecords) => {// 表示部分[1, n-1]行被勾选的状态,仅控制UIlet [partialChecked, setPartialChecked] = useState(false);// 表示是否所有的条目当前都被选中(即UI表现为表头的checkbox是否勾选)let [headerChecked, setHeaderChecked] = useState(false);// 表示当前用户是否主动点击了表头的那一个checkbox,点击后无论状态如何,其他checkbox都要跟随该状态,同headerChecked配合控制使用let [operateAll, setOperateAll] = useState(false);// 当前勾选的行所代表的数据单元组成的列表let [checkedItemList, setCheckedItemList] = useState([]);// 选中某行记录let checkItem = useCallback((item) => {let newCheckedItemList = [...checkedItemList];if (!Array.isArray(item)) {item = [item];}for (let i = 0; i < item.length; i++) {let index = checkedItemList.indexOf(item[i]);if (index === -1) {newCheckedItemList.push(item[i]);}}setCheckedItemList(newCheckedItemList);return newCheckedItemList;},[checkedItemList]);// 取消选中某行记录let uncheckItem = useCallback((item, clear = false) => {let newCheckedItemList = [];if (!clear) {if (!Array.isArray(item)) {item = [item];}for (let i = 0; i < checkedItemList.length; i++) {if (item.indexOf(checkedItemList[i]) === -1) {newCheckedItemList.push(checkedItemList[i]);}}}setCheckedItemList(newCheckedItemList);return newCheckedItemList;},[checkedItemList]);// 记录行checkbox的onChange事件let onSingleCheckBoxChange = useCallback((checked, record) => {// 按照判断逻辑,必须放在第一行setOperateAll(false);let newCheckedItemList;if (checked) {newCheckedItemList = checkItem(record);} else {newCheckedItemList = uncheckItem(record);}setPartialChecked(newCheckedItemList.length > 0 &&newCheckedItemList.length < allRecords.length);setHeaderChecked(newCheckedItemList.length === allRecords.length);},[checkItem, uncheckItem, allRecords]);// 表头行checkbox的onChange事件let onBatchCheckBoxChange = useCallback(() => {if (!headerChecked) {checkItem(allRecords);} else {uncheckItem(null, true);}setPartialChecked(false);setHeaderChecked(!headerChecked);setOperateAll(true);}, [headerChecked, checkItem, uncheckItem, allRecords]);// 选中的记录,其Id组成的列表let checkedIdList = useMemo(() => {if (checkedItemList.length > 0) {return checkedItemList.map((item) => {return item.id;});}return [];}, [checkedItemList]);return [checkedIdList,partialChecked,operateAll,headerChecked,onSingleCheckBoxChange,onBatchCheckBoxChange];
};export { useBatchOperation };
这里代码量有110行,还是比较多的,我们拆开来讲一下逻辑。一共用了3种React Hook,分别是useState、useCallback和useMemo。其中useState4处,useCallback4处,useMemo1处。
4处useState
// 表示部分[1, n-1]行被勾选的状态,仅控制UIlet [partialChecked, setPartialChecked] = useState(false);// 表示是否所有的条目当前都被选中(即UI表现为表头的checkbox是否勾选)let [headerChecked, setHeaderChecked] = useState(false);// 表示当前用户是否主动点击了表头的那一个checkbox,点击后无论状态如何,其他checkbox都要跟随该状态,同headerChecked配合控制使用let [operateAll, setOperateAll] = useState(false);// 当前勾选的行所代表的数据单元组成的列表let [checkedItemList, setCheckedItemList] = useState([]);
- partialChecked: 标识
表头行Checkbox当前是否处于部分选中状态,仅用于控制UI样式,初始值为false - headerChecked: 标识
表头行Checkbox当前是否处于全部选中状态,即是否所有记录行Checkbox都为选中状态,初始值为false - operateAll: 标识当前用户是否主动点击了
表头行Checkbox,点击后所有记录行Checkbox必须跟随改变为同样的状态,初始值为false - checkedItemList: 当前勾选的记录行所代表的数据组成的列表,前文段落页面的文件App.js中
records数组的子集,初始值为空数组[]
4处useCallback
代码较长,不再复制徒增篇幅。
- checkItem: 勾选某行
记录行Checkbox后执行的事件方法。实际代码逻辑是给checkedItemList列表中新增一个记录数据,然后通过setCheckedItemList更新最新的checkedItemList,之所以使用useCallback封装一层,是为了其访问到的checkedItemList是当前最新的。 - uncheckItem: 和
checkItem作用相反,取消勾选某行记录行Checkbox后执行的事件方法。实际代码逻辑是在checkedItemList列表中找到并删除一个记录数据… - onSingleCheckBoxChange: 当
记录行Checkbox被点击而发生状态变化时执行的事件方法。代码逻辑包括:根据当前状态是选中还是未选中调用checkItem或uncheckItem更新checkedItemList,根据checkedItemList的length判断表头行Checkbox是否应该改为部分选中、全部选中或未选中状态等。 - onBatchCheckBoxChange : 当
表头行Checkbox被点击而发生状态变化时执行的事件方法。代码逻辑包括:根据当前状态是全部选中还是未选中调用checkItem或uncheckItem更新checkedItemList等。
1处useMemo
- checkedIdList: 根据
checkedItemList实时计算,表示当前被选中的记录的id组成的列表,暴露出去,向后台发请求时用。
App.js——部分改造
......
const MainPage = (props) => {......// 使用自定义hook-useBatchOperation,传入records列表let [checkedIdList,partialChecked,operateAll,headerChecked,onSingleCheckBoxChange,onBatchCheckBoxChange] = useBatchOperation(records);let recordRowViews = useMemo(() => {return records.map((item) => {return (<RecordRowkey={`record-${item.id}`}record={item}operateAll={operateAll}headerChecked={headerChecked}onSingleCheckBoxChange={onSingleCheckBoxChange}/>);});}, [records, operateAll, headerChecked, onSingleCheckBoxChange]);return (<div><HeaderRowpartialChecked={partialChecked}headerChecked={headerChecked}onBatchCheckBoxChange={onBatchCheckBoxChange}/>{recordRowViews}</div>);
};export default MainPage;
为了不占过多篇幅,用......代替未发生改变的部分。
主要修改3个部分:
- 创建一个自定义Hook-useBatchOperation的实例,获得暴露出来的6个变量。
RecrodRow传入operateAll、headerChecked和onSingleCheckBoxChangeHeaderRow传入partialChecked、headerChecked、onBatchCheckBoxChange
剩下暂时未用到的
checkedIdList留给后面的batch-operation-buttons.js
header-row.js——部分改造
......
const HeaderRow = (props) => {let { partialChecked, headerChecked, onBatchCheckBoxChange } = props;......<Checkboxindeterminate={partialChecked}checked={headerChecked}onChange={onBatchCheckBoxChange}/>......);
};export default HeaderRow;
主要修改2个部分:
- 引入父组件
App.js传入的partialChecked、headerChecked、onBatchCheckBoxChange - 将上述值和方法传入
Checkbox控件
record-row.js——部分改造
......
const RecordRow = (props) => {......let { record, operateAll, headerChecked, onSingleCheckBoxChange } = props;let [checked, setChecked] = useState(false);useEffect(() => {if (operateAll) {setChecked(headerChecked);}}, [operateAll, headerChecked, setChecked]);let wrappedOnChange = useCallback(() => {setChecked(!checked);onSingleCheckBoxChange(!checked, record);}, [checked, setChecked, record, onSingleCheckBoxChange]);return (......<Checkboxchecked={checked}onChange={wrappedOnChange}onClick={wrappedOnChange}/>......);
};export default RecordRow;
主要修改4个部分:
- 引入父组件
App.js传入的operateAll、headerChecked、onSingleCheckBoxChange - 添加一个
useEffectHook,如果表头行Checkbox被点击,跟随其改变状态 - 给
onSingleCheckBoxChange封装一层,被点击时不仅要更新自身状态,还要触发自定义Hook的数据更新 - 将上述值和方法传入
Checkbox控件
阶段效果
- 全选 / 取消全选

- 部分选中

四、 最后一步
经过前文中的努力,UI上表现达到预期了,所需的数据(checkedIdList)也拿到了,距离实现文章开头的效果还差右上角的操作按钮。这里我们新建一个batch-operation-buttons.js
import "./index.css";
import React, { useCallback } from "react";const BatchOperationButtons = (props) => {let { checkedIdList } = props;let handleClick = useCallback((func) => {switch (func) {case 0:alert(`批量删除记录,IdList:${JSON.stringify(checkedIdList)}`);break;case 1:alert(`批量下载记录,IdList:${JSON.stringify(checkedIdList)}`);break;default:throw new TypeError(`操作码[${func}]未实现!`);}},[checkedIdList]);if (checkedIdList?.length < 1) {return null;}return (<div className="batch-operation-buttons"><span className="delete-button" onClick={() => handleClick(0)}>删除</span><span>/</span><span className="download-button" onClick={() => handleClick(1)}>下载</span></div>);
};export default BatchOperationButtons;
注意: 这里的
alert是为了演示方便,现实情况下应该改为向后台发请求,按照checkedIdList和操作的func对选中的记录进行批量操作.
App.js中仅需改动以下代码即可
......return (<div><div className="buttons"><BatchOperationButtons checkedIdList={checkedIdList} /></div>......</div>);
后记
这次的实现中首次学习并使用了自定义Hook。实现之后发现了它的重要意义,即我们可以通过自定义Hook真正地将HTML模板和JS数据逻辑拆分为两个独立的文件,一个只管模板内容,一个只管数据的更新。官方一点的说法即:实现了Model(custom-hooks.js)和View(App.js)的分离,意义重大。
为了便于理解,你可以想象,在学会使用自定义Hook之前,App.js和custom-hooks.js里的代码统统写在App.js里,这样一个控件里的代码量将非常大,维护起来比较麻烦。拆分为两个文件后,模板有Bug我们就只改View文件,数据有Bug我们就只改Model文件。
相关文章:
React学习笔记(番外二)——列表多选批量处理复合组件
React学习笔记(番外二)——列表多选批量操作复合组件前言〇、Show you the code一、 任务分析及拆解表头行的Checkbox——总开关记录行的Checkbox——行级开关二、 基础实现表头行的文件——header-row.js记录行的文件——record-row.js页面的文件App.js…...
Pom.xml详解
目录 1、Maven的下载安装 2、什么是pom? 3、较完整的pom元素 4、默认生成Maven工程的pom内容 5、自定义的属性变量 6、依赖管理 6.1、整体依赖关系列表 6.2、依赖关系的传递性 6.3、依赖传递可能造成的问题 6.3.1、scope依赖范围 6.3.2、依赖调节 6.3.3…...
浅谈软件测试需求管理
什么是需求管理? 需求管理,指对产品、系统或工程的开发需求的搜集、定义、分析、评审、整理、维护、追溯和复用等相关的管理工作和流程。通常特指应用程序或软件系统的研发需求。需求管理和配置管理、测试管理、缺陷管理、风险管理、变更管理等管理流程…...
面试题复盘
Vuex与本地存储的区别Vuex是一个专门为Vue.js应用程序开发的状态管理模式和库。它提供了一个中央存储库,用于存储应用程序的所有组件之间共享的状态【组件间通信的一种方法,一般用于中大型应用】。Vuex的主要目的是在Vue.js应用程序中管理复杂的状态逻辑…...
Telerik UI for WPF 2023 R1
Telerik UI for WPF 2023 R1 之 WPF 的 Telerik 用户界面,WPF 控件库开发人员信任,快速构建美观、高性能的 WPF 业务应用程序。现在支持 .NET 6 和 7.0。 概述部分背景图像 主要特征 现代专业主题图标,现代专业主题 通过各种受 Office、Wind…...
基于 CentOS7 的 KVM 部署 + 虚拟机创建
目录一、实验环境二、部署 KVM三、创建虚拟机四、远程管理 KVM 虚拟机FAQ一、实验环境 实验环境:VMware Workstation 16 Pro 打开虚拟机之前,首先开启 VMware Workstation Pro 16 上的硬件辅助虚拟化功能,如下图所示: 二、部署 …...
Python自动化测试实战篇(5)优化selenium+unittest+ddt,搞定100条测试用例只执行前50条
这些是之前的文章,里面有一些基础的知识点在前面由于前面已经有写过,所以这一篇就不再详细对之前的内容进行描述 Python自动化测试实战篇(1)读取xlsx中账户密码,unittest框架实现通过requests接口post登录网站请求&…...
C语言--数据的存储2
目录前言练习有符号类型与无符号类型char类型的取值范围有符号char无符号char有符号与无符号类型混合运算有符号无符号类型形成的bugchar类型取值范围应用浮点型在内存中的存储浮点数的存储浮点数存储规则浮点数取出规则前言 上篇文章我们讲解了数据类型,类型的基本…...
Ubuntu 安装 Qt5.7.0
下载 地址:https://download.qt.io/https://download.qt.io/ 文件夹说明: snapshots:预览版,该文件夹中包含最新的测试版本。 online:在线安装包。 official_releases:最终发布版。 new_archive&#…...
“世界”的伊利,“三难”的潘刚
(图片来源于网络,侵删) 来源 | 螳螂观察 文 | 叶小安 一棵草,一头牛,到一杯牛奶,乳品如何守住舌尖上的安全? 央视财经频道专访中,伊利集团董事长兼总裁潘自信满满地介绍了现代智…...
【新】华为OD机试 - 开心消消乐(Python)
开心消消乐 题目 给定一个 N 行 M 列的二维矩阵,矩阵中每个位置的数字取值为 0 或 1,矩阵示例如: 1 1 0 0 0 0 0 1 0 0 1 1 1 1 1 1现需要将矩阵中所有的 1 进行反转为 0,规则如下: 当点击一个 1 时,该 1 被反转为 0,同时相邻的上、下、左、右,以及左上、左下、右上…...
山东大学2022-2023数据仓库挖掘期末考题回忆
2023.2.14 一、 1.数据预处理的过程和解决问题 2.什么是离群点,检测离群点的四个方法 3.数据仓库的四个特点,画出数据仓库结构图 4.维度归约的两个方法及区别。 二、 两个模型用来预测新冠病毒的阳性和阴性 1.分别求准确率,精确率,…...
SSM整合
SSM整合 ContextLoaderListener Spring提供了监听器ContextLoaderListener,实现ServletContextListener接口,可监听 ServletContext的状态,在web服务器的启动,读取Spring的配置文件,创建Spring的IOC容器。 web 应用中…...
Android平台版本所对应的 API 级别
平台版本API级别版本号备注Android 1333TIRAMISU平台亮点Android 1232S_V2平台亮点31S平台亮点Android 1130R平台亮点Android 1029Q平台亮点Android 928P平台亮点Android 8.127O_MR1平台亮点Android 8.026O平台亮点Android 7.1.1Android 7.125N_MR1平台亮点Android 7.024N平台亮…...
入职字节外包一个月,我离职了
有一种打工人的羡慕,叫做“大厂”。 真是年少不知大厂香,错把青春插稻秧。 但是,在深圳有一群比大厂员工更庞大的群体,他们顶着大厂的“名”,做着大厂的工作,还可以享受大厂的伙食,却没有大厂…...
中创教育PMP分享,复盘没效果?该怎么办
复盘的清单框架 一、现在情况如何 二、当初是怎么决定的 三、让我们再审视下思考的前提 四、复盘他人 复盘没效果,我们可以试试下面的提问: 一、现在情况如何 现在做到什么程度? 当时定的目标是多少? 现在的结果和目标对比处于什么状态? 有没…...
Kubelet监控指标说明
Probe路径 含义:kubelet以及kubelet监控的Pod的存活性请求路径:“/metrics/probes”指标 名称类型含义upGauge服务是否存活prober_probe_totalCounter按结果计算容器的活动探测、就绪探测或启动探测的累计数目以及存活性结果 Metrics路径 含义&#x…...
python中的数据类型(价值6980的全能工程师课程笔记)
概述 python数据类型主要分为以下七大类: Numbers(数字) Boolean(布尔) String(字符串) List(列表) Tuple(元组) Dictionary(字典) Set(集合) Python 的七个标准数据类型中: 不可变数据类型(4 个):Number(数字)、Boolean(布尔)、String(字符串)、T…...
Tomcat 配置IPV6
文章目录一、场景二、tomcat开启ipv6三、ipv6环境配置四、访问总结一、场景 我们在linux下安装一个tomcat,启用ipv6的方式,然后在windows下用浏览器访问这个tomcat 二、tomcat开启ipv6 在server.xml配置文件的里面加上 address”[::]” ,这…...
JavaEE——MyBatis的简单介绍和使用
MyBatis是什么 MyBatis是一个支持普通SQL查询,存储过程以及高级映射的持久层框架,他消除了几乎所有的JDBC代码和参数的手动设置以及对结果集的检索,使用简单的XML或注解进行配置和原始映射,将接口和Java的POJO映射成数据库中的记…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...
微信小程序之bind和catch
这两个呢,都是绑定事件用的,具体使用有些小区别。 官方文档: 事件冒泡处理不同 bind:绑定的事件会向上冒泡,即触发当前组件的事件后,还会继续触发父组件的相同事件。例如,有一个子视图绑定了b…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
什么是Ansible Jinja2
理解 Ansible Jinja2 模板 Ansible 是一款功能强大的开源自动化工具,可让您无缝地管理和配置系统。Ansible 的一大亮点是它使用 Jinja2 模板,允许您根据变量数据动态生成文件、配置设置和脚本。本文将向您介绍 Ansible 中的 Jinja2 模板,并通…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
