【Vue3】elementPlus图标和自定义侧边栏图标

目录

使用elementPlus图标

自定义图标

侧边栏自定义图标的应用

vite+vue3+ts中使用自定义图标


使用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"/>
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Vue 3 中使用 Element Plus 表单进行自定义规则检验可以通过以下步骤来完成: 1. 在组件中引入需要使用的 Element Plus 组件和验证规则。 ```javascript import { ElForm, ElFormItem, ElInput, ElButton } from 'element-plus'; import { defineComponent, ref } from 'vue'; import { required, email } from 'element-plus/es/utils/validate'; ``` 2. 在模板中使用 Element Plus 表单组件和表单项组件。 ```html <template> <el-form :model="form" ref="form" :rules="rules" label-width="80px"> <el-form-item label="用户名" prop="username"> <el-input v-model="form.username"></el-input> </el-form-item> <el-form-item label="邮箱" prop="email"> <el-input v-model="form.email"></el-input> </el-form-item> <el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> </el-form-item> </el-form> </template> ``` 3. 在组件中定义表单数据和验证规则。 ```javascript export default defineComponent({ name: 'FormDemo', components: { ElForm, ElFormItem, ElInput, ElButton }, setup() { const form = ref({ username: '', email: '' }); const rules = { username: [ { required: true, message: '请输入用户名', trigger: 'blur' }, { min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' } ], email: [ { required: true, message: '请输入邮箱地址', trigger: 'blur' }, { validator: emailValidator, trigger: 'blur' } ] }; // 自定义邮箱验证规则 const emailValidator = (rule, value, callback) => { if (value && !email(value)) { callback(new Error('请输入正确的邮箱地址')); } else { callback(); } }; const submitForm = () => { const formRef = refs.form; formRef.validate((valid) => { if (valid) { // 验证通过 } else { // 验证不通过 } }); }; return { form, rules, submitForm }; } }); ``` 在以上代码中,我们使用了 Element Plus 中自带的 `required` 和 `email` 验证规则,并且自定义了邮箱验证规则 `emailValidator`。在 `submitForm` 方法中调用 `formRef.validate` 方法来验证表单数据是否符合要求。如果验证通过,执行相应的操作;否则,提示用户错误信息。 这就是使用 Vue 3 和 Element Plus 进行表单自定义规则检验的基本流程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值