- 当前几种图标使用方式
:图像嵌入元素
用法
html
<img src={'/com/huawei/static/images/grapefruit-slice-332-332.jpg'} className="App-logo" alt="logo" />
// 或
import logo from '/com/huawei/static/images/logo.svg';
<img src={logo} className="App-logo" alt="logo" />
// 支持响应式图片
<picture>
<source media="(max-width: 799px)" srcset="elva-480w-close-portrait.jpg" />
<source media="(min-width: 800px)" srcset="elva-800w.jpg" />
<img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva" />
</picture>
-
学习成本:简单的标签即可。
-
支持图像格式:APNG(动态可移植网络图形)------无损动画序列的不错选择(GIF 性能较差)。AVIF(AV1 图像文件格式)------静态图像或动画的不错选择,其性能较好。GIF(图像互换格式)------简单图像和动画的不错选择。JPEG(联合图像专家组)------有损压缩静态图像的不错选择(目前最流行的格式)。PNG(便携式网络图形)------对于无损压缩静态图像而言是不错的选择(质量略好于 JPEG)。SVG(可缩放矢量图形)------矢量图像格式。用于必须以不同尺寸准确描绘的图像。WebP(网络图片格式)------图像和动画的绝佳选择。Base64。
-
是否矢量图: 不是,除非源文件本身就是SVG。
-
如何修改图标样式:width和height,或者通过css修改宽高。
-
体积大小:
-
性能: 大量图标可以使用精灵图减少http请求;支持Base64。
-
懒加载:
html
<img src={logo} className={"App-logo"} alt={"logo"} loading={'lazy'} />
jsx
import React, { useRef, useEffect, useState } from 'react';
const LazyLoadImage = ({ src, alt }) => {
const [imageSrc, setImageSrc] = useState('');
const imgRef = useRef(null);
useEffect(() => {
let observer;
if (imgRef.current) {
observer = new IntersectionObserver(
([entry]) => {
// 当图片进入可视区域时,设置图片地址进行加载
if (entry.isIntersecting) {
setImageSrc(src);
observer.unobserve(imgRef.current);
}
},
{
rootMargin: '0px 0px 200px 0px', // 可视区域的边距设置为200px
}
);
observer.observe(imgRef.current);
}
return () => {
if (observer && observer.unobserve) {
observer.unobserve(imgRef.current);
}
};
}, [src]);
return <img ref={imgRef} src={imageSrc} alt={alt} />;
};
export default LazyLoadImage;
- 缓存: 可以被浏览器缓存。
- 加载失败处理:
- 适用场景: 适合于单个较大的图像或非矢量图标。
CSS背景图像 用法: 通过CSS background-image属性设置背景图像。
css
background:<attachment> <bg-image> <position> <bg-size> <repeat-style>
学习成本:只需要了解css的background属性 支持图片格式:同img。 是否矢量图: 不是,除非源文件本身就是SVG。 体积大小: 性能: 支持Base64。 缓存: 可以被浏览器缓存。 加载失败处理: 适用场景: 适合于不需要频繁更新背景图的情况。
Base64编码 Base64 是一组相似的二进制到文本(binary-to-text)的编码规则,让二进制数据在解释成 64 进制的表现形式后能够用 ASCII 字符串的格式表示出来。
用法: 直接在CSS或HTML中嵌入Base64编码的字符串。
jsx
<img src={"data:image/jpeg;base64,/9j/..."} alt={"Example Image"}>
学习成本: 低,只需知道如何使用Base64编码。 是否矢量图: 取决于源文件类型。 体积大小: 比原始文件大33%,但可以避免额外HTTP请求。 性能: 对于小图标较好,对于大图标可能增加页面加载时间。 缓存: 无法缓存,因为是内联数据;如果 base64 是被编码到 css/js 中,是可以缓存的,因为 css/js 文件可以缓存。 适用场景: 适合于小图标,可以减少HTTP请求次数。
HTML5 Canvas 用法: 使用JavaScript动态绘制。
js
// html
<canvas width="120" height="120">
An alternative text describing what your canvas displays.
</canvas>
//js
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.fillStyle = "green";
// Add a rectangle at (10, 10) with size 100x100 pixels
ctx.fillRect(10, 10, 100, 100);
语法便利程度: 复杂,需要编程知识。 学习成本: 较高,需要熟悉Canvas API。 是否矢量图: 可以视为矢量图,但实际上是像素渲染,绘制完成后会导出为 PNG 或 JPEG。 体积大小: 动态生成,取决于实际绘制的内容。 性能: 较好,适合动态效果和动画。 缓存: 无法缓存,每次都需要重新绘制。 适用场景: 适合于复杂的图形处理和动画效果。
Web Components Web Component - Web API | MDN (mozilla.org) 用法: 定义自定义元素,并在其中放置图标。 语法便利程度: 中等到高,需要编写组件。 学习成本: 较高,需要了解Web Components。 是否矢量图: 取决于使用的图标类型。 体积大小: 取决于图标本身。 性能: 较好,封装性好。 缓存: 可以被浏览器缓存。 适用场景: 适合于复杂的Web应用,便于组件化管理。
Server-Side Rendering (SSR) 用法: 在服务器端生成图标HTML。 语法便利程度: 中等到高,需要服务器端脚本。 学习成本: 较高,需要了解服务器端渲染技术。 是否矢量图: 取决于生成的图标类型。 体积大小: 取决于图标本身。 性能: 较好,可以提高首屏加载速度。 缓存: 可以被浏览器缓存。 适用场景: 适合于需要服务器端渲染的应用程序。
SVG 用法:
html
<svg version="1.1"
baseProfile="full"
width="300" height="200"
xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="100%" fill="red" />
<circle cx="150" cy="100" r="80" fill="green" />
<text x="150" y="125" font-size="60" text-anchor="middle" fill="white">SVG</text>
</svg>
<object data="image.svg" type="image/svg+xml"></object>
<iframe src="image.svg"></iframe>
// SVG 可以通过 JavaScript 动态创建并注入到 HTML DOM 中
学习成本: 需要了解SVG语法。 是否矢量图: 是。 体积大小: 较小,特别是当图标简单时。 性能: 较好,因为是矢量图且体积较小。 缓存: 直接嵌入 SVG 代码时,整个 HTML 文档会被缓存;而通过 <img>
标签引入时,SVG 文件会被作为一个独立的资源缓存。 适用场景: 适合于需要缩放而不失真的情况。
优点:矢量图,随时可改变形状大小颜色,SVG 支持渐变、旋转、复杂的曲线动画、滤镜效果、与 JavaScript 交互。
- 通过 ID 和 Class 选择 SVG 元素 用法:给 SVG 元素分配 ID 或 class,然后使用 JavaScript 通过这些选择器来访问和操作这些元素。
html
<svg id="mySVG" width="100" height="100">
<circle id="myCircle" cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" />
</svg>
<script>
const circle = document.getElementById('myCircle');
circle.setAttribute('fill', 'blue');
</script>
- 添加事件监听器 用法:使用 addEventListener 方法来为 SVG 元素添加事件监听器。
js
<svg width="100" height="100">
<rect x="10" y="10" width="80" height="80" fill="green" id="myRect" />
</svg>
<script>
const rect = document.getElementById('myRect');
rect.addEventListener('click', function(event) {
event.target.setAttribute('fill', 'yellow');
});
</script>
- 动画和定时器 用法:使用 JavaScript 的 setTimeout 和 setInterval 来创建动画效果。
js
<svg width="200" height="200">
<circle cx="100" cy="100" r="50" fill="blue" id="myCircle" />
</svg>
<script>
const circle = document.getElementById('myCircle');
let angle = 0;
setInterval(function() {
angle += 5; // 每次旋转 5 度
const rad = angle * Math.PI / 180;
const cx = 100 + 50 * Math.cos(rad);
const cy = 100 + 50 * Math.sin(rad);
circle.setAttribute('cx', cx);
circle.setAttribute('cy', cy);
}, 100); // 每 100 毫秒更新一次位置
</script>
- 与 CSS 结合使用 用法:结合使用 JavaScript 和 CSS 来控制 SVG 元素的样式。
js
<svg width="200" height="200">
<circle cx="100" cy="100" r="50" fill="blue" id="myCircle" />
</svg>
<style>
#myCircle.active {
fill: red;
}
</style>
<script>
const circle = document.getElementById('myCircle');
circle.addEventListener('click', function() {
circle.classList.toggle('active');
});
</script>
- 使用 SVG.js 或 Snap.svg 用法:使用这些轻量级的 SVG 操作库来简化 SVG 元素的操作和动画。
js
<svg width="200" height="200">
<circle cx="100" cy="100" r="50" fill="blue" id="myCircle" />
</svg>
<script src="https://cdn.jsdelivr.net/npm/svg.js@3.1.1/dist/svg.min.js"></script>
<script>
const circle = SVG('myCircle');
circle.animate(2000).attr({ fill: 'red' }).repeat();
</script>
SVG 与 JavaScript 的交互可以让你创建动态的图形和动画效果。通过选择器、事件监听器、定时器、SVG DOM 方法、第三方库以及 CSS 的组合使用,你可以轻松地实现复杂的 SVG 动画和交互。选择合适的方法取决于你的具体需求和项目的复杂性。 缺点:加载慢。
为了完整地实现这个功能,你需要编写一个脚本来生成 SVG 组件,并更新 index.ts
文件。以下是完整的示例代码:
1. 安装依赖项
首先,确保安装了 @svgr/cli
和 child_process
模块。在你的项目根目录中运行以下命令:
bash
bash
深色版本
1npm install -D @svgr/cli child_process
2. 编写脚本文件
创建一个名为 generate-icons.js
的文件,并将以下代码复制进去:
javascript
javascript
深色版本
1const path = require('path');
2const fs = require('fs');
3const execSync = require('child_process').execSync;
4
5function generateSvgComponent(item) {
6 if (item === 'index') return Promise.resolve();
7
8 return new Promise((resolve, reject) => {
9 try {
10 execSync(`npx @svgr/cli -- ${path.resolve(__dirname, `../src/components/ui/icon/svg/${item}.svg`)}`);
11 resolve();
12 } catch (error) {
13 reject(error);
14 }
15 });
16}
17
18function updateIndexFile() {
19 const indexPath = path.join(__dirname, '../src/components/ui/icon/index.ts');
20 const iconDirPath = path.resolve(__dirname, '../src/components/ui/icon/icons');
21
22 const files = fs.readdirSync(iconDirPath).filter(file => file.endsWith('.svg'));
23
24 let content = files
25 .map(file => `export * from './icons/${file.replace(/.svg$/, '')}'`)
26 .join('\n');
27
28 content += '\n';
29
30 fs.writeFileSync(indexPath, content);
31}
32
33async function main() {
34 await generateSvgComponent('index');
35 updateIndexFile();
36}
37
38main().catch(console.error);
3. 运行脚本
在终端中运行以下命令:
bash
深色版本
1node generate-icons.js
这个脚本会自动遍历 ./src/components/ui/icon/icons
目录下的所有 .svg
文件,并使用 @svgr/cli
将它们转换为 React 组件。同时,它还会更新 index.ts
文件,使你可以按需导入和使用这些组件。
4. 使用生成的组件
在你的 React 应用程序中,你可以像这样使用生成的组件:
ini
jsx
深色版本
1import { UserIcon } from './components/ui/icon';
2
3function App() {
4 return (
5 <div className="App">
6 <UserIcon color="red" />
7 </div>
8 );
9}
在这个例子中,color
属性会被传递给 UserIcon
组件,使其能够更改图标颜色。这是由于 @svgr/cli
工具生成的组件通常具有这样的功能。
请注意,这个脚本仅适用于简单的场景。在实际项目中,你可能需要对它进行调整以满足特定需求,比如处理错误、添加日志记录等功能。
IconFont 用法: 使用字体图标字符,通过CSS设置。 语法便利程度: 方便,只需一个字符。 学习成本: 低,只需了解基本的CSS和字体图标集。 支持的格式: 字体图标,通常是 TTF, OTF, WOFF, WOFF2 等字体格式。 是否矢量图: 是,基于字体。 体积大小: 较小,尤其是当多个图标打包在一个字体文件中时。 性能: 好,因为字体文件可以被缓存。 缓存: 可以被浏览器缓存。 适用场景: 适合于需要大量图标并且希望保持字体一致性的项目。
各自优缺点
- Img (Image) 优点: 易于使用: 只需一个 标签即可显示图标。 跨浏览器兼容性: 几乎所有浏览器都支持 标签。 尺寸固定: 图标尺寸不会随文本缩放而改变,保持一致的视觉效果。 缺点: 不灵活: 需要为不同尺寸和状态准备多个图像文件。 加载时间: 每个图像都需要额外的HTTP请求,可能会增加页面加载时间。 样式限制: 无法使用CSS进行颜色或透明度调整。
- CSS 优点: 可定制性强: 可以通过CSS对图标进行颜色、阴影等样式的修改。 响应式: 图标可以随着容器尺寸变化而自动调整大小。 单个HTTP请求: 如果使用CSS Sprites或者CSS背景图,可以减少HTTP请求数量。 缺点: 复杂性: 需要额外的工作来创建复杂的图标。 维护成本: 更改图标可能需要修改CSS代码。 兼容性问题: 对于某些较老的浏览器,可能需要额外的polyfills。
- HTML5 Canvas 优点: 高性能: 特别适合动画和复杂的图形操作。 动态生成: 可以根据需要动态绘制图标。 可扩展性: 图标可以根据需要缩放而不失真。 缺点: JavaScript依赖: 需要编写JavaScript代码来绘制图标。 不便于维护: 修改图标通常需要更改代码。 SEO不友好: Canvas内容对搜索引擎不可见。
- SVG (Scalable Vector Graphics) 优点: 矢量图形: 图标可以无损缩放。 样式可定制: 可以使用CSS来改变颜色、填充等属性。 单个HTTP请求: 可以内联到HTML中,避免额外的HTTP请求。 响应式: 可以根据容器尺寸自动调整大小。 缺点: 复杂图标: 复杂图标可能需要较多的手工编码。 IE兼容性: IE9及以下版本不支持SVG。
- Icon Font 优点: 样式可定制: 使用CSS来改变颜色、大小等属性。 单个HTTP请求: 所有图标都可以打包在一个字体文件中。 易于使用: 只需像使用文字一样使用图标字符。 缺点: 图标质量: 字体图标可能不如SVG清晰。 兼容性问题: 较老的浏览器可能不支持某些字体。 多语言环境: 在多语言环境中可能与文字混排产生问题。
- Web Components 优点: 封装性: Web Components 提供了一种封装图标的方法,可以将图标及其行为封装在一个自定义元素中。 重用性: 可以轻松地在多个项目中重用相同的图标组件。 可扩展性: 可以在组件内部添加更多的逻辑和交互。 缺点: 浏览器兼容性: 虽然大多数现代浏览器都支持Web Components,但在一些旧版浏览器上可能需要polyfills。 学习曲线: 开发者需要学习如何创建和使用Web Components。 性能: 使用Web Components可能会带来一些额外的性能开销,尤其是在大量使用时。