从零搭建基于element-plus的Vue3项目05——统一图标封装

element-plus已经自带部分图标,不过图标数量并不多,因为是后台系统,可以考虑集成更多的图标,这里选择xicons图标库里面的material图标库。

目前图标库基本都是用组件的形式来使用图标,开始已经集成了element-plus的图标,这里要安装xicons

地址:https://www.xicons.org/#/

安装xicons图标

根据文档,选择安装:https://github.com/07akioni/xicons#installation

安装:npm i @vicons/material

注册组件

安装之后统一注册到app中,这里以插件的形式注册组件,注册成icon-xxx的形式,如果遇到同名的图标,加上一个前缀区分:

import * as ElementPlusIconsVue from '@element-plus/icons-vue' // element图标
import * as MaterialIconsVue from '@vicons/material' // xicons的material图标
import kebabCase from 'lodash/kebabCase'

export const INSTALL_ICONS = []
export const ICON_PREFIX = 'icon-'

const registryIconComponent = (app, key, component, prefix) => {
  let componentName = `${ICON_PREFIX}${kebabCase(key)}` // 组件名字
  if (app.component(componentName)) {
    key = `${prefix}${key}`
    componentName = `${ICON_PREFIX}${kebabCase(key)}`
  }
  INSTALL_ICONS.push(key)
  app.component(componentName, component)
}

export default {
  install (app) {
    for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
      registryIconComponent(app, key, component, 'El')
    }
    for (const [key, component] of Object.entries(MaterialIconsVue)) {
      registryIconComponent(app, key, component, 'Md')
    }
  }
}

在main.js中引入并use就可以了:

app.use(icons)

图标搜索工具

图标数量很多,如果直接把所有图标列在页面上使用会有性能问题,因此使用vue-virtual-scroller虚拟滚屏来提升性能。

安装vue-virtual-scroller

安装:npm install --save vue-virtual-scroller

地址:https://www.npmjs.com/package/vue-virtual-scroller

在main.js中引入:

import VueVirtualScroller from 'vue-virtual-scroller'
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'

Vue.use(VueVirtualScroller)

图标搜索页面

页面通过名字关键字过滤图标,选择图标后用vueuse提供的useClipboard来复制数据,大数据量用recycle-scroller来加速,否则页面会卡死。

<script setup>
import { computed, ref } from 'vue'
import { useClipboard } from '@vueuse/core'
import { ElMessage } from 'element-plus'
import { filterIconsByKeywords } from '@/services/icon/IconService'

const colSize = ref(8)
const keyWords = ref('')

const filterIcons = computed(() => {
  return filterIconsByKeywords(keyWords.value, colSize.value)
})

const copyIcon = (icon) => {
  const { copy, isSupported } = useClipboard()
  const iconStr = `<common-icon icon="${icon}"/>`
  if (isSupported) {
    copy(iconStr)
    ElMessage({
      message: `Copied: ${iconStr}`,
      type: 'success'
    })
  } else {
    ElMessage({
      message: `Copy Not supported: ${iconStr}`,
      type: 'error'
    })
  }
}

</script>

<template>
  <el-container
    class="icon-container"
  >
    <el-header height="40px">
      <el-form label-width="120px">
        <el-form-item :label="$t('common.label.keywords')">
          <el-input
            v-model="keyWords"
            :placeholder="$t('common.msg.inputKeywords')"
          />
        </el-form-item>
      </el-form>
    </el-header>
    <el-main>
      <recycle-scroller
        v-slot="{ item }"
        class="scroller icon-list"
        :items="filterIcons"
        :item-size="80"
        key-field="id"
      >
        <el-row>
          <el-col
            v-for="icon in item.icons"
            :key="icon"
            :span="24/colSize"
            class="text-center"
          >
            <a
              class="el-button el-button--large is-text icon-a"
              @click="copyIcon(icon)"
            >
              <div>
                <common-icon
                  size="20"
                  :icon="icon"
                />
                <br>
                <span class="icon-text">{{ icon }}</span>
              </div>
            </a>
          </el-col>
        </el-row>
      </recycle-scroller>
    </el-main>
  </el-container>
</template>

<style scoped>
.scroller, .icon-container  {
  height: 100%;
}
.icon-container .el-input {
  width: 80%;
}
.icon-a {
  height:80px;
  display: block;
  width:100%;
  overflow:hidden;
  padding: 15px 10px;
}
.icon-a span {
  font-size: 12px;
}
</style>

image-20240113185604731

图标使用包装

为了方便使用,统一封装一个common-icon组件,在el-icon基础上包装一层,统一使用图标组件

<script setup>
import { computed } from 'vue'
import { ICON_PREFIX } from '@/icons'
import kebabCase from 'lodash/kebabCase'

const props = defineProps({
  icon: {
    type: String,
    required: false
  }
})
const calcIcon = computed(() => {
  if (props.icon) {
    return `${ICON_PREFIX}${kebabCase(props.icon)}`
  }
  return props.icon
})
</script>

<template>
  <el-icon
    v-if="calcIcon"
    v-bind="$attrs"
  >
    <component
      :is="calcIcon"
    />
  </el-icon>
</template>

使用:

<common-icon icon="HomeFilled"/>

最终开源地址:

https://github.com/fugary/simple-element-plus-template

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