vue3+element-plus实现图标选择器

见题知意,效果如下所示:

在这里插入图片描述
在这里插入图片描述
如上所示,该组件有两种模式,分别为输入框模式(input)及按钮模式(button),可根据不同的需求传入相应的模式参数。

具体代码如下:

<template>
  <div class="icon-select-container relative" :style="{ width }">
    <el-input
      v-if="type === 'input'"
      v-model="selectValue"
      placeholder="点击选择图标"
      v-click-outside="clickOutside"
      readonly
      ref="selectRef"
    >
      <template #prepend>
        <svg-icon :name="selectValue" />
      </template>
    </el-input>
    <el-button v-else v-click-outside="clickOutside" ref="selectRef">
      <svg-icon :name="selectValue" />
      <span class="ml-4px">{{ selectValue || '点击选择图标' }}</span>
    </el-button>
    <el-popover
      shadow="none"
      ref="popoverRef"
      :virtual-ref="selectRef"
      virtual-triggering
      placement="bottom-end"
      trigger="click"
      :teleported="false"
      :width="width"
    >
      <el-input v-model="searchValue" placeholder="输入名称搜索图标" />
      <el-divider border-style="dashed" />
      <el-scrollbar :height="scrollbarHeight">
        <ul class="icon-list m-0 pl-10px">
          <template v-for="icon in filterIcons" :key="icon">
            <el-tooltip effect="dark" :content="icon" placement="top">
              <li
                class="icon-item p-5px mr-10px mb-10px w-10% cursor-pointer"
                @click="selectIcon(icon)"
              >
                <svg-icon :name="icon" />
              </li>
            </el-tooltip>
          </template>
        </ul>
      </el-scrollbar>
    </el-popover>
  </div>
</template>

<script setup lang="ts">
import { ClickOutside as vClickOutside } from 'element-plus';

defineOptions({
  name: 'iconSelect',
});

const prop = withDefaults(
  defineProps<{
    modelValue: string;
    type?: 'input' | 'button'; // 选择元素类型
    width?: string; // 容器宽度
    scrollbarHeight?: string; // 滚动高度
  }>(),
  {
    type: 'input',
    width: '100%',
    scrollbarHeight: '200px',
  }
);
const emit = defineEmits(['update:modelValue']);

// useVModel 为 vueuse中封装的hook,强烈推荐使用vueuse
const selectValue = useVModel(prop, 'modelValue', emit);
const selectRef = ref();
const searchValue = ref('');
const popoverRef = ref();

// 点击其它区域隐藏 popover 弹窗
function clickOutside() {
  unref(popoverRef).popperRef?.delayHide?.();
}

// 加载所有svg图标
const icons: string[] = [];
function loadIcons() {
  const svgs = import.meta.glob('../assets/svgs/*.svg');
  for (const icon in svgs) {
    const iconName = icon.split('assets/svgs/')[1].split('.svg')[0];
    icons.push(iconName);
  }
}
loadIcons();

const filterIcons = computed(() =>
  icons.filter((item) => item.includes(searchValue.value))
);
// 选则图标
function selectIcon(icon: string) {
  selectValue.value = icon;
  popoverRef.value?.hide();
  searchValue.value = '';
}
</script>

<style lang="scss" scoped>
.icon-list {
  display: flex;
  flex-wrap: wrap;
  list-style: none;

  .icon-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-items: center;
    border: 1px solid #ccc;

    &:hover {
      color: var(--el-color-primary);
      border-color: var(--el-color-primary);
      transition: all 0.2s;
      transform: scaleX(1.1);
    }
  }
}
</style>

代码中类名的书写像 relative、mr-10px等等结尾css原子化写法,代码中其依赖包为 unocss

使用示例

<template>
  <div class="text-20px">
    <icon-select
      v-model="iconStr"
      width="520px"
      type="button"
      class="my-10px"
    />
    <icon-select v-model="iconStr" width="520px" />
  </div>
</template>

<script setup lang="ts">
// 图标选择
const iconStr = ref();
</script>

<style lang="scss" scoped></style>

更多详情可以查看项目在线地址,更希望能共同开发为这个项目添加各种功能,有意者可留言联系

