目录
使用elementPlus图标
在项目中引入
npm install @element-plus/icons-vue
import 'element-plus/dist/index.css'
import * as ElementPlusIconsVue from '@element-plus/icons-vue'
// 图标
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
app.component(key, component)
}
方法一(动态使用图标):
<el-icon>
<component :is="menu.meta.icon" class="icon"></component>
</el-icon>
方法二(直接使用图标):
然后直接使用
<el-icon><Expand /></el-icon>
具体详细图标可查看:https://element-plus.gitee.io/zh-CN/component/icon.html
自定义图标
1、创建src/icons/svg目录,将自己的图标放入此文件夹内。
2、npm install svg-sprite-loader --save-dev (实现加载svg自定义组件)
npm i svgo@1.0.5 svgo-loader@2.2.0 --save-dev (自动去除图标中的fill)
3、配置vue.config.js,没有在项目根目录新建一个即可
const path = require("path");
function resolve (dir) {
return path.join(__dirname, dir);
}
module.exports = {
chainWebpack: config => {
// 清除svg默认配置对./src/icons文件夹的处理
config.module
.rule("svg")
.exclude.add(resolve("src/icons")) // icons存放地(svg放的地方)
.end()
// 添加新的rule处理./src/icons文件夹的svg文件
config.module
.rule("svg-sprite")
.test(/\.svg$/)
.include
.add(resolve("src/icons"))
.end()
.use("svg-sprite-loader")
.loader("svg-sprite-loader")
.options({
symbolId: "icon-[name]",
include: ["src/assets/icons"]
})
.end()
//去除fill
.before("svg-sprite-loader")
.use("svgo-loader")
.loader("svgo-loader")
.options({
plugins: [
{ removeAttrs: { attrs: "fill" } }
]
})
.end()
},
}
5、 创建src/components/svg,封装svg组件
<template>
<div
v-if="External"
:style="styleExternalIcon"
class="svg-external-icon svg-icon"
v-bind="$attrs"
/>
<svg v-else :class="svgClass" aria-hidden="true" v-bind="$attrs">
<use :xlink:href="symbolId" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
import { defineComponent, reactive, ref, computed } from 'vue'
export default defineComponent({
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
setup (props) {
const External = computed(() => {
return isExternal(props.iconClass)
})
const symbolId = computed(() => {
return `#icon-${props.iconClass}`
})
const svgClass = computed(() => {
if (props.className) {
return 'svg-icon ' + props.className
} else {
return 'svg-icon'
}
})
const styleExternalIcon = computed(() => {
return {
mask: `url(${props.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${props.iconClass}) no-repeat 50% 50%`
}
})
return {
External,
symbolId,
svgClass,
styleExternalIcon,
}
}
})
</script>
<style scoped>
.svg-icon {
width: 1.4em;
height: 1.4em;
margin: 0 0 0 2px;
vertical-align: -0.1em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover !important;
display: inline-block;
}
</style>
其中utils/validate.ts
/**
* Created by PanJiaChen on 16/11/18.
*/
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path: string) {
const isExternal = /^(https?:|http?:|mailto:|tel:)/.test(path);
return isExternal;
}
6、使用全局注册,这样就不用图标一个一个引入了,创建src/icons/index.ts
import SvgIcon from '@/components/svg/index.vue' // svg component
/**
* 一次性的引入某个文件夹下的所有文件
* require.context(directory, useSubdirectories,regExp)
* 形参:
* directory:需要引入文件的目录
* useSubdirectories:是否查找该目录下的子级目录
* regExp:匹配引入文件的正则表达式
*/
const registerSvgIcon = (app: any) => {
app.component('svg-icon', SvgIcon) // 注册全局组件
const req = require.context('./svg', false, /\.svg$/);
const requireAll = (requireContext: any) => requireContext.keys().map(requireContext);
requireAll(req);
}
export default registerSvgIcon;
5、main.ts引入
import registerSvgIcon from "@/icons/index";
const app = createApp(App)
registerSvgIcon(app)
6、页面使用
在所需页面中也需要引入svgIcon组件
<SvgIcon icon-class="yonghu"/>
侧边栏自定义图标的应用
侧边栏使用图标的时候需要判断一下,使用的是自定义图标还是elementPlus图标。
像elementUI图标他每一个图标都是以el-icon开头的,所以只要判断一下图标是否包含‘el-icon’,不包含的就是自定义图标。而elementPlus图标相反,所以我们可以在自定义图标前添加一个标识即可。
我这里没有使用render进行对图标封装,因为我还没弄明白怎么返回elementPlus图标,所以有大佬如果知道,还请留言指教
重点代码:
<!-- 判断有没有图标并且是否是自定义图标,有就展示,没有则去除icon的位置 -->
<SvgIcon
v-if="
item.meta && item.meta.icon && item.meta.icon.includes('icon-')
"
:icon-class="item.meta.icon"
/>
<el-icon v-else>
<component
v-if="item.meta && item.meta.icon"
:is="item.meta.icon"
class="icon"
></component>
</el-icon>
完整代码:
<template>
<div v-if="!item.meta || !item.meta.hide">
<!-- 一级 -->
<template
v-if="
hasOneShowingChild(item.children, item) &&
(!onlyOneChild.children || onlyOneChild.noShowingChildren) &&
(!item.meta || !item.alwaysShow)
"
>
<app-link v-if="item.meta" :to="item.path">
<el-menu-item
:index="item.children ? item.children[0].path : item.path"
:class="{ 'submenu-title-noDropdown': item.class_true }"
>
<!-- 判断有没有图标并且是否是自定义图标,有就展示,没有则去除icon的位置 -->
<SvgIcon
v-if="
item.meta && item.meta.icon && item.meta.icon.includes('icon-')
"
:icon-class="item.meta.icon"
/>
<el-icon v-else>
<component
v-if="item.meta && item.meta.icon"
:is="item.meta.icon"
class="icon"
></component>
</el-icon>
<template #title>
{{ item.meta.title }}
</template>
</el-menu-item>
</app-link>
</template>
<!-- 二级 -->
<template v-else>
<el-sub-menu ref="subMenu" :index="item.path" popper-append-to-body>
<template #title>
<SvgIcon
v-if="
item.meta && item.meta.icon && item.meta.icon.includes('icon-')
"
:icon-class="item.meta.icon"
/>
<el-icon v-else>
<component
v-if="item.meta && item.meta.icon"
:is="item.meta.icon"
class="icon"
></component>
</el-icon>
<span>{{ item.meta.title }}</span>
</template>
<el-menu-item-group>
<SidebarItem
v-for="v in item.children"
:item="v"
:key="v.path"
:base-path="v.path"
:is-nest="true"
></SidebarItem>
</el-menu-item-group>
</el-sub-menu>
</template>
</div>
</template>
<script>
import { defineComponent, reactive, ref } from 'vue'
import AppLink from './Link.vue'
import SvgIcon from "@/components/svg/index.vue";
import Item from './item.vue'
export default defineComponent({
name: 'SidebarItem',
components: {
AppLink,
SvgIcon,
Item
},
props: {
item: {
type: Object,
required: true,
},
isNest: {
type: Boolean,
required: false,
},
basePath: {
type: String,
required: true,
},
},
setup () {
const onlyOneChild = ref();
function hasOneShowingChild (children, parent) {
if (!children) {
children = [];
}
const showingChildren = children.filter((item) => {
if (item.meta && item.meta.hide) {
return false;
} else {
// Temp set(will be used if only has one showing child)
onlyOneChild.value = item;
return true;
}
});
// When there is only one child router, the child router is displayed by default
if (showingChildren.length === 1) {
return true;
}
// Show parent if there are no child router to display
if (showingChildren.length === 0) {
onlyOneChild.value = { ...parent, path: '', noShowingChildren: true };
return true;
}
return false;
}
return {
onlyOneChild,
hasOneShowingChild,
}
}
})
</script>
<style lang="scss">
.icon {
font-size: 20px;
}
.submenu-title-noDropdown {
color: #3fa9f5;
}
</style>
vite+vue3+ts中使用自定义图标
1、创建src/icons/svg目录,将自己的图标放入此文件夹内。
2、下载插件
npm i vite-plugin-svg-icons -D
3、vite.config.ts 中的配置插件
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from "path";
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
createSvgIconsPlugin({
// 指定需要缓存的图标文件夹
iconDirs: [path.resolve(process.cwd(), 'src/icons')],
// 指定symbolId格式
symbolId: 'icon-[dir]-[name]',
}),
],
})
4、main.ts
import 'virtual:svg-icons-register'
5、 创建src/components/svg,封装svg组件
<template>
<div
v-if="External"
:style="styleExternalIcon"
class="svg-external-icon svg-icon"
v-bind="$attrs"
/>
<svg v-else :class="svgClass" aria-hidden="true" v-bind="$attrs">
<use :xlink:href="symbolId" />
</svg>
</template>
<script>
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage
import { isExternal } from '@/utils/validate'
import { defineComponent, reactive, ref, computed } from 'vue'
export default defineComponent({
name: 'SvgIcon',
props: {
iconClass: {
type: String,
required: true
},
className: {
type: String,
default: ''
}
},
setup (props) {
const External = computed(() => {
return isExternal(props.iconClass)
})
const symbolId = computed(() => {
return `#icon-${props.iconClass}`
})
const svgClass = computed(() => {
if (props.className) {
return 'svg-icon ' + props.className
} else {
return 'svg-icon'
}
})
const styleExternalIcon = computed(() => {
return {
mask: `url(${props.iconClass}) no-repeat 50% 50%`,
'-webkit-mask': `url(${props.iconClass}) no-repeat 50% 50%`
}
})
return {
External,
symbolId,
svgClass,
styleExternalIcon,
}
}
})
</script>
<style scoped>
.svg-icon {
width: 1.4em;
height: 1.4em;
margin: 0 0 0 2px;
vertical-align: -0.1em;
fill: currentColor;
overflow: hidden;
}
.svg-external-icon {
background-color: currentColor;
mask-size: cover !important;
display: inline-block;
}
</style>
其中utils/validate.ts
/**
* Created by PanJiaChen on 16/11/18.
*/
/**
* @param {string} path
* @returns {Boolean}
*/
export function isExternal(path: string) {
const isExternal = /^(https?:|http?:|mailto:|tel:)/.test(path);
return isExternal;
}
6、全局注册mian.ts
import 'virtual:svg-icons-register'
import SvgIcon from "@/components/svg/index.vue";
const app = createApp(App)
app.use(store)
.use(router)
.use(ElementPlus)
.component('svg-icon', SvgIcon)
.mount("#app");
7、页面使用
在所需页面中也需要引入svgIcon组件
<SvgIcon icon-class="yonghu"/>