Vue3通过 directive 实现 el-dropdown下拉菜单项最小宽度等于内容宽度

文章目录

    • 1. 初始效果与最终效果
    • 2. 分析
    • 3. 解决思路:`directives`
    • 4. 代码实现
    • 小结

1. 初始效果与最终效果

原始效果 最终效果
Vue3通过 directive 实现 el-dropdown下拉菜单项最小宽度等于内容宽度_第1张图片 Vue3通过 directive 实现 el-dropdown下拉菜单项最小宽度等于内容宽度_第2张图片

2. 分析

el-dropdown API 并不提供配置项让我们实现下拉菜单项最小宽度等于内容宽度,但我们能发现它提供了 popper-class 用于自定义浮层类名。
那么我们是否可以通过 popper-class 配置项来实现想要的功能呢?或者通过 这种形式进行最小宽度的设置?

答案明显是可行的,但有个问题:这两种方式设置最小宽度是需要提前知道内容宽度的值,那么就得在编码的时候限定一个值,限制性太大了。


3. 解决思路:directives

既然我们知道了通过 popper-class 配置项是可以实现效果的,所以我们只需要解决内容宽度计算并且设置下拉框最小宽度即可。
查阅 Vue3 文档,发现 directive 这个 API 可以让我们自定义指令,使 el-dropdown 渲染的时候进行自定义计算,获取内容宽度的同时设置下拉框选项的最小宽度。


4. 代码实现

  1. 定义 siem-dropdown 指令
    注:这里是新建了一个 siemDropdown.js 文件进行指令定义,目录:siem/share/directives/siemDropdown

    function setDropdownMinWidth(el, binding, vNode) {
        const { props, uid } = vNode.ctx; // 获取下拉菜单实例的 uid 和 props
        const siemDropdownClass = `siem-dropdown-${uid}`;
        if (props.popperClass?.indexOf(siemDropdownClass) === -1) {
            props.popperClass += ` ${siemDropdownClass}`; // 添加自定义浮层类名 popper-class
        }
    
        if (el) {
            setTimeout(() => {
                const $dom = document.querySelectorAll(`.${siemDropdownClass}`)[0]; // 获取下拉菜单项浮层元素
                if (el?.offsetWidth) {
                    $dom.style.minWidth = el.offsetWidth + 'px'; // 设置最小宽度为下拉菜单内容宽度
                }
            }, 100);
        }
    }
    
    const siemDropdown = {
        mounted: setDropdownMinWidth,
        updated: setDropdownMinWidth,
    };
    
    export default siemDropdown;
    
    
  2. 全局绑定 siem-dropdown 指令

    import siemDropdown from 'siem/share/directives/siemDropdown';
    
    export default function bindAllConfigs(APP){
        APP.directive('siem-dropdown', siemDropdown); // 全局绑定 siem-dropdown 指令
    }
    
  3. el-dropdown 使用 siem-dropdown 指令

    <el-dropdown
         v-siem-dropdown 
         @command="handleBatchOperation"
         style="margin-left: 8px;"
     >
         <el-button>
             <span style="display: inline-flex; align-items: center;">
                 用于测试的更多操作很长很长
                 <el-icon>
                     <arrow-down />
                 el-icon>
             span>
         el-button>
         <template #dropdown>
             <el-dropdown-menu>
                 <el-dropdown-item command="test1">
                     测试1
                 el-dropdown-item>
                 <el-dropdown-item command="test2">
                     测试2222
                 el-dropdown-item>
                 <el-dropdown-item command="test3">
                     测试3
                 el-dropdown-item>
             el-dropdown-menu>
         template>
     el-dropdown>
    

小结

通过实现这个效果,学会了如何使用 directive,感觉还是很有收获的。
愿各位也能从中有所收获吧~~

你可能感兴趣的:(vue.js,前端,elementui)