用户鼠标右击出现自定义菜单

本文讲述了作者如何在Vue应用中实现一个右键菜单,包括防止浏览器默认右键行为、动态定位菜单、处理input输入状态和焦点切换问题,以及遇到的bug和优化方案,如使用span和input切换以提高性能。
摘要由CSDN通过智能技术生成

需求:

        老板希望通过右键的菜单选项,来实现对数据的操作,其中有一个菜单的功能---重命名需要默认将input中的文字全部选中,并且输入时input样式也会变。

我的解决方案:

        生成一个menu,通过鼠标右键传递的事件对象控制menu的位置

基本操作:

        因为是第一次做这个功能,我的menu内部是嵌套的原生input标签,涉及到了很多问题

        1.需要阻止浏览器默认的右击行为(弹出默认的菜单)---@contextmenu.prevent

        2.@contextmenu鼠标右击的事件---实际上1.2可以合在一起

        3.菜单的动态位置(希望用户只要在限定区域内,菜单永远保持在鼠标右下角)

                通过vue结合内链样式---:style="`position: absolute;top: ${topVal}px;left:${leftVal}px;`"  

是不是感觉很简单!很快就完成了一个菜单   

//主体的html代码
//每一个v-row都是一个选项,注意这并不是菜单选项,而是单纯的一个列表,待交互的(这里我就只截取主要)
          <v-row
            v-for="(page, index) in pages"
            :key="page.id"
            class="item"
            tabindex="0"
            @contextmenu.prevent
            @contextmenu="handleRightClick($event, index, page)"
            @click="onPageClick(page.id)"
          >
            <v-col class="item-name">
              <input
                ref="myInput"
                class="text-input-default"
                :readonly="isdisabled"
                :value="page.name"
                @blur="blurInput"
                @keydown="inputKeydown"
              />
            </v-col>

------------------------------------------------
    //菜单部分代码实现
            <p-menu
              :style="`position: absolute;top: ${topVal}px;left:${leftVal}px;`"
              :model-value="控制这个菜单的显示与隐藏"
              :items="菜单中的选项"
            ></p-menu>

         在input标签内部禁用输入状态,这里之所以不使用disabled而是使用readonly是因为一个需求:老板希望用户右键时菜单弹出,但是input标签在禁用状态下,是无法触发事件(click等等),所以导致无法触发事件去控制menu菜单的显示,所以这里选择了readonly。

bug以及知识点

        知识点:

                1.整体功能是实现是利用vue实现的,涉及到input获取焦点和失去的焦点时样式的切换问题,并且还牵扯到一个问题,样式的切换应该采用切换焦点样式来做即(获取焦点时是一个样式,失去焦点时就恢复默认样式)但是在实际场景中发现,用户输入的只是input标签,但是样式改变却是外层的div所以,我们应该通过原生js的形式去删除和添加样式,那么这里就涉及到了通过ref选择对应的dom元素

// 通过ref获取到指定的祖先(父)元素dom---除了可以获取class以外id和标签名也是可以获取到dom的
myInput.value[selsectIndex.value].closest('.item')

// js的方式添加样式(.classList.add) 这里的selectFocus就是样式
myInput.value[selsectIndex.value].closest('.item').classList.add('selectFocus');

// js的形式取消样式(.classList.remove)
myInput.value[selsectIndex.value].closest('.item').classList.remove('selectFocus');

// 

                2.通过ref获取到当前dom然后通过类获取到祖先元素的dom

// 其中.item是祖先元素class属性,当然你也可以通过标签等形似
myInput.value[selsectIndex.value].closest('.item')

                 3.用户点击菜单选项(重命名后,input文本框内容默认全选并自动获取焦点立刻输入)

// 这里展示的是通过dom实现
myInput.value[selsectIndex.value].focus();// 当前dom获取焦点
myInput.value[selsectIndex.value].select();// 当前dom文本内容默认全选!

     

bug

                1.用户点击更改名称后,确实是高亮了,但是input失去焦点后居然还在高亮

                解决方案:使用 window.getSelection().removeAllRanges() 方法清除选中的文本范围。

//解决bug (通过select()全选文字,当失去焦点后,这个默认的样式依然高亮)
  window.getSelection().removeAllRanges();

                2.文本框默认获取焦点和文字全选,不生效

                解决方案:1.在setTimeout中执行即可

                                  2.老板给我说,最好别用setTimeout,因为它的执行时机不确定,可以用nextTick来做,确实也是一样的

// 这里的问题是,第一次重命名无法全选并且获取不了焦点(不执行)
// 添加setTimeout可以
setTimeout(() => {
   myInput.value[selsectIndex.value].focus();
   myInput.value[selsectIndex.value].select();
}, 0);

-----------------------------------

老板建议我通过切换span 和input来做,想了想确实,在单个标签中判断太多了,还是切换两个标签,一个输入一个展示(菜单逻辑还是一样,就是input标签哪里,改成与span切换)

1.同时生成input和span标签,通过切换父元素的class类,完成display的none和block,可以提升性能,不用在频繁的操作js来实现样式控制

2.项目中通过.closest去获取祖先元素的dom更是不行,它会去遍历整体的效率不好,还是直接绑定一个父的ref来控制

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值