前言
之前我在项目中使用Icon图标习惯使用iconfont的形式。但是渐渐觉得,这种方式需要固定下载并引入字体的ttf文件和woff文件。并且使用iconfont的形式,自己一个人写项目的时候是爽了,但是一旦项目交给其他人了,别人想继续添加新的icon图标,是没办法在你之前的icon图标文件上添加新图标的。必须得重新下载引入ttf文件和woff文件,定义新的字体和icon类名。而且使用iconfont的形式的icon元素语义不直观,别人看到这行代码很难分辨出这是个什么图标。
所以我选择直接使用icon图标的svg代码加组件封装的形式,具体如下:
React中使用
1. 先安装 @ant-design/icons
npm install @ant-design/icons
2. 新建一个CreateIcon.tsx文件(注意:文件是tsx文件)
import type { CustomIconComponentProps } from "@ant-design/icons/lib/components/Icon";
import Icon from "@ant-design/icons";
type OtherProps = {
/**图标的大小,会转换为style-fontSize写入组件 */
size?: number;
/**图标的颜色,会转换为style-color写入组件 */
color?: string;
};
const mergeObj = <T extends Obj, D extends Obj[]>(mainObj: T, ...otherObj: D): T & UnionToIntersection<D[number]> => {
return Object.assign({}, mainObj, ...otherObj)
}
/**创建一个icon组件,传入svg代码
* @param Svg 符合条件的svg代码
* @tip 条件
* 基于SVG,可以在 https://www.iconfont.cn/ 上寻找喜欢的图标,然后复制svg代码
* 1. 把复制下来的代码中svg的属性,t和class删掉,就可以没有ts报错,然后宽高改为1em
* 2. 如果需要颜色跟随自己定制的颜色,需要给svg的path标签的fill属性设置为"currentColor"
* @returns
*/
export const createIcon = (Svg: JSX.Element) => {
return function _Icon(props: Partial<CustomIconComponentProps> & OtherProps) {
const { size, color, style = {}, ...IconProps } = props;
const realStyle = mergeObj({ fontSize: size, color }, style);
return <Icon component={() => Svg} {...IconProps} style={realStyle} />;
};
};
export default createIcon;
再新建一个MyIcon.tsx文件
import { createIcon } from ".";
export const Audio = createIcon(
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5118" width="1em" height="1em"><path className="audioSvg" d="M566.215111 899.811556v118.158222h-85.333333v-114.915556C294.4 888.718222 147.342222 735.573333 147.342222 562.688a42.666667 42.666667 0 0 1 85.333334 0c0 134.257778 123.790222 256.113778 276.764444 256.113778s276.707556-121.912889 276.707556-256.113778a42.666667 42.666667 0 1 1 85.333333 0c0 164.067556-132.380444 310.385778-305.265778 337.123556zM510.976 33.336889a170.666667 170.666667 0 0 1 170.666667 170.666667v341.333333a170.666667 170.666667 0 1 1-341.333334 0v-341.333333a170.666667 170.666667 0 0 1 170.666667-170.666667z" fill="#1296DB" p-id="5119"></path></svg>
)
- 复制自己喜欢的icon图标的svg代码,粘贴到createIcon函数的参数里。
- 把复制下来的代码中svg的属性,t和class删掉,就可以没有ts报错,然后宽高改为1em
- 如果需要颜色跟随自己传入的颜色,需要给svg的path标签的fill属性设置为"currentColor"
- 最后导出的Audio就是Icon组件,可以直接使用
后面想要多少个icon就按照这种方法添加就行
最后在组件中使用
import { Audio } from "@/components/base/UI/MyIcon.tsx"
export default function FunctionComponent(){
return (
<div>
{/* 注意这里如果要传入color参数的话,记得把图标svg代码的fill属性设置为"currentColor",这样color参数才会生效 */}
<Audio size={30} />
</div>
)
}
在Vue项目中使用
首先要配置一下vue配置,使其支持jsx语法
配置Vue
- 安装 @vitejs/plugin-vue-jsx 和 element-plus
npm install @vitejs/plugin-vue-jsx element-plus
- 配置 vite.config.ts
import VueJsx from '@vitejs/plugin-vue-jsx'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
.....
vueJsx({
transformOn: true,
mergeProps: true
})
],
})
配置tsconfig.json
{
......
"compilerOptions": {
.........
"jsx": "preserve",
"jsxImportSource": "vue"
}
}
新建一个CreateIcon.tsx文件 (注意是tsx文件)
import { defineComponent } from 'vue'
import type { JSX } from 'vue/jsx-runtime';
import { ElIcon } from "element-plus"
type OtherProps = {
/**图标的大小 */
size?: number;
/**图标的颜色 */
color?: string;
};
/**创建一个icon组件,传入svg组件
* @param Svg 符合条件的svg组件
* @tip 条件
* 基于SVG,可以在 https://www.iconfont.cn/ 上寻找喜欢的图标,然后复制svg代码
* 1. 把复制下来的代码中svg的属性,t和class删掉,就可以没有ts报错,然后宽高改为1em
* 2. 如果需要颜色跟随自己定制的颜色,需要给svg的path标签的fill属性设置为"currentColor"
* @returns
*/
export const createIcon = (Svg: () => JSX.Element) => {
return defineComponent<OtherProps>(
(props, { emit, slots, attrs }) => {
const { size, color } = props;
return () => (
<ElIcon size={size} color={color}>
<Svg></Svg>
</ElIcon>
)
}
)
};
export default createIcon
新建一个MyIcon.tsx文件 (注意是tsx文件)
import { createIcon } from ".";
export const XiaoXiIcon = createIcon(
() => (
<svg
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="951"
width="1em"
height="1em"
>
<path
d="M513.4 97.2c-220.5 0-399.2 156.4-399.2 349.3 0 110.3 58.5 208.4 149.7 272.5v176.7l174.9-106.1c24.2 4 49.1 6.3 74.6 6.3 220.5 0 399.2-156.4 399.2-349.3 0.1-193-178.7-349.4-399.2-349.4z m124.8 474.1H388.7c-13.8 0-25-11.2-25-25s11.2-25 25-25h249.5c13.8 0 25 11.2 25 25s-11.2 25-25 25z m49.9-149.8H338.8c-13.8 0-25-11.2-25-25s11.2-25 25-25h349.3c13.8 0 25 11.2 25 25 0 13.9-11.2 25-25 25z"
fill="currentColor"
p-id="952"
></path>
</svg>
)
)
- 复制自己喜欢的icon图标的svg代码,粘贴到createIcon函数的参数里。(注意:这里粘贴svg代码时,要写成函数返回值的形式,如上 () => (<svg>.......<\svg>)
- 把复制下来的代码中svg的属性,t和class删掉,就可以没有ts报错,然后宽高改为1em
- 如果需要颜色跟随自己传入的颜色,需要给svg的path标签的fill属性设置为"currentColor"
- 最后导出的XiaoXiIcon就是Icon组件,可以直接使用
后面想要多少个icon就按照这种方法添加就行
在Vue组件中使用
<template>
<div>
<!--注意这里如果要传入color参数的话,记得把图标svg代码的fill属性设置为"currentColor",这样color参数才会生效 -->
<XiaoXiIcon :size="30" color="#1296db" />
</div>
</template>
<script setup lang="ts">
import { XiaoXiIcon } from "@/components/icons/createIcon";
</script>
其他
当然如果不想在vue中使用jsx语法,也可以使用vue提供的h函数来生成虚拟dom,也可以做到像这样传入svg代码生成icon组件的效果,也可以直接创建一个.vue文件做为icon组件,这里展示一下
新建icon图标的.vue组件
//IconBack.vue
<template>
<svg
t="1725352194401"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2464"
:width="props.size"
:height="props.size"
>
<path
d="M682.424996 911.667585c-8.490372 0-17.041118-2.841721-24.091698-8.685823L199.142038 522.585079c-8.662287-7.185656-13.682627-17.853623-13.682627-29.112038s5.02034-21.926382 13.682627-29.111015L658.333298 83.941807c16.068977-13.325493 39.902802-11.06194 53.228295 4.995781 13.313214 16.081257 11.073196 39.901779-4.995781 53.228295L282.502607 493.473041 706.565812 844.756663c16.068977 13.326517 18.308995 37.147038 4.995781 53.228295C704.080202 907.004379 693.301717 911.667585 682.424996 911.667585z"
p-id="2465" :fill="props.color || ''"
></path>
</svg>
</template>
<script setup lang="ts">
interface iconProps {
/**图标的大小 */
size?: string;
/**图标的颜色 */
color?: string;
}
const props = defineProps<iconProps>();
</script>