设计模式 - Provider 模式
在某些情况下,我们希望为应用程序中的许多(如果不是全部)组件提供数据。尽管我们可以使用 props
将数据传递给组件,但如果应用程序中的几乎所有组件都需要访问 prop 的值,这可能很难做到。
我们经常遇到所谓的属性钻探(prop drilling)问题,这在我们将属性向下传递至组件树的深层时就会出现。重构依赖属性的代码几乎不可能,也很难知道某些数据来自哪里。
假设我们有一个包含某些数据的 App
组件。在组件树的下方,我们有一个 ListItem
、Header
和 Text
组件,它们都需要这些数据。为了将这些数据传递到这些组件,我们必须将其传递到多个组件层。
在我们的代码库中,这将如下所示:
function App() {const data = { ... }return (<div><SideBar data={data} /><Content data={data} /></div>)
}const SideBar = ({ data }) => <List data={data} />
const List = ({ data }) => <ListItem data={data} />
const ListItem = ({ data }) => <span>{data.listItem}</span>const Content = ({ data }) => (<div><Header data={data} /><Block data={data} /></div>
)
const Header = ({ data }) => <div>{data.title}</div>
const Block = ({ data }) => <Text data={data} />
const Text = ({ data }) => <h1>{data.text}</h1>
以这种方式传递 props 会变得非常混乱。如果我们将来想重命名data
属性,我们必须在所有组件中重命名它。您的应用程序越大,支柱钻孔就越棘手。
如果我们可以跳过不需要使用此数据的所有组件层,那将是最佳的。我们需要有一些东西,让需要访问 data
价值的组件直接访问它,而不依赖于 props 钻孔。
这就是 Provider
模式 可以帮助我们的地方!借助 Provider
模式,我们可以将数据提供给多个组件。我们可以将所有组件包装在一个 Provider
中,而不是通过 prop 将数据传递到每一层。Provider 是 Context
对象提供给我们的高阶组件。我们可以创建一个 Context 对象,使用 React 为我们提供的 createContext
方法。
Provider 收到一个 value
属性,其中包含我们想要传递的数据。包装在此 Provider 中的所有组件都可以访问 value
属性的值。
const DataContext = React.createContext()function App() {const data = { ... }return (<div><DataContext.Provider value={data}><SideBar /><Content /></DataContext.Provider></div>)
}
我们不再需要手动将 data props
传递给每个组件!那么,ListItem
、Header
和 Text
组件如何访问data
的值呢?
每个组件都可以使用 useContext
钩子访问data
。此钩子接收 data
具有引用的上下文,在本例中为 DataContext
。useContext
钩子允许我们在上下文对象中读取和写入数据。
const DataContext = React.createContext();function App() {const data = { ... }return (<div><DataContext.Provider value={data}><SideBar /><Content /></DataContext.Provider></div>)}const SideBar = () => <List />
const List = () => <ListItem />
const Content = () => <div><Header /><Block /></div>function ListItem() {const { data } = React.useContext(DataContext);return <span>{data.listItem}</span>;
}function Text() {const { data } = React.useContext(DataContext);return <h1>{data.text}</h1>;
}function Header() {const { data } = React.useContext(DataContext);return <div>{data.title}</div>;
}
不使用data
值的组件根本不需要处理data
。我们再也不用担心通过不需要 prop 值的组件将 prop 向下传递几个级别,这使得重构变得容易得多。
Provider 模式对于共享全局数据非常有用。Provider 模式的一个常见用例是与许多组件共享主题 UI 状态。
假设我们有一个显示列表的简单应用程序。
// index.js
import React from "react";
import ReactDOM from "react-dom";import App from "./App";const rootElement = document.getElementById("root");
ReactDOM.render(<React.StrictMode><App /></React.StrictMode>,rootElement
);// App.js
import React from "react";
import "./styles.css";import List from "./List";
import Toggle from "./Toggle";export default function App() {return (<div className="App"><Toggle /><List /></div>);
}// List.js
import React from "react";
import ListItem from "./ListItem";export default function Boxes() {return (<ul className="list">{new Array(10).fill(0).map((x, i) => (<ListItem key={i} />))}</ul>);
}// Toggle.js
import React from "react";export default function Toggle() {return (<label className="switch"><input type="checkbox" /><span className="slider round" /></label>);
}// ListItem.js
import React from "react";export default function ListItem() {return (<li>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmodtempor incididunt ut labore et dolore magna aliqua. Ut enim ad minimveniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex eacommodo consequat.</li>);
}
我们希望用户能够通过切换开关在浅色模式和深色模式之间切换。当用户从深色模式切换到浅色模式时,反之亦然,背景颜色和文本颜色应该会发生变化!我们可以将组件包装在 ThemeProvider
中,并将当前主题颜色传递给 Provider,而不是将当前主题值向下传递给每个组件。
export const ThemeContext = React.createContext();const themes = {light: {background: "#fff",color: "#000",},dark: {background: "#171717",color: "#fff",},
};export default function App() {const [theme, setTheme] = useState("dark");function toggleTheme() {setTheme(theme === "light" ? "dark" : "light");}const providerValue = {theme: themes[theme],toggleTheme,};return (<div className={`App theme-${theme}`}><ThemeContext.Provider value={providerValue}><Toggle /><List /></ThemeContext.Provider></div>);
}
由于 Toggle
和 List
组件都包装在 ThemeContext
Provider 中,因此我们可以访问作为value
传递给 Provider 的值 theme
和 toggleTheme
。
在 Toggle
组件中,我们可以使用 toggleTheme
函数相应地更新主题。
import React, { useContext } from "react";
import { ThemeContext } from "./App";export default function Toggle() {const theme = useContext(ThemeContext);return (<label className="switch"><input type="checkbox" onClick={theme.toggleTheme} /><span className="slider round" /></label>);
}
List
组件本身并不关心主题的当前值。但是,ListItem
组件可以!我们可以直接在 ListItem
中使用 theme
上下文。
import React, { useContext } from "react";
import { ThemeContext } from "./App";export default function TextBox() {const theme = useContext(ThemeContext);return <li style={theme.theme}>...</li>;
}
我们不必将任何数据传递给不关心主题当前值的组件。
// App.js
import React, { useState } from "react";
import "./styles.css";import List from "./List";
import Toggle from "./Toggle";export const themes = {light: {background: "#fff",color: "#000"},dark: {background: "#171717",color: "#fff"}
};export const ThemeContext = React.createContext();export default function App() {const [theme, setTheme] = useState("dark");function toggleTheme() {setTheme(theme === "light" ? "dark" : "light");}return (<div className={`App theme-${theme}`}><ThemeContext.Provider value={{ theme: themes[theme], toggleTheme }}><><Toggle /><List /></></ThemeContext.Provider></div>);
}// Toggle.js
import React, { useContext } from "react";
import { ThemeContext } from "./App";export default function Toggle() {const theme = useContext(ThemeContext);return (<label className="switch"><input type="checkbox" onClick={theme.toggleTheme} /><span className="slider round" /></label>);
}
Hooks
我们可以创建一个钩子来为组件提供上下文。我们不必在每个组件中导入 useContext
和 Context,而是可以使用一个钩子来返回我们需要的上下文。
function useThemeContext() {const theme = useContext(ThemeContext);return theme;
}
为了确保它是一个有效的主题,如果 useContext(ThemeContext)
返回一个虚假值,让我们抛出一个错误。
function useThemeContext() {const theme = useContext(ThemeContext);if (!theme) {throw new Error("useThemeContext must be used within ThemeProvider");}return theme;
}
我们可以创建一个 HOC,包装组件以提供其值,而不是直接使用 ThemeContext.Provider
组件包装组件。这样,我们可以将上下文逻辑与渲染组件分开,从而提高 Provider 的可重用性。
function ThemeProvider({ children }) {const [theme, setTheme] = useState("dark");function toggleTheme() {setTheme(theme === "light" ? "dark" : "light");}const providerValue = {theme: themes[theme],toggleTheme,};return (<ThemeContext.Provider value={providerValue}>{children}</ThemeContext.Provider>);
}export default function App() {return (<div className={`App theme-${theme}`}><ThemeProvider><Toggle /><List /></ThemeProvider></div>);
}
现在,每个需要访问 ThemeContext
的组件都可以简单地使用 useThemeContext
钩子。
通过为不同的上下文创建挂钩,可以很容易地将 Provider 的逻辑与呈现数据的组件分开。
个案研究
有些库提供内置的提供者,我们可以在消费组件中使用这些值。styled-components就是一个很好的例子。
了解此示例并不需要具备styled-components的使用经验。
styled-components 库为我们提供了一个 ThemeProvider
。每个样式化的组件都可以访问此Provider 的价值!我们可以使用提供给我们的 API,而不是自己创建上下文 API!
让我们使用相同的 List 示例,并将组件包装在从styled-component
库导入的 ThemeProvider
中。
import { ThemeProvider } from "styled-components";export default function App() {const [theme, setTheme] = useState("dark");function toggleTheme() {setTheme(theme === "light" ? "dark" : "light");}return (<div className={`App theme-${theme}`}><ThemeProvider theme={themes[theme]}><Toggle toggleTheme={toggleTheme} /><List /></ThemeProvider></div>);
}
我们不会将内联style
prop 传递给 ListItem
组件,而是将其设置为 styled.li
组件。由于它是一个样式化的组件,我们可以访问theme
的价值!
import styled from "styled-components";export default function ListItem() {return (<Li>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmodtempor incididunt ut labore et dolore magna aliqua. Ut enim ad minimveniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex eacommodo consequat.</Li>);
}const Li = styled.li`${({ theme }) => `background-color: ${theme.backgroundColor};color: ${theme.color};`}
`;
我们现在可以使用 ThemeProvider
轻松地将样式应用于所有样式组件!
import React, { useState } from "react";
import { ThemeProvider } from "styled-components";
import "./styles.css";import List from "./List";
import Toggle from "./Toggle";export const themes = {light: {background: "#fff",color: "#000"},dark: {background: "#171717",color: "#fff"}
};export default function App() {const [theme, setTheme] = useState("dark");function toggleTheme() {setTheme(theme === "light" ? "dark" : "light");}return (<div className={`App theme-${theme}`}><ThemeProvider theme={themes[theme]}><><Toggle toggleTheme={toggleTheme} /><List /></></ThemeProvider></div>);
}// ListItem.js
import React from "react";
import styled from "styled-components";export default function ListItem() {return (<Li>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmodtempor incididunt ut labore et dolore magna aliqua. Ut enim ad minimveniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex eacommodo consequat.</Li>);
}const Li = styled.li`${({ theme }) => `background-color: ${theme.backgroundColor};color: ${theme.color};`}
`;
权衡
优点
Provider 模式/上下文 API 可以将数据传递到许多组件,而无需手动将数据传递到每个组件层。
它降低了在重构代码时意外引入错误的风险。以前,如果我们以后想要重命名一个 prop,我们必须在使用此值的整个应用程序中重命名此 prop。
我们不再需要处理 prop 向下传递,这可以被视为一种反模式。以前,理解应用程序的数据流可能很困难,因为并不总是清楚某些 prop 值的来源。使用 Provider 模式,我们不再需要将不必要的 prop 传递给不关心这些数据的组件。
使用 Provider 模式可以轻松保持某种全局状态,因为我们可以为组件提供对此全局状态的访问权限。
缺点
在某些情况下,过度使用 Provider 模式可能会导致性能问题。使用上下文的所有组件都会在每次状态更改时重新呈现。
让我们看一个例子。我们有一个简单的计数器,每次单击 Button
组件中的 Increment
按钮时,该计数器的值都会增加。我们在 Reset
组件中还有一个 Reset
按钮,它将计数重置回 0
。
但是,当您单击Increment
”时,您可以看到重新渲染的不仅仅是计数。Reset
组件中的日期也会重新渲染!
import React, { useState, createContext, useContext, useEffect } from "react";
import ReactDOM from "react-dom";
import moment from "moment";import "./styles.css";const CountContext = createContext(null);function Reset() {const { setCount } = useCountContext();return (<div className="app-col"><button onClick={() => setCount(0)}>Reset count</button><div>Last reset: {moment().format("h:mm:ss a")}</div></div>);
}function Button() {const { count, setCount } = useCountContext();return (<div className="app-col"><button onClick={() => setCount(count + 1)}>Increment</button><div>Current count: {count}</div></div>);
}function useCountContext() {const context = useContext(CountContext);if (!context)throw new Error("useCountContext has to be used within CountContextProvider");return context;
}function CountContextProvider({ children }) {const [count, setCount] = useState(0);return (<CountContext.Provider value={{ count, setCount }}>{children}</CountContext.Provider>);
}function App() {return (<div className="App"><CountContextProvider><Button /><Reset /></CountContextProvider></div>);
}ReactDOM.render(<App />, document.getElementById("root"));
Reset
组件也重新呈现,因为它使用了 useCountContext
。在较小的应用程序中,这并不重要。在较大的应用程序中,将经常更新的值传递给许多组件可能会对性能产生负面影响。
若要确保组件不会使用包含可能更新的不必要值的 Provider,您可以为每个单独的用例创建多个 Provider。
相关文章:
设计模式 - Provider 模式
在某些情况下,我们希望为应用程序中的许多(如果不是全部)组件提供数据。尽管我们可以使用 props 将数据传递给组件,但如果应用程序中的几乎所有组件都需要访问 prop 的值,这可能很难做到。 我们经常遇到所谓的属性钻探…...
R语言颜色细分
1.如何对R语言中两种颜色之间进行细分 2.代码: x <- colorRampPalette(c("#FC8D62","#FDEAE6"))(12) #打印向量值 # 按字典顺序排序颜色值 x_sorted <- sort(x,decreasing TRUE)# 打印排序后的颜色值 print(x_sorted)#展示颜色 scales:…...
面向返回编程ROP问题及挑战
像我们描述的执行权限等功能已经使执行任意代码变得越来越困难。这意味着攻击者使用其他方法,比如面向返回编程(ROP)。ROP利用了许多现代系统中软件堆栈的规模。攻击者分析系统中的软件,寻找小工具(gadgets)…...
vscode shadertoy插件,非常方便的glsl着色器编写工具
很著名的shadertoy网站,集合了非常多大神利用数学写出美妙的shader效果。像shadertoy创始人之一的IQ大神它在这方面有很多的建树。他的利用光线步进和躁声可以创建很多不可思议的3D场景。 vscode有一件shadertoy的插件,安装后可以新建一个*.glsl文件&am…...
网络请求避坑,私有网络请求(Private Network Access)
前言 网络请求,大家肯定熟悉的不能再熟悉,网络请求失败,大家也肯定很熟悉。排查网络请求,也是我们必备的技能,对不,兄弟。 我坦言,最怕两种网络请求失败。 第一种:PC端模拟没有异常…...
AVL树和红黑树
AVL树和红黑树 AVL树理论代码实现 红黑树理论代码实现 AVL树 理论 我们知道二叉搜索树拥有极高的搜索效率,但当二叉搜索树退化成单支时,其查找效率会大幅下降,因此我们需要避免其出现单支的情况,并且尽可能让其接近满二叉树。解…...
多线程入门
多线程 Thread 现在的Thread中的run方法,已经被实现了,所以已经不需要实现了 操作 继承 extends Thread方法 重写run方法 start() 案例 public class ThreadTest extends Thread{public void run() {for (int i 0; i < 100; i) {System.out.…...
#!/bin/sh和#!/bin/bash的区别
前言:都是脚本文件中的 shebang(也称为 hashbang)行,用于指定脚本文件的解释器 解释: #!/bin/sh:这行告诉操作系统使用 /bin/sh 这个解释器来执行脚本。/bin/sh 是一个标准的 Unix Shell,通常是…...
腾讯云(CVM)托管进行权限维持
前言 刚好看到一个师傅分享了一个阿里云ECS实战攻防,然后想到了同样利用腾讯云CVM的托管亦可实现在实战攻防中的权限维持。 简介 腾讯云自动化助手(TencentCloud Automation Tools,TAT)是一个原生运维部署工具,它可…...
STM32-03基于HAL库(CubeMX+MDK+Proteus)输入检测案例(按键控制LED)
文章目录 一、功能需求分析二、Proteus绘制电路原理图三、STMCubeMX 配置引脚及模式,生成代码四、MDK打开生成项目,编写HAL库的按键检测代码五、运行仿真程序,调试代码 一、功能需求分析 搭建完成开发STM32开发环境之后,开始GPIO…...
DS3231SN
这份文件是关于DS3231SN芯片的数据手册,由Maxim Integrated公司生产。DS3231SN是一款高精度的I2C接口集成实时时钟(RTC)/温度补偿晶体振荡器(TCXO)/晶体的芯片。以下是该芯片的核心内容概述: 产品概述&…...
tsconfig.json文件翻译
原文件 {"compilerOptions": {/* Visit https://aka.ms/tsconfig to read more about this file *//* Projects */// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects.…...
树状数组学习笔记
树状数组 拜读了大佬的讲解博文(树状数组(详细分析应用),看不懂打死我!),写一篇Python版的笔记巩固消化,附带蓝桥杯历年真题作为例题演示 一、作用 用于快速读取列表中 某个区间内所有元素的和 实现单点修改ÿ…...
【bugfix】如何解决svg到线上显示空白或者svg的viewBox为空
svgo的默认机制是当width和height和viewbox一样会删除viewbox,这都是为了svg的压缩做的,详情可以看issue中的讨论,我们可以通过更改babel的配置来解决 https://github.com/svg/svgo/issues/1128 https://github.com/ant-design/ant-design-we…...
docker基础学习指令
文章目录 [toc] docker基础常用指令一、docker 基础命令二、docker 镜像命令1. docker images2. docker search3. docker pull4. docker system df5. docker rmi1. Commit 命令 三、 docker 容器命令1. docker run2. docker logs3. docker top4. docker inspect5. docker cp6. …...
回溯大学生活
回顾一下大学四年 bg:湖南大学 20级计科,成绩60%,无考研考公打算 四年之前,怀着激动的心情来到了大学校园,经过了太久的压抑终于迎来了高中老师口中的美好的大学生活,然而呢事实并非如此。恋爱呢…...
Android Fence机制
Android Fence机制 Android中的GraphicBuffer同步机制-Fence (最全最详细,推荐) AndroidQ 图形系统(5)Fence机制简介 Android P 图形显示系统(十一) BufferQueue(二)...
sa-token非Web上下文无法获取Request
0x02 非Web上下文无法获取Request 问题定位 在我们使用sa-token安全框架的时候,有时候会提示:**SaTokenException:非Web上下文无法获取Request**** 错误截图: 在官方网站中,查看常见问题排查: 非Web上下文无法获取…...
tomcat 常见优化方案
tomcat作为Web服务器,它的处理性能直接关系到用户体验,下面是几种常见的优化措施: 对web.xml的监视,把jsp提前编辑成Servlet。有富余物理内存的情况,加大tomcat使用的jvm的内存 服务器所能提供CPU、内存、硬盘的性能…...
前端导出文本内容为csv文件,excel乱码
原因:编码格式问题,需要改为utf-8 bom // Create blob with utf8-bom 编码 const createBlobWithBOM(data, mimeType)> {const bom [0xEF, 0xBB, 0xBF];const bomArray new Uint8Array(bom);const dataArray new TextEncoder().encode(data);const…...
36---USB HUB电路设计
视频链接 USB HUB电路设计01_哔哩哔哩_bilibili USB HUB 电路设计 1、USB HUB基本介绍 USB Hub,指的是一种可以将一个USB接口扩展为多个,并可以使这些接口同时使用的装置。 Hub也是大家常说的集线器,它使用星型拓扑结构连接多个USB接口设…...
FPGA在深度学习领域的应用的优势
FPGA(Field-Programmable Gate Array)是一种可编程逻辑芯片,可以根据需要重新配置其内部的逻辑电路和功能。在深度学习领域,FPGA被广泛用于加速模型训练和推理任务。 首先,FPGA可以提供高度定制化的计算架构ÿ…...
Windows Edge 兼容性问题修复 基本解决方案
Windows Edge 浏览器兼容性问题可能源于多个方面,以下是一些常见的问题及其处理结果: 插件或扩展冲突:某些第三方插件或扩展可能与Edge浏览器不兼容,导致崩溃或运行异常。处理结果为,尝试禁用所有插件和扩展ÿ…...
【Servlet】服务器内部转发以及客户端重定向
文章目录 一、服务器内部转发:request.getRequestDispatcher("...").forward(request, response);二、客户端重定向:response.sendRedirect("");三、服务器内部转发代码示例四、客户端重定向代码示例 一、服务器内部转发:…...
是否有替代U盘,可安全交换的医院文件摆渡方案?
医院内部网络存储着大量的敏感医疗数据,包括患者的个人信息、病历记录、诊断结果等。网络隔离可以有效防止未经授权的访问和数据泄露,确保这些敏感信息的安全。随着法律法规的不断完善,如《网络安全法》、《个人信息保护法》等,医…...
Java设计模式详解:单例模式
设计模式详解:单例模式 文章目录 设计模式详解:单例模式一、单例模式的原理二、单例模式的实现推荐1、饿汉模式2、静态内部类 三、单例模式的案例四、单例模式的使用场景推荐总结 一、单例模式的原理 单例模式听起来很高大上,但其实它的核心…...
Pointnet++改进即插即用系列:全网首发OREPA在线重新参数化卷积,替代普通卷积 |即插即用,提升特征提取模块性能
简介:1.该教程提供大量的首发改进的方式,降低上手难度,多种结构改进,助力寻找创新点!2.本篇文章对Pointnet++特征提取模块进行改进,加入OREPA,提升性能。3.专栏持续更新,紧随最新的研究内容。 目录 1.理论介绍 2.修改步骤 2.1 步骤一 2.2 步骤二 2.3 步骤三...
XRDP登录ubuntu桌面闪退问题
修改 /etc/xrdp/startwm.sh unset DBUS_SESSION_BUS_ADDRESS unset XDG_RUNTIME_DIR . $HOME/.profile...
【Node】使用Node.js构建简单的静态页面生成器
使用Node.js构建简单的静态页面生成器 在现代的Web开发中,静态网站因其速度快、安全性高而越来越受到开发者的青睐。本文将介绍如何使用Node.js构建一个简单的静态页面生成器,通过这个小项目,你将了解到静态网站生成的基本原理和实现方法。 …...
AI智能客服机器人是什么?对企业重要吗?
在数字化时代,客户服务是企业与客户建立牢不可破关系的重要桥梁。AI智能客服机器人,顾名思义,就是利用人工智能技术提升客户服务体验的自动化工具。今天,就让我们来揭开AI智能客服机器人的神秘面纱,并讨论它对企业的重…...
编辑网站/搜狗站长工具平台
一般写法: package strategy_mode;/*** 实现起来比较容易,符合一般开发人员的思路* 假如,类型特别多,算法比较复杂时,整个条件语句的代码就变得很长,难于维护.* 如果有新增类型,就需要频繁的修改此处的代码!* 不符合开闭原则!*/ public class TestStrategy {/*** 根据类型,打折…...
网站建设问题大全/平原县网站seo优化排名
今天给大家分享一个最新开发的Vue3自定义模拟滚动条组件v3scroll。V3Scroll 基于vue3.0开发的轻量级PC端虚拟滚动条组件。支持是否自动隐藏、自定义大小、颜色及层叠等功能。开发灵感来自于之前的vue2版自定义滚动条组件。借鉴了ElementPlus滚动条设计。vue2.x自定义桌面端滚动…...
商城网站建设是什么/东莞做网站的联系电话
1.状态栏状态栏一般高度为20像素,在打手机或者显示消息时会放大到40像素高,注意,两倍高度的状态栏在好像只能在纵向的模式下使用。如下图用户可以隐藏状态栏,也可以将状态栏设置为灰色,黑色或者半透明的黑色。如果需要…...
手机做网站多少钱/国外免费网站服务器
作者:Derek 简介 Github地址:https://github.com/Bytom/bytom Gitee地址:https://gitee.com/BytomBlockc... 本章介绍Derek解读-Bytom源码分析-创世区块 作者使用MacOS操作系统,其他平台也大同小异Golang Version: 1.8 创世区块介…...
深圳服务网站设计哪家公司好/推广平台哪个效果最好
题库来源:安全生产模拟考试一点通公众号小程序 2022化工自动化控制仪表题库系化工自动化控制仪表试卷新版教材大纲题库!2022年化工自动化控制仪表复训题库及在线模拟考试根据化工自动化控制仪表考试大纲。化工自动化控制仪表考试模拟题通过安全生产模拟…...
做购物网站平台/深圳知名网络优化公司
存在即是合理的。 表格的现在还是较为常用的一种标签,但不是用来布局,常见处理、显示表格式数据。创建表格在HTML网页中,要想创建表格,就需要使用表格相关的标签。创建表格的基本语法格式如下:单元格内的文字......在上…...