/【雷火UX平台开发】还在使用字体图标?试试打造SVG图标库吧

【雷火UX平台开发】还在使用字体图标?试试打造SVG图标库吧



1
 背  景  
SVG是一种图像的文件格式,全称是可缩放矢量图(Scalable Vector Graphics)。它是基于 XML 语法的文本文件,其他图像格式大都基于像素处理,因此SVG不像其他图像格式一样,在放大的时候,会发生失真现象。
SVG相比于PNG、JPEG图像,尺寸更小,可压缩性更强,并且可伸缩,可在图像不失真的情况下被放大,具有开放的标准,可以用来表示图形、滤镜、动画等。它的历史也非常悠久 ,在2003年就已经成为W3C标准,主流浏览器都支持SVG。
在实际工作中,SVG非常适合静态图片展示、高保真文档查看和打印等场景由于SVG是基于XML语法描述的,因此可以方面的对更改XML描述,比如Path、Line、颜色、大小等,达到变化SVG图标的作用。设计只需要出一份SVG图,即可变化大小、颜色、动画等用在页面的多处
2
icon-front方案的弊端  

IconFont是国内功能知名度非常高、强大且图标内容很丰富的SVG开源库,除此之外,还有一些常见的开源SVG库

  • Font Awesome

  • Iconicons

  • css.gg

  • Featheroicons

  • Eva Icons

  • Heroicon

  • Bootstrap iconsl

  • Remix icons

    ...

这些常用的SVG开源库,都拥有非常庞大的SVG图标资源。



在实际开发过程中,接入使用这些SVG资源的流程如下:

这种方式,有一些弊端
操作步骤繁琐,每次更新图标之后,都需要重新完整的走一遍上述所有流程
无法形成标准,不同项目之间无法复用,项目间只能重复拷贝;想要查询之前公司已经有的SVG,没有入口
需要借助第三方网站,强依赖上述提及的第三方网站,公司内部的SVG上传存在安全风险
实际使用是统一将所有的icon打包到字体文件,通过class+css的方式引入,没办法做按需加载
基于这些弊端,我们会更期望有一个具有统一标准、能被复用、不依赖第三方网站、支持按需加载、接入使用和维护扩展更加便捷的SVG组件库
3
  方案调研    
>>

SVG Sprite

webpack svg-sprite-loader 支持将SVG文件合并成一个SVG sprite 并加载到一个 display: none 的元素中,使用时,传入图标的id渲染出图标。这种方案,支持按需加载和打包。


>>

SVG To React

webpack svg-react-loader 支持直接require一个SVG图片,用户只需要对webpack做简单配置即可直接使用。


>>

将SVG转换为React组件

SVG Sprite 和 SVG To React方案,如果svg放置在独立的组件库的话,业务需要配置loader处理node_modules的文件。这两种方式,对于组件库的易用性来说,都是有缺点的。
因此,考虑将每个独立的SVG在组件库进行转换,转换为纯粹的React组件,render返回SVG的XML,Props传入对SVG的更改操作。
4
  开发实现    

重新梳理下上述方案思路,明确要做的事情:

1. 创建独立SVG组件库,存放通用的SVG图片

2. 将每个SVG转换为独立的React Component
3. 将每个React Component编译构建,支持业务按需引入

我们主要介绍2和3

>>

将SVG转换为独立的React Component

● 主要用到的方式是svgr 的开源库

    SVGR的特点:

  • 强大:svgr支持处理所有类型的svg,并将其转换为React组件

  • 通用:支持多种方式,在线、CLI、Nodejs、webpack插件、Rollup插件... 支持列表名单很长

  • 可定制:svgr是完全可配置的,可以使用内置设置,也可以完全自定义创建自己的配置

  • 使用广泛:很多开源社区项目,都使用了svgr,8.1K的star数目

 配置svgr的方式非常简单,只需要简单,指定svg转换后的react模板
function propTypesTemplate({ template }, opts, { imports, interfaces, componentName, props, jsx, exports }) {  const plugins = ['jsx'];  if (opts.typescript) {    plugins.push('typescript');  }  const typeScriptTpl = template.smart({ plugins });  return typeScriptTpl.ast`  ${imports}${interfaces}const ${componentName} = (${props}) => {  const color = props.color ? props.color : props.style?.color ? props.style.color : 'currentColor';  props = { ...props, fill: color };  return ${jsx};}${exports}  `;}module.exports = propTypesTemplate;

 即可获得转换后的React 组件
const SvgArrowBoldRight = (props: React.SVGProps<SVGSVGElement>) => {  const color = props.color ? props.color : props.style?.color ? props.style.color : 'currentColor';  props = { ...props, fill: color };  return (    <svg width="1em" height="1em" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" {...props}>      <path        fillRule="evenodd"        clipRule="evenodd"        d="M5.94 18.06a1.5 1.5 0 010-2.12L11.878 10l-5.94-5.94a1.5 1.5 0 112.122-2.12l6.116 6.115a2.75 2.75 0 010 3.89L8.06 18.06a1.5 1.5 0 01-2.122 0z"      />    </svg>

>>

将React Component编译构建出esm和cjs

babel和tsconfig的配置,就不在这里详细再介绍了
使用build:es,将每一个React Component 按esm格式输出到es文件夹
{  "build:es": "npm run build:es:types && cross-env NODE_ENV=es babel src --out-dir es --extensions '.ts,.tsx'",  "build:js": "npm run build:js:types && babel src --out-dir lib --extensions '.ts,.tsx'",}
指定组件库访问路径
{  "main": "lib/index.js",  "module": "es/index.js",}
至此,支持按需加载的独立svg库就已经搭建完毕,将svg组件库发布到npm仓库之后,可以以非常便捷方便的方式引用
添加新的svg的话,只需要将svg加入到组件库,执行convert和build指令即可。
import { ArrowUp } from 'react-svg-component';<ArrowUp style={{ fontSize: '48px', color: 'red' }} />
同时,也可以通过import * 获取组件库的所有SVG组件,渲染到在线Demo文档,方便实时查看。

5
  总  结    

svg是基于xml语法描述的一种图像文件格式,最大的优点是放大不失真、方便修改大小和色值,实际工作中非常适合作为静态图片展示;

公司内部往往会有自己通用的一些SVG Icon,将这些SVG Icon沉淀成组件库,可以方便设计、产品和开发实时取用;

搭建SVG库的思路,主要体现在,将SVG转换为独立的React Component,再将React Component输出对应的esm和cjs格式;

公用的SVG库,可以简化icon font的svg使用方式,开发人员能以便捷的方式对svg进行更改;也能在各产品中统一和规范Icon的使用和风格。

往期推荐


本文来自微信公众号“网易雷火UX用户体验中心”(ID:LeihuoUX)。大作社经授权转载,该文观点仅代表作者本人,大作社平台仅提供信息存储空间服务。