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映射成数据库中的记…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
让AI看见世界:MCP协议与服务器的工作原理
让AI看见世界:MCP协议与服务器的工作原理 MCP(Model Context Protocol)是一种创新的通信协议,旨在让大型语言模型能够安全、高效地与外部资源进行交互。在AI技术快速发展的今天,MCP正成为连接AI与现实世界的重要桥梁。…...
成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战
在现代战争中,电磁频谱已成为继陆、海、空、天之后的 “第五维战场”,雷达作为电磁频谱领域的关键装备,其干扰与抗干扰能力的较量,直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器,凭借数字射…...
用docker来安装部署freeswitch记录
今天刚才测试一个callcenter的项目,所以尝试安装freeswitch 1、使用轩辕镜像 - 中国开发者首选的专业 Docker 镜像加速服务平台 编辑下面/etc/docker/daemon.json文件为 {"registry-mirrors": ["https://docker.xuanyuan.me"] }同时可以进入轩…...
华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码
目录 一、👨🎓网站题目 二、✍️网站描述 三、📚网站介绍 四、🌐网站效果 五、🪓 代码实现 🧱HTML 六、🥇 如何让学习不再盲目 七、🎁更多干货 一、👨…...
