vue3+element-plus icons图标选择组件封装

一、最终效果

二、参数配置

1、代码示例

html 复制代码
<t-select-icon v-model="selectVlaue" />

2、配置参数(Attributes)继承 el-input Attributes

参数 说明 类型 默认值
v-model 绑定值 string -
prefixIcon 输入框前缀icon string Search
isShowSearch 是否显示搜索图标 Boolean true
isShowIcon 是否显示选中后的图标 Boolean true
selectBind Attributes selectBind "prefix-icon": props.prefixIcon, placeholder: "请选择图标",dialogTitle:'请选择图标',clearable: true,width: "50%"

3、events

事件名 说明 返回值
select 选择完图标 返回选中的图标name

三、源码

html 复制代码
<template>
  <div class="t_select_icon">
    <el-input
      ref="inputRef"
      v-model="valueIcon"
      v-bind="attrs"
      @clear="clearIcon"
      @click="
        () => {
          ;(dialogVisible = true), (inputValue = '')
        }
      "
    >
      <template #append v-if="isShowIcon">
        <el-button :icon="customIcons[modelValue]" />
      </template>
    </el-input>
    <el-dialog v-model="dialogVisible" :title="attrs.dialogTitle" draggable :width="attrs.width">
      <el-input
        v-model="inputValue"
        v-if="isShowSearch"
        :placeholder="attrs.searchPlaceholder"
        clearable
        :prefix-icon="Icons.Search"
      />
      <el-scrollbar v-if="Object.keys(iconsList).length">
        <div class="icon-list">
          <div
            v-for="item in iconsList"
            :key="item"
            class="icon-item"
            :class="{ 'icon-active': item.name == valueIcon }"
            @click="selectIcon(item)"
          >
            <component :is="item"></component>
            <span>{{ item.name }}</span>
          </div>
        </div>
      </el-scrollbar>
      <el-empty :description="attrs.emptyDescription" v-else />
    </el-dialog>
  </div>
</template>

<script setup lang="ts" name="TSelectIcon">
import { ref, computed, useAttrs } from "vue"
import * as Icons from "@element-plus/icons-vue"

const props = defineProps({
  modelValue: {
    type: String,
    default: ""
  },
  prefixIcon: {
    type: String,
    default: "Search"
  },
  selectBind: Object,
  isShowSearch: {
    type: Boolean,
    default: true
  },
  isShowIcon: {
    type: Boolean,
    default: true
  }
})
const emit = defineEmits(["update:modelValue", "select"])
// v-model简写
let valueIcon = computed({
  get() {
    return props.modelValue
  },
  set(val) {
    // console.log("v-model简写", val);
    emit("update:modelValue", val)
  }
})
const $attrs: any = useAttrs()
const attrs = computed(() => {
  const selectBind = {
    "prefix-icon": customIcons[props.prefixIcon],
    placeholder: "请选择图标",
    dialogTitle: "请选择图标",
    searchPlaceholder: "搜索图标",
    emptyDescription: "未搜索到您要找的图标",
    clearable: true,
    width: "50%",
    ...props.selectBind
  }
  return { ...$attrs, ...selectBind }
})
// open Dialog
const dialogVisible = ref(false)

// 选择图标
const selectIcon = (item: any) => {
  dialogVisible.value = false
  valueIcon.value = item.name
  emit("update:modelValue", item.name)
  emit("select", item.name)
}

// 清空图标
const inputRef = ref()
const clearIcon = () => {
  valueIcon.value = ""
  emit("update:modelValue", "")
  setTimeout(() => inputRef.value.blur(), 0)
}

// 监听搜索框值
const inputValue = ref("")
const customIcons: { [key: string]: any } = Icons
const iconsList = computed((): { [key: string]: any } => {
  if (!inputValue.value) return Icons
  let result: { [key: string]: any } = {}
  for (const key in customIcons) {
    if (key.toLowerCase().indexOf(inputValue.value.toLowerCase()) > -1)
      result[key] = customIcons[key]
  }
  return result
})
</script>

<style scoped lang="scss">
.t_select_icon {
  width: 100%;
  .el-button {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    color: var(--el-text-color-regular);
    :deep(.el-icon) {
      color: var(--el-color-primary);
    }
  }
  :deep(.el-dialog__body) {
    padding: 25px 20px 20px;
    .el-input {
      margin-bottom: 10px;
    }
    .icon-list {
      display: grid;
      grid-template-columns: repeat(auto-fill, 115px);
      justify-content: space-evenly;
      max-height: 60vh;
      .icon-item {
        display: flex;
        flex-direction: column;
        align-items: center;
        width: 42px;
        padding: 20px 30px;
        cursor: pointer;
        transition: all 0.2s;
        svg {
          width: 30px;
          height: 30px;
        }
        &:hover {
          transform: scale(1.3);
        }
        &.icon-active {
          color: var(--el-color-primary);
        }
        span {
          margin-top: 5px;
          line-height: 20px;
          text-align: center;
        }
      }
    }
  }
}
</style>

六、组件地址

gitHub组件地址

gitee码云组件地址

七、相关文章

基于ElementUi&antdUi再次封装基础组件文档


vue3+ts基于Element-plus再次封装基础组件文档

相关推荐
xChive3 小时前
优化表单交互:在 el-select 组件中嵌入表格显示选项
前端·vue.js·交互·element-plus
半度℃温热5 天前
ERROR TypeError: AutoImport is not a function
webpack·vue3·element-plus·插件版本·autoimport
朝阳396 天前
vue3 中直接使用 JSX ( lang=“tsx“ 的用法)
vue3·tsx·jsx
xcLeigh6 天前
VUE3实现简洁的特色美食网站源码
前端·源码·vue3
邱自强8 天前
el-table 行列文字悬浮超出屏幕宽度不换行的问题
el-table·element-plus·el-tooltip
陈逸子风9 天前
(系列十一)Vue3框架中路由守卫及请求拦截(实现前后端交互)
vue3·webapi·权限·流程·表单
爱分享的Hayes小朋友10 天前
如何用post请求调用Server-Sent Events服务
前端·vue3·sse·post
getaxiosluo12 天前
vue3使用element-plus,树组件el-tree增加引导线
前端·javascript·vue.js·elementui·css3·element-plus
Coisini_甜柚か12 天前
打字机效果显示
前端·vue3·antv
Modify_QmQ12 天前
初识Electron & 进程通信
electron·vue3·桌面端