element-plus
已经自带部分图标,不过图标数量并不多,因为是后台系统,可以考虑集成更多的图标,这里选择xicons
图标库里面的material
图标库。
目前图标库基本都是用组件的形式来使用图标,开始已经集成了element-plus
的图标,这里要安装xicons
。
安装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>
图标使用包装
为了方便使用,统一封装一个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"/>
最终开源地址: