解锁SVG新姿势:ChatGPT绘制图标+SVG Symbol自动导入
1 前言
大家好,我是心锁,一枚23届准毕业生。
近期ChatGPT很火,作为前端er,我思考与尝试了让它帮忙写代码、帮助我解析与研究某些国内资料较少的技术、优化代码、解释代码、优化简历——都非常棒,就是很可惜GPT的图片能力还一般,如果什么时候它可以解析图片了,或许图片生成代码就不远了。
等一下,SVG好像也是图片,就在某个时刻我灵光一闪,于是本文章就出来了。
2 目标
不知道诸位读者们有没有自己找icon的经历:
- 先找到对应图片并下载
- 将文件移动到项目并改名
- 在需要使用的地方导入并通过img标签使用
私以为,第一步,第二步,第三步我都不喜欢。有没有一种合适的方式,让我可以直接通过IDE新建文件,不再需要下载,同时使用的时候不再需要导入?
这或许是有的,本文旨在完成该目标。
3 演示ChatGPT生成SVG
本步骤也可以理解成正常流程中的寻找图标与自行绘制图片
众所周知,SVG是一种矢量图形格式,可以通过代码描述出图形,而不是像普通图片一样储存像素点。这使得SVG图标具有可缩放性,适合在不同分辨率的设备上使用。同时,SVG图标可以用作网站的某些元素,例如logo、导航菜单等。
再众所周知,ChatGPT具有生成代码的能力。我们可以利用ChatGPT生成SVG代码,这样就可以省去自己绘制图标或者自己找图标的步骤。
我试着用下边的文案生成了一些icon,大家可以参考:
3.1 一款网络助手的logo
生成一个扁平风格的图标,该图标用途是作为一款网络助手程序的logo。背景色是“#7FA1F7”,圆角22.5%。注意要求图像大小为64*64,图像内容需在viewBox居中。
3.2 绘制一个用于掘金的拟物化“矿石”图标
绘制一个64*64的“矿石”图标,以svg格式输出。该图标用于表示社区中的金币,图标风格应偏向拟物化风格,整体需符合掘金社区的气质,并确保图像内容需在viewBox居中。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<circle cx="32" cy="32" r="30" fill="#e8ca6f" stroke="#c3a150" stroke-width="2"/>
<path d="M 32 5 L 60 23 L 60 41 L 32 59 L 4 41 L 4 23 Z" fill="#e0b757" stroke="#c3a150" stroke-width="2"/>
<path d="M 32 17 L 52 33 L 32 49 L 12 33 Z" fill="#d4a84a"/>
<path d="M 32 23 L 45 33 L 32 43 L 19 33 Z" fill="#e8ca6f"/>
<path d="M 32 27 L 41 33 L 32 39 L 23 33 Z" fill="#f2e1a9"/>
</svg>
3.3 绘制一个用于掘金的拟态化“收藏”图标(它好像把掘金社区误会成真的掘金了)
绘制一个64*64的“收藏”图标,以svg格式输出。图标风格应偏向拟态化风格,整体需符合掘金社区的气质,并确保图像内容需在viewBox居中。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<circle cx="32" cy="32" r="30" fill="#e8ca6f" stroke="#c3a150" stroke-width="2"/>
<path d="M 32 17 L 44 33 L 32 49 L 20 33 Z" fill="#e0b757" stroke="#c3a150" stroke-width="2"/>
<path d="M 32 21 L 40 33 L 32 45 L 24 33 Z" fill="#d4a84a"/>
<path d="M 32 27 L 36 33 L 32 39 L 28 33 Z" fill="#e8ca6f"/>
<rect x="25" y="26" width="14" height="12" fill="#f2e1a9"/>
<path d="M 26 27 L 32 22 L 38 27 L 38 33 L 26 33 Z" fill="#c3a150"/>
<path d="M 38 27 L 32 32 L 26 27 L 26 33 L 38 33 Z" fill="#d4a84a"/>
<circle cx="32" cy="32" r="9" fill="#f2e1a9"/>
</svg>
4 Svg Symbol自动导入
4.1 什么是Symbol
为了实现不需要下载和导入文件,我们可以使用SVG Symbol。使用SVG Symbol,我们可以将所有的图标放在一个单独的SVG文件中,并通过引用该文件中的Symbol元素来使用它们。
以下是一个示例SVG文件,其中定义了两个Symbol元素:
<svg xmlns="<http://www.w3.org/2000/svg>" style="display:none">
<symbol id="icon-search" viewBox="0 0 24 24">
<path fill="none" d="M0 0h24v24H0V0z"/>
<path d="M9.5 15h-.79l-.28-.27C8.01 13.54 7.5 12.8 7.5 12c0-1.38 1.12-2.5 2.5-2.5s2.5 1.12 2.5 2.5c0 .8-.5 1.54-1.21 1.73l-.28.27v.5l5 4.99L20.49 19l-4.95-5zm-1-3a2.5 2.5 0 1 0 0-5 2.5 2.5 0 0 0 0 5z"/>
</symbol>
<symbol id="icon-heart" viewBox="0 0 24 24">
<path fill="none" d="M0 0h24v24H0V0z"/>
<path d="M12 21.35l-1.45-1.32C5.4 14.35 2 11.43 2 7.77 2 5.82 3.16 4.02 5 3.14 6.38 2.5 8.35 2.5 10 3.44 11.65 2.5 13.62 2.5 15 3.14c1.84.88 3 2.68 3 4.63 0 3.66-3.4 6.58-8.55 11.26L12 21.35z"/>
</symbol>
</svg>
以下是一个使用SVG Symbol的示例代码:
<svg>
<use xlink:href="#icon-search"></use>
<use xlink:href="#icon-heart"></use>
</svg>
在上面的代码中,我们通过<use>
元素引用了SVG文件中的两个Symbol元素,并将它们放在了<svg>
元素内。
4.2 自动化导入
为了进一步简化该流程,我们可以使用Webpack和svg-sprite-loader自动导入SVG Symbol。
4.2.1 添加svg-sprite-loader
以下是一个Webpack配置文件中添加的svg-sprite-loader
规则:
module: {
rules: [
{
test: /\.svg$/i,
oneOf: [
{
resourceQuery: /asset/,
type: "asset/resource",
},
{
loader: "svg-sprite-loader",
include: path.resolve(__dirname, "../src/images/svg"),
options: {
symbolId: "icon-[name]",
},
},
],
},
]
}
该规则将处理所有以.svg
结尾的文件,并使用svg-sprite-loader
将它们转换为SVG Symbol元素。其中,symbolId
选项用于生成Symbol元素的ID。这样既保留了导入svg为url的能力,又拥有了symbol导入能力。
4.2.2 自动导入所有svg图标
我们可以在images
文件夹下新建一个svg
文件夹,在其中存放所有的SVG图标文件。然后,我们创建一个svg-sprite.ts
文件,使用require.context
函数自动导入所有的SVG文件并将它们添加到页面中。
// svg-sprite.ts
const importAll = (requireContext: __WebpackModuleApi.RequireContext) =>
requireContext.keys().forEach(requireContext);
importAll(require.context('./svg', true, /\.svg$/));
export {};
在上面的代码中,我们使用require.context
函数导入了所有以.svg
结尾的文件,并将它们添加到页面中。
在该步骤,需要注意两个点。
- 需要导入
svg-sprite.ts
文件
务必在主文件中导入该文件:
// App.tsx
import "./images/svg-sprite";
- 若出现和WebpackModuleApi相关错误,强烈建议使用any代替
4.2.3 在React中使用
为方便使用,我们封装一个SvgIcon组件。
import React from "react";
import "./index.less";
export interface SvgIconProps extends React.HTMLAttributes<HTMLElement> {
name: string;
className?: string;
color?: string;
}
const SvgIcon: React.FC<SvgIconProps> = ({
name = "",
className = "",
color = "currentColor",
...rest
}) => {
return (
<i className={`${className}`} aria-hidden {...rest}>
<svg className={"svg-icon"}>
<use xlinkHref={"#icon-" + name} fill={color} />
</svg>
</i>
);
};
export default SvgIcon;
在上面的代码中,我们定义了一个SvgIcon
组件,用于渲染SVG图标。该组件使用了<use>
元素引用了SVG文件中的Symbol元素。其中,name
属性用于指定Symbol元素的ID。
.svg-icon{
width: 1em; height: 1em;
vertical-align: -0.15em;
fill: currentColor;
overflow: hidden;
}
使用em
作为icon的单位,是因为em
是相对于当前对象内文本的字体尺寸的宽度单位,这样我们就可以通过设置fontSize的方式来调整icon的图标了。
使用方式:
import SvgIcon from "@/components";
const MyComponent: React.FC = () => {
return (
<div>
<SvgIcon name="search" className="text-[1rem]" />
<SvgIcon name="heart" />
</div>
);
};
在上面的代码中,我们使用了SvgIcon
组件来渲染SVG图标,其中,name
属性用于指定需要渲染的图标的名称。
至此,我们已经完成了将SVG图标转换为SVG Symbol,并自动导入的流程。现在,我们可以直接在代码中使用SVG图标了,而不需要导入文件。
4.2.4 性能考虑
值得注意的是,该方法存在一定的问题。由于我们全量引用了图标,会导致在所有页面,都会导入所有icon,原因是我们在svg-sprite.ts
文件中做了自动化导入,我们亦可通过单行导入的方式来避免全量引入,我目前在思考有没有什么更好的方案解决该问题。
import "@/images/svg/rough.svg";
5 总结
本文主要介绍了两个方法,分别是使用ChatGPT自动生成SVG代码和使用Webpack和svg-sprite-loader自动导入SVG Symbol。这些方法可以使得在代码中使用SVG图标更加方便和高效。
综上所述,通过使用ChatGPT自动生成SVG代码和使用Webpack和svg-sprite-loader自动导入SVG Symbol,我们可以更加便捷地在代码中使用SVG图标,提高开发效率和代码质量。
本文正在参加「金石计划」