Skip to content

图标选择器

架构

bash
├── src
   ├── components
   ├── chooseIcon
      ├── lib (引入的第三方库)
    └── xxx.json
      ├── src (源码)
   ├── index.vue
      ├── index.ts

index.ts

ts
import { type App } from 'vue'
import chooseIcon from './src/index.vue'

// 让这个组件可以通过use的形式使用
export default {
    install(app: App) {
        app.component('YJ-choose-icon', chooseIcon)
    }
}

hooks/chooseIcon/useIcon

  • useIcon.ts
ts

import { ElMessage } from 'element-plus'
export const useIcon = () => {
    // 写一个方法复制内容到剪贴板
    const copyToClipboard = (text: string, callback: (arg: boolean) => void) => {
        navigator.clipboard
            .writeText(text)
            .then(() => {
                ElMessage.success('复制成功')
                callback(false)
            })
            .catch(error => {
                ElMessage.error('复制失败')
                callback(false)
            })
    }

    return {
        copyToClipboard
    }
}

类型

  • interfaces/chooseIcon/type.ts
ts
export interface Idata {
    title: String
    visible: Boolean
    width: Number
    height: Number
}

src/index.vue

  • Object as PropType<Idata> 这个类型是ts的语法,表示将对象类型转换为Idata类型
vue
<template>
    <div>
        <el-button type="primary" @click="changevisable(true)">
            <slot></slot>
        </el-button>
        <!--弹出框开始-->

        <el-dialog
            v-model="props.data.visible"
            :title="props.data.title"
            :width="props.data.width"
            :height="props.data.height"
        >
            <el-scrollbar :height="props.data.height">
                <div class="icon-list">
                    <div v-for="item in iconList" :key="item" class="icon-item">
                        <div class="icon" @click="chooseIcon(item)">
                            <el-icon :size="30">
                                <component :is="item"></component>
                            </el-icon>
                            <div>{{ item }}</div>
                        </div>
                    </div>
                </div>
            </el-scrollbar>
        </el-dialog>
        <!--弹出框结束-->
    </div>
</template>

<script setup lang="ts">
    import { defineProps, defineEmits, defineExpose, ref, watch, computed, type PropType } from 'vue'
    import { type Idata } from '@/interfaces/chooseIcon/type'
    import * as ElementPlusIconsVue from '@element-plus/icons-vue'
    import { toLine } from '@/utils/tools'
    import { useIcon } from '@/hooks/chooseIcon/useIcon'
    const { copyToClipboard } = useIcon()
    const props = defineProps({
        data: {
            type: Object as PropType<Idata>,
            required: true
        }
    })
    // 改变父元素
    const emits = defineEmits(['changedatavisible'])
    const changevisable = (content: boolean) => {
        emits('changedatavisible', content)
    }
    // 图标列表
    const iconList = computed(() => {
        const result = []
        for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
            result.push(`el-icon${toLine(key)}`)
        }
        return result
    })
    // 选择图标,传递进来回调函数
    const chooseIcon = (icon: string) => {
        let text = `<${icon}></${icon}>`
        copyToClipboard(text, changevisable)
    }
</script>

<style scoped lang="scss">
    .icon-list {
        display: flex;
        flex-wrap: wrap;
        .icon-item {
            width: 25%;
            height: 100px;
            display: flex;
            justify-content: center;
            align-items: center;
            cursor: pointer;
            .icon {
                display: flex;
                flex-direction: column;
                justify-content: center;
                align-items: center;
            }
        }
    }
</style>

父元素调用

vue
<template>
    <div>
        图标选择
        <YJ-choose-icon :data="data" @changedatavisible="changevisible">
            选择图标
            <el-icon-setting class="el-icon--right"></el-icon-setting>
        </YJ-choose-icon>
    </div>
</template>

<script setup lang="ts">
    import { ref } from 'vue'
    import { type Idata } from '@/interfaces/chooseIcon/type'
    const data = ref<Idata>({
        title: '图标选择',
        visible: true,
        width: 800,
        height: 450
    })
    const changevisible = (content: boolean) => {
        data.value.visible = content
    }
</script>

<style scoped></style>