优雅的在Vue3 Vite3中模仿element-plus的图标使用方式

优雅的在Vue3 Vite3中模仿element-plus的图标使用方式

  • 最终实现效果
  • 使用Vue对svg文件进行封装
    • 准备文件
      • 直接将svg代码写入vue文件
      • 利用自己封装的SvgIcon简化代码,保持svg文件的可读性
    • 在main.js中注入所有相关文件
  • 在注入时批量对svg文件进行封装简化【推荐】

最终实现效果

使用效果如下

<el-button icon="el-icon-send" type="primary">
 新增
el-button>

使用Vue对svg文件进行封装

准备文件

直接将svg代码写入vue文件

about.vue

<template>
    <svg class="icon" viewBox="0 0 1229 1024" xmlns="http://www.w3.org/2000/svg" width="240.039" height="200">
        <path d="M727.59 511.004C817.748 467.99 880.387 375.63 880.387 268.53 880.387 120.549 761.052.147 614.391.147S348.4 120.549 348.4 268.53c0 107.098 62.674 199.46 152.792 242.474-224.396 55.89-328.166 277.36-328.166 485.41 0 14.89 11.962 26.876 26.643 26.876 14.76 0 26.68-12.027 26.68-26.876 0-214.47 121.399-445.341 388.01-445.341 266.604 0 388.004 230.871 388.004 445.341 0 14.89 11.96 26.876 26.678 26.876 14.721 0 26.643-12.027 26.643-26.876.074-208.051-103.656-429.522-328.093-485.41M401.72 268.53c0-118.315 95.37-214.583 212.67-214.583 117.297 0 212.675 96.268 212.675 214.583 0 118.276-95.376 214.511-212.675 214.511-117.301 0-212.67-96.235-212.67-214.511"/>
        <path d="M289.591 493.675c12.114-1.162 21.894-10.48 23.806-22.626 1.877-12.147-4.674-24.098-15.868-28.931-5.364-2.321-130.794-58.097-120.828-189.135C188.124 103.764 349.2 85.703 356.177 84.966c14.607-1.428 25.34-14.541 23.924-29.32-1.38-14.812-14.225-25.601-29.058-24.25C277.56 38.475 135.42 93.01 123.5 248.847c-7.324 96.924 44.313 166.582 95.411 207.43-88.82 31.206-234.37 119.899-216.354 364.072 1.034 14.118 12.728 24.947 26.523 24.947.692 0 1.347 0 2.039-.077 14.68-1.121 25.719-14.041 24.607-28.854-21.62-293.563 223.52-321.686 233.865-322.69m815.579-244.827C1093.283 93.05 951.185 38.513 877.702 31.397c-14.76-1.318-27.679 9.477-29.06 24.213-1.415 14.773 9.355 27.928 24 29.356 6.86.655 167.9 17.87 179.358 167.978 10.01 131.04-115.456 186.853-120.708 189.098-11.23 4.797-17.787 16.667-15.952 28.812 1.803 12.146 11.615 21.581 23.73 22.781 10.43 1.009 255.568 29.125 233.95 322.655-1.111 14.813 9.926 27.726 24.608 28.848.69.083 1.345.083 2.033.083 13.8 0 25.494-10.792 26.527-24.947 18.052-244.097-127.497-332.79-216.354-363.997 51.1-40.923 102.77-110.505 95.336-207.43z"/>
    svg>
template>

利用自己封装的SvgIcon简化代码,保持svg文件的可读性

send.vue

<template>
  <svg-icon icon-class="send" />
template>
<script>
export default {
  name: 'send'
}
script>

在main.js中注入所有相关文件

/**
 * 使用vue嵌套svg文件之后将其批量注册全局组件,支持在类似el-button的icon属性中直接书写el-icon-edit使用edit.svg图标文件。
 * @param app 当前程序上下文
 */
export function importSvgVue(app) {
  const importFn = import.meta.glob('./svgs/*', { eager: true })
  console.log(importFn)
  // 批量注册全局组件
  Object.keys(importFn).forEach(key => {
    let icon = key.substring(key.lastIndexOf('/') + 1, key.lastIndexOf('.'))
    icon = icon.substring(0, 1).toUpperCase() + icon.substring(1)
    console.log(icon, importFn[key])
    // 导入组件
    const component = importFn[key].default
    console.log(component)
    // 注册组件
    app.component(`ElIcon${icon}`, component)
  })
}

在注入时批量对svg文件进行封装简化【推荐】

import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from 'vue'

/**
 * 将svg文件批量注册全局组件,支持在类似el-button的icon属性中直接书写el-icon-edit使用edit.svg图标文件。
 * @param app 当前程序上下文
 */
export function importSvg(app) {
  const importFn = import.meta.glob('./svg/*', { as: 'raw' })
  console.log(importFn)
  const components_exports_temp = {}
  for (const icon in importFn) {
    const fileName = icon.substring(icon.lastIndexOf('/') + 1, icon.lastIndexOf('.'))
    const iconName = fileName.substring(0, 1).toUpperCase() + fileName.substring(1)

    components_exports_temp[iconName] = () => createSvgIconComponent(iconName, fileName)
  }
  const components_exports = {}
  __export(components_exports, components_exports_temp)

  for (const [key, component] of Object.entries(components_exports)) {
    console.log(key, component)
    app.component(`ElIcon${key}`, component)
  }
}

/**
 * 创建svgIcon组件
 * 参考自{@link @element-plus/icons-vue/dist/index.js}
 * @param iconName  图标名称:Send
 * @param fileName  文件名称:send
 * @return {ComponentOptionsBase<{}, any, any, any, any, any, any, any> & ThisType>>}
 */
function createSvgIconComponent(iconName, fileName) {
  function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
    const svgAttr = {
      class: 'svg-icon'
    }; const useNode = _createElementVNode('use', {
      href: `#icon-${fileName}`
    }); const children = [
      useNode
    ]
    return (_openBlock(), _createElementBlock('svg', svgAttr, children))
  }
  const vue_type_script_lang_default = {
    name: iconName
  }
  return export_helper_default(vue_type_script_lang_default, [['render', _sfc_render], ['__file', `${iconName}.vue`]])
}

/**
 * 参考自{@link @element-plus/icons-vue/dist/global.js}
 * @type {(o: T, p: PropertyKey, attributes: (PropertyDescriptor & ThisType)) => T}
 * @private
 */
const __export = (target, all) => {
  for (const name in all) {
    Object.defineProperty(target, name, { get: all[name], enumerable: !0 })
  }
}

/**
 * 参考自{@link @element-plus/icons-vue/dist/global.js}
 * @param sfc
 * @param props
 * @return {ComponentOptionsBase<{}, any, any, any, any, any, any, any> & ThisType>>}
 */
const export_helper_default = (sfc, props) => {
  // unplugin-vue:/plugin-vue/export-helper
  const target = sfc.__vccOpts || sfc
  for (const [key, val] of props) {
    target[key] = val
  }
  return target
}

你可能感兴趣的:(JS,Vue,前端,vue.js,javascript,前端)