SVG 是一种基于 XML 语法的图像格式的矢量图。且不管放大多少倍都不会失真。由于项目中需要用到图标。然而在 React 版记账项目中应用 SVG 的过程并不是很顺利... anyway 最终功能实现啦~
当作图片使用
- 导入:
import x from 'label.svg'
- 使用
<img src={x} alt=""/>
弊端
- 我们无法实现设置图片的颜色等其它功能
- 重复的 SVG 代码就要复制粘贴,后期维护工作量巨大。
因此,为何不能组件化呢?其实使用 SVG 配合 use 标签就实现该功能
当作 SVG Symbol 使用
由于需要对应的 loader 但是 React 应用没有 webPack 配置文件,因此需要自定义 webpack
自定义 webpack
- 运行 yarn eject 拿到 webpack 配置
- 安装 svg-sprite-loader:yarn add --dev svg-sprite-loader
- 安装 svgo-loader:yarn add --dev svgo-loader
- 在 config/webpack.config.js 文件中 配置 两个 loader
{
test: /\.svg$/,
use: [
{loader: 'svg-sprite-loader', options: {}},
{loader: 'svgo-loader',
options: {plugins:[{removeAttrs: {attrs: 'fill'}}]}
}
]
},
安装完可能会报错,问题不大根据提示操作即可。
使用
svg 里面要包含 use 标签, id 对应 # 加上 svg 的文件名
<svg><use xlinkHref=id/></svg>
举个栗子:
// 导入
import x from 'label.svg'
// 使用
<svg><use xlinkHref='#label'/></svg>
图片未显示??? 触发了 TreeShaking
TreeShaking
默认删除没有用到的变量
- 可以看到没有明显的使用 x,只是把 svg 导入进来了
- 因此会被 TreeShanking
- 防止引入的 SVG 被 TreeShaking,使用 require 代替 import
require('label.svg')
<svg><use xlinkHref='#label'/></svg>
每次使用 SVG 要以上操作 ,为什么不将使用 SVG 的代码封装成组件使用呢?
创建 Icon 组件(组件化重点!)
-
一次性引入所有的 SVG
-
在 icons 目录通过文件名当作 id引用到任何组件
Icon.tsx
import React from 'react';
let importAll = (requireContext: __WebpackModuleApi.RequireContext) => requireContext.keys().forEach(requireContext);
try {importAll(require.context('icons', true, /\.svg$/));}
catch (error) {console.log(error);}
type Props = {
name: string
} & React.SVGAttributes<SVGElement>
const Icon = (props: Props) => {
return (
<svg>
<use xlinkHref={'#' + props.name}/>
</svg>
);
};
export default Icon;
当需要用到 SVG ,直接引用 Icon 组件同时向组件传入 SVG 文件名是不是相当方便呢
<Icon name="left"/>
一次性引入所有 SVG 的代码报错:
安装 :yarn add --dev @types/webpack-env@1.15.1
loader 到底做了什么?
svg-sprite-loader
- svg-sprite-loader 发现有 svg 标签,就把 svg 变成 symbol,再在 symbol 外面套一层 svg 标签,最后把 svg 放到 body 里面。
- 为什么要套一层svg 呢?因为可能会有很多 SVG
- 通过 use 标签即可使用 SVG
svgo-loader
当 SVG 默认使用了 fills 属性设置颜色,导致无法换色
- 配置 svgo-loader 删除 SVG 自带的fill 属性,从而可通过设置 fill自定义 SVG 颜色的