<think>好的,我现在需要帮用户解决在Vue3Element Plus实现el-drawer组件的拖拽功能的问题。首先,我应该回忆一下el-drawer组件的基本用法和特性。el-drawer是一个侧边栏抽屉组件,通常用于导航或显示额外内容。用户想要实现拖拽功能,可能是指通过拖动某个元素来打开或关闭抽屉,或者调整抽屉的大小或位置。 接下来,我需要考虑如何结合Vue3的响应式系统和Element Plus组件方法。用户提到的拖拽功能,可能需要用到HTML5的拖放API或者鼠标事件监听。根据引用[2]中提到的拖拽事件,如dragstart、dragend等,可能需要监听这些事件来触发el-drawer的状态变化。 不过,el-drawer本身可能不支持拖拽调整大小或位置,所以可能需要自定义指令或者手动处理鼠标事件。例如,当用户点击并拖动某个手柄时,调整抽屉的宽度或位置。这时候需要用到mousedown、mousemove和mouseup事件来处理拖拽逻辑。 另外,引用[3]提到在dialog组件中去掉遮罩层后操作底层页面,可能涉及到修改组件的模态属性。虽然el-drawer和dialog不同,但可能需要类似的属性设置,比如是否显示遮罩层,或者在拖拽时允许与底层页面交互。 现在需要设计一个示例代码,可能的结构是:在el-drawer的标题栏添加一个可拖拽的区域,当用户拖动时调整抽屉的宽度。使用Vue3的composition API,比如ref来存储抽屉的宽度和拖拽状态,然后在mousedown事件中开始监听mousemove和mouseup事件,根据鼠标移动的距离调整宽度。 需要注意的几个点: 1. 拖拽开始时,记录初始宽度和鼠标位置。 2. 拖拽过程中,计算鼠标移动的差值,更新抽屉宽度。 3. 拖拽结束后,移除事件监听,避免内存泄漏。 4. 样式调整,确保拖拽区域的可视化反馈,比如光标变为调整大小形状。 另外,可能需要处理边界情况,比如最小和最大宽度限制,防止抽屉过小或过大。同时,考虑组件卸载时的事件监听清理,避免潜在的问题。 最后,确保代码符合Vue3Element Plus的最佳实践,比如使用setup语法糖、正确的组件绑定等。测试示例代码是否在拖拽时平滑调整宽度,并且与其他功能(如打开/关闭)兼容。</think>### Vue3 + Element Plus实现el-drawer拖拽功能 #### 实现思路 1. 通过鼠标事件监听实现拖拽交互 2. 使用CSS3的`cursor: ew-resize`显示可拖拽标识 3. 动态计算抽屉宽度变化 4. 处理边界值防止过度拉伸 #### 示例代码 ```vue <template> <el-button @click="drawerVisible = true">打开可拖拽抽屉</el-button> <el-drawer v-model="drawerVisible" title="可拖拽抽屉" :size="width + &#39;px&#39;" direction="rtl" class="custom-drawer" > <!-- 拖拽手柄 --> <div class="drag-handle" @mousedown="startDrag" ></div> <div class="content"> <p>拖拽左侧边框调整宽度(最小300px,最大800px)</p> </div> </el-drawer> </template> <script setup> import { ref } from &#39;vue&#39; const drawerVisible = ref(false) const width = ref(400) const isDragging = ref(false) let startX = 0 let startWidth = 0 const startDrag = (e) => { isDragging.value = true startX = e.clientX startWidth = width.value document.addEventListener(&#39;mousemove&#39;, onDrag) document.addEventListener(&#39;mouseup&#39;, stopDrag) } const onDrag = (e) => { if (!isDragging.value) return const deltaX = e.clientX - startX let newWidth = startWidth - deltaX // 限制宽度范围 newWidth = Math.max(300, Math.min(newWidth, 800)) width.value = newWidth } const stopDrag = () => { isDragging.value = false document.removeEventListener(&#39;mousemove&#39;, onDrag) document.removeEventListener(&#39;mouseup&#39;, stopDrag) } </script> <style scoped> .drag-handle { position: absolute; left: -5px; top: 0; width: 10px; height: 100%; cursor: ew-resize; z-index: 100; } .custom-drawer :deep(.el-drawer__header) { margin-bottom: 20px; } .content { padding: 20px; } </style> ``` #### 实现说明 1. **拖拽手柄**:通过绝对定位在抽屉左侧创建10px宽的拖拽区域,设置`cursor: ew-resize`显示水平调整光标 2. **事件监听**:使用`@mousedown`启动拖拽,通过`mousemove`计算宽度变化,`mouseup`结束拖拽 3. **边界控制**:通过`Math.max`和`Math.min`限制宽度在300-800px范围内 4. **性能优化**:使用CSS的`will-change: transform`提升动画性能(可根据需要添加) #### 注意事项 1. 添加`:modal="false"`可允许拖拽时操作底层页面(参考引用[3]的模态框处理逻辑) 2. 使用`direction="rtl"`实现从右侧滑出抽屉 3. 深度选择器`:deep()`用于覆盖Element Plus组件样式
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值