• vue3 + vite项目使用SVG图标


    我们在开发一个项目时常会用到一些图标,有些图标在有限的图标库中却是没有,因此少数的图标需要我们去网上查找,或是自定义一些专用的图标。一般很少有图标库满足现实的项目开发,这时将推荐使用 iconify 这个图标库,几乎包含我们常见全部的图标,使用也非常简单。废话不多说咱们开始真刀实战。

    引入vite插件

    • unplugin-icons
    • unplugin-vue-components
    • vite-plugin-svg-icons
    • @iconify/json
    • @iconify/vue
    1. # npm
    2. npm i -D @iconify/json @iconify/vue unplugin-icons vite-plugin-svg-icons unplugin-vue-components
    3. #yarn
    4. yarn add -D @iconify/json @iconify/vue unplugin-icons vite-plugin-svg-icons unplugin-vue-components
    5. #pnpm
    6. pnpm add -D @iconify/json @iconify/vue unplugin-icons vite-plugin-svg-icons unplugin-vue-components

    使用方式

    第一种:unplugin-icons

    配置vite插件:

    1. // 配置图标- unplugin-icons
    2. Icons({
    3. compiler: "vue3",
    4. customCollections: {
    5. ["local"]: FileSystemIconLoader(LOCAL_PATH, (svg: string) =>
    6. svg.replace(/^, '))
    7. },
    8. scale: 1,
    9. autoInstall: true,
    10. defaultClass: "inline-block"
    11. }),
    12. // 配置unplugin-vue-components
    13. Components({
    14. resolvers: [
    15. IconsResolver({
    16. prefix: "icon",
    17. customCollections: COLLECTION_NAME,
    18. }),
    19. ],
    20. }),
    1. 使用iconify图标作为载体显示:
    1. <icon-ep-bicycle style="font-size: 30px;color: #0C0C0C;background-color: #efafaf">icon-ep-bicycle>

    效果:

    图标解释:

    icon 为我们自定义的前缀

    ep-bicycle 为图标的名字,可以去iconify查询,将冒号 :更换横杠 - 。

            2. 使用本地svg图标作为载体显示

    下载svg图标文件,放在项目的 src/assets/icons/svg 目录下

    1. <icon-local-acrobat class="icons">icon-local-acrobat>
    2. <icon-local-control-center class="icons">icon-local-control-center>
    3. <icon-local-setting class="icons">icon-local-setting>

    效果:

    图标的样式部分可自行调整,演示的样式是我自定义的

    图标解释:

    icon-local-acrobat

    icon 为我们自定义的前缀

    local 为我们自定义的集合容器名,在配置vite时指定的

    acrobat 为图标文件的名字

    第二种:vite-plugin-svg-icons

    配置vite插件

    1. // 配置图标- vite-plugin-svg-icons
    2. createSvgIconsPlugin({
    3. // 指定需要缓存的图标文件夹
    4. iconDirs: [LOCAL_PATH],
    5. // 指定symbolId格式
    6. symbolId: `icon-[dir]-[name]`,
    7. inject: "body-last",
    8. customDomId: "__SVG_ICON_LOCAL__",
    9. })

    在main.ts中引入样式

    import "virtual:svg-icons-register";

    自定义SvgIcon组件方便图标的使用,这里我使用的是jsx的形式定义的组件,用vue定义的组件可以自行参照下面的形式写即可。

    1. import type {CSSProperties, PropType} from "vue";
    2. import {computed, defineComponent} from "vue";
    3. import {Icon} from "@iconify/vue";
    4. // horizontal: 水平翻转 ,vertical:垂直翻转
    5. type FlipType = "horizontal" | "vertical";
    6. // 数字代表旋转角度 0° 90° 180° 270°
    7. type RotateType = 0 | 1 | 2 | 3;
    8. /**
    9. * SvgIcon 组件
    10. * @date 2023/9/26
    11. */
    12. export default defineComponent({
    13. name: "SvgIcon",
    14. props: {
    15. // 图标名字
    16. icon: {
    17. type: String,
    18. required: true,
    19. default: "",
    20. },
    21. // 是否为本地 svg 图标
    22. isLocal: {
    23. type: Boolean,
    24. default: false,
    25. },
    26. // 图标大小
    27. size: {
    28. type: [Number, String],
    29. default: 14,
    30. },
    31. // 旋转角度
    32. rotate: {
    33. type: Number as PropType<RotateType>,
    34. default: 0,
    35. },
    36. // 图标翻转(水平翻转、垂直翻转)
    37. flip: String as PropType<FlipType>,
    38. // 图标旋转动画效果
    39. spin: {
    40. type: Boolean,
    41. default: false,
    42. },
    43. // 单独图标样式
    44. iconStyle: Object as PropType<CSSProperties>,
    45. // 图标颜色
    46. color: String,
    47. // 点击图标触发事件
    48. onClick: Function as PropType<(e: MouseEvent) => void>,
    49. },
    50. setup(props, {attrs}) {
    51. const bindAttrs = computed<{ class: string; style: string }>(() => ({
    52. class: (attrs.class as string) || "",
    53. style: (attrs.style as string) || "",
    54. }));
    55. const symbolId = () => `#icon-${props.icon}`;
    56. const rotate = [0, 90, 180, 270];
    57. const localIconStyle = {
    58. width: "1em",
    59. height: "1em",
    60. lineHeight: "1em",
    61. fontSize: `${`${props.size}`.replace("px", "")}px`,
    62. animation: props.spin ? "circle 3s infinite linear" : "",
    63. transform: (() => {
    64. const scale = props.flip
    65. ? props.flip == "vertical"
    66. ? "scaleY(-1)"
    67. : props.flip == "horizontal"
    68. ? "scaleX(-1)"
    69. : ""
    70. : "";
    71. return `rotate(${rotate[props.rotate]}deg) ${scale}`;
    72. })(),
    73. };
    74. const iconStyles = {outline: "none", animation: props.spin ? "circle 3s infinite linear" : ""};
    75. return () => (
    76. <b
    77. onClick={e => {
    78. props.onClick?.(e);
    79. }}
    80. class={["inline-block", bindAttrs.value.class, props.onClick ? "cursor-pointer" : ""]}
    81. style={bindAttrs.value.style}
    82. >
    83. {props.isLocal ? (
    84. <svg aria-hidden="true"
    85. style={props.iconStyle ? Object.assign(localIconStyle, props.iconStyle) : localIconStyle}>
    86. <use xlinkHref={symbolId()} fill="currentColor"/>
    87. svg>
    88. ) : (
    89. <Icon
    90. icon={props.icon}
    91. width={props.size}
    92. height={props.size}
    93. rotate={props.rotate}
    94. flip={props.flip}
    95. color={props.color}
    96. style={props.iconStyle ? Object.assign(iconStyles, props.iconStyle) : iconStyles}
    97. />
    98. )}
    99. b>
    100. );
    101. },
    102. });

    使用iconify图标

    1. <SvgIcon icon="ep:avatar" size="50" color="#000">SvgIcon>

    使用本地图标

    1. <SvgIcon icon="setting" size="50" is-local class="icons">SvgIcon>

    区别是使用本地svg图标时需要 isLocal 设置为true,其他的属性可自行摸索,在组件中也有相应的代码注释

    完整代码

    vite配置:

    1. import {fileURLToPath, URL} from 'node:url'
    2. import {defineConfig} from 'vite'
    3. import path from "path";
    4. import vue from '@vitejs/plugin-vue'
    5. import vueJsx from '@vitejs/plugin-vue-jsx'
    6. import Icons from "unplugin-icons/vite";
    7. import {FileSystemIconLoader} from "unplugin-icons/loaders";
    8. import {createSvgIconsPlugin} from "vite-plugin-svg-icons";
    9. import Components from "unplugin-vue-components/vite";
    10. import IconsResolver from 'unplugin-icons/resolver';
    11. /**
    12. * 获取项目根路径
    13. * @descrition 末尾不带斜杠
    14. */
    15. export function getRootPath() {
    16. return path.resolve(process.cwd());
    17. }
    18. /**
    19. * 获取项目src路径
    20. * @param srcName - src目录名称(默认: "src")
    21. * @descrition 末尾不带斜杠
    22. */
    23. export function getSrcPath(srcName = "src") {
    24. const rootPath = getRootPath();
    25. return `${rootPath}/${srcName}`;
    26. }
    27. const LOCAL_PATH = `${getSrcPath()}/assets/icons/svg`
    28. const COLLECTION_NAME = "local"
    29. // https://vitejs.dev/config/
    30. export default defineConfig({
    31. plugins: [
    32. vue(),
    33. vueJsx(),
    34. // 配置unplugin-vue-components
    35. Components({
    36. resolvers: [
    37. IconsResolver({
    38. prefix: "icon",
    39. customCollections: COLLECTION_NAME,
    40. }),
    41. ],
    42. }),
    43. // 配置图标- unplugin-icons
    44. Icons({
    45. compiler: "vue3",
    46. customCollections: {
    47. [COLLECTION_NAME]: FileSystemIconLoader(LOCAL_PATH, (svg: string) =>
    48. svg.replace(/^, '),
    49. ),
    50. },
    51. scale: 1,
    52. autoInstall: true,
    53. defaultClass: "inline-block",
    54. }),
    55. // 配置图标- vite-plugin-svg-icons
    56. createSvgIconsPlugin({
    57. // 指定需要缓存的图标文件夹
    58. iconDirs: [LOCAL_PATH],
    59. // 指定symbolId格式
    60. symbolId: `icon-[dir]-[name]`,
    61. inject: "body-last",
    62. customDomId: "__SVG_ICON_LOCAL__",
    63. })
    64. ],
    65. resolve: {
    66. alias: {
    67. '@':
    68. fileURLToPath(new URL('./src', import.meta.url))
    69. }
    70. }
    71. })

    SvgIcon组件:

    1. import type {CSSProperties, PropType} from "vue";
    2. import {computed, defineComponent} from "vue";
    3. import {Icon} from "@iconify/vue";
    4. // horizontal: 水平翻转 ,vertical:垂直翻转
    5. type FlipType = "horizontal" | "vertical";
    6. // 数字代表旋转角度 0° 90° 180° 270°
    7. type RotateType = 0 | 1 | 2 | 3;
    8. /**
    9. * SvgIcon 组件
    10. * @date 2023/9/26
    11. */
    12. export default defineComponent({
    13. name: "SvgIcon",
    14. props: {
    15. // 图标名字
    16. icon: {
    17. type: String,
    18. required: true,
    19. default: "",
    20. },
    21. // 是否为本地 svg 图标
    22. isLocal: {
    23. type: Boolean,
    24. default: false,
    25. },
    26. // 图标大小
    27. size: {
    28. type: [Number, String],
    29. default: 14,
    30. },
    31. // 旋转角度
    32. rotate: {
    33. type: Number as PropType<RotateType>,
    34. default: 0,
    35. },
    36. // 图标翻转(水平翻转、垂直翻转)
    37. flip: String as PropType<FlipType>,
    38. // 图标旋转动画效果
    39. spin: {
    40. type: Boolean,
    41. default: false,
    42. },
    43. // 单独图标样式
    44. iconStyle: Object as PropType<CSSProperties>,
    45. // 图标颜色
    46. color: {
    47. type: String,
    48. default: "#000",
    49. },
    50. // 点击图标触发事件
    51. onClick: Function as PropType<(e: MouseEvent) => void>,
    52. },
    53. setup(props, {attrs}) {
    54. const bindAttrs = computed<{ class: string; style: string }>(() => ({
    55. class: (attrs.class as string) || "",
    56. style: (attrs.style as string) || "",
    57. }));
    58. const symbolId = () => `#icon-${props.icon}`;
    59. const rotate = [0, 90, 180, 270];
    60. const localIconStyle = {
    61. width: "1em",
    62. height: "1em",
    63. lineHeight: "1em",
    64. fontSize: `${`${props.size}`.replace("px", "")}px`,
    65. animation: props.spin ? "circle 3s infinite linear" : "",
    66. transform: (() => {
    67. const scale = props.flip
    68. ? props.flip == "vertical"
    69. ? "scaleY(-1)"
    70. : props.flip == "horizontal"
    71. ? "scaleX(-1)"
    72. : ""
    73. : "";
    74. return `rotate(${rotate[props.rotate]}deg) ${scale}`;
    75. })(),
    76. };
    77. const iconStyles = {outline: "none", animation: props.spin ? "circle 3s infinite linear" : ""};
    78. return () => (
    79. <b
    80. onClick={e => {
    81. props.onClick?.(e);
    82. }}
    83. class={["inline-block", bindAttrs.value.class, props.onClick ? "cursor-pointer" : ""]}
    84. style={bindAttrs.value.style}
    85. >
    86. {props.isLocal ? (
    87. <svg aria-hidden="true"
    88. style={props.iconStyle ? Object.assign(localIconStyle, props.iconStyle) : localIconStyle}>
    89. <use xlinkHref={symbolId()} fill="currentColor"/>
    90. svg>
    91. ) : (
    92. <Icon
    93. icon={props.icon}
    94. width={props.size}
    95. height={props.size}
    96. rotate={props.rotate}
    97. flip={props.flip}
    98. color={props.color}
    99. style={props.iconStyle ? Object.assign(iconStyles, props.iconStyle) : iconStyles}
    100. />
    101. )}
    102. b>
    103. );
    104. },
    105. });

    main.ts 引入

    import "virtual:svg-icons-register";

    使用:

    1. <script setup lang="ts">
    2. import SvgIcon from "@/components/SvgIcon";
    3. script>
    4. <template>
    5. <main style="display: flex;flex-direction: column">
    6. <icon-ep-bicycle class="icons">icon-ep-bicycle>
    7. <icon-local-acrobat class="icons">icon-local-acrobat>
    8. <icon-local-control-center class="icons">icon-local-control-center>
    9. <icon-local-setting class="icons">icon-local-setting>
    10. <SvgIcon icon="ep:avatar" size="50">SvgIcon>
    11. <SvgIcon icon="setting" size="50" is-local class="icons">SvgIcon>
    12. main>
    13. template>
    14. <style scoped>
    15. .icons {
    16. font-size: 30px;
    17. color: #0C0C0C;
    18. background-color: #efafaf;
    19. margin: 20px;
    20. }
    21. style>

  • 相关阅读:
    SpringBoot+Vue的社区疫情防控管理系统|基于Python+Django的社区物资采购系统
    winform 自定义数值(数字)输入框
    【Javascript】运算符(赋值,算术,自增,自减)
    从系统设计到撸代码?我用了这些方法和工具
    【数据算法与结构】栈与队列篇
    天然气跟踪监管系统功能模块实现
    畅购商城_第15章-秒杀v-2.0
    willchange 优化性能的原理是什么
    Springboot毕设项目工商闲置单车销售平台2r343(java+VUE+Mybatis+Maven+Mysql)
    JPA 查询的类型
  • 原文地址:https://blog.csdn.net/WLPJLP/article/details/133681075