elementUI使用vue-direction-key实现键盘上下左右bug解决办法

本文介绍了一个使用Vue-direction-key库实现输入框焦点在页面元素间切换的解决方案,特别针对Element UI的select和date组件存在的问题进行了修复。作者通过监听键盘按键事件,动态调整焦点,并处理select的展开、关闭以及date picker的隐藏,以实现流畅的导航效果。代码中包含了针对上下左右四个方向的焦点移动逻辑,并提供了具体的代码片段作为示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近要求输入框上下左右能实现输入框焦点切换的效果,在网上查了下决定使用vue-direction-key来实现功能,但是实际使用发现vue-direction-key配合element的select和date组件使用有问题,比如select无法展开、切换、关闭,然后对direction.on的方法进行修改,最后实现了功能。

页面部分代码,注意x和y必须严格从0开始加1,我没做跳多个的判断,select和date分别使用type,date还需要配置dateIndex和ref

<el-form :model="ruleForm" :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"
          v-if="dialogVisible">


          <section>
            <div class="row">
              <el-form-item label="筛选条件" label-width="100px">
                <el-input v-direction="{x: 0, y: 0,type:'input'}" v-model="searchPaient" placeholder="健康id,证件号,姓名,手机号"  @input="nameChange"
                  @click.native.stop="nameChange"></el-input>
                <div class="paientList" v-show="isShow && searchList.length>0">
                  <div class="item" v-for="item in searchList" :key="item.id" @click="setPaient(item)">
                    {{item.realName}}
                  </div>
                </div>
              </el-form-item>
            </div>
            <div class="title">
              基本信息
            </div>

            <div class="row">
              <div class="inputBox">
                <el-form-item label="姓名" prop="realName">
                  <el-input v-direction="{x: 0, y: 1,type:'input'}" v-model="ruleForm.realName"></el-input>
                </el-form-item>
              </div>
              <div class="inputBox">
                <el-form-item label="证件类型" prop="cardType">
                  <el-select v-direction="{x: 1, y: 1,type:'select'}" v-model="ruleForm.cardType" placeholder="" style="width: 120px;">
                    <el-option v-for="item in cardTypeArr" :key="item.standardCode" :label="item.dictName"
                      :value="item.standardCode">
                    </el-option>
                  </el-select>
                </el-form-item>
              </div>
              <div class="inputBox">
                <el-form-item label="证件号" prop="idCard">
                  <el-input v-direction="{x: 2, y: 1,type:'input'}" v-model="ruleForm.idCard" placeholder="" @input="getBir"></el-input>
                </el-form-item>
              </div>


            </div>
            <div class="row">
              <div class="inputBox">
                <el-form-item label="性别" prop="accountSex">
                  <el-select v-direction="{x: 0, y: 2,type:'select'}" v-model="ruleForm.accountSex" placeholder="" style="width: 100px;" @change="sexChange">
                    <el-option v-for="item in sexArr" :key="item.standardCode" :label="item.dictName"
                      :value="item.standardCode">
                    </el-option>
                  </el-select>
                </el-form-item>
              </div>
              <div class="inputBox">
                <el-form-item label="出生日期" prop="birthday">
                <!--   <el-input v-direction="{x: 2, y: 1,type:'input'}" v-model="ruleForm.idCard" placeholder="" @input="getBir" type="date"></el-input> -->
                 <el-date-picker v-direction="{x: 1, y: 2,type:'date',dateIndex:1}" ref="date1" v-model="ruleForm.birthday" type="date" placeholder="" style="width: 200px;"
                    @change="dateChange" value-format="yyyy-MM-dd" :picker-options="pickerBeginDateBefore" >
                  </el-date-picker>
                </el-form-item>
              </div>

修改direction.on代码

  created() {
    let direction = this.$getDirection()
    direction.on('keyup', (e, val) => {
      e.preventDefault()
      console.log($(document.activeElement).parents('.el-input,.el-select'));
      console.log(direction)
      let activeNode = $(document.activeElement).parents('.el-input,.el-select')[1] ? $(document.activeElement)
        .parents('.el-input,.el-select')[1] : $(document.activeElement).parents('.el-input,.el-select')[0];
      let nodeArrayActive;
      let x, y;
      let nodeArr = direction.nodeArray;
      nodeArr.forEach(item => {
        item.forEach((item2) => {
          if (item2.node == activeNode) {
            nodeArrayActive = item2;
            x = item2.value.x;
            y = item2.value.y;
          }
        })
      })
      // 右
      if (e.keyCode === 39) {
        x += 1;
        let nextIndex = nodeArr[y].findIndex(item => {
          return item.value.x == x && item.value.y == y
        })
        if (nextIndex != -1) {
          $(nodeArr[y][nextIndex].node).find('input').focus()
          if (nodeArr[y][nextIndex].value.type == 'select') {
            nodeArr[y][nextIndex].node["__vue__"].toggleMenu()
          }

          if(nodeArrayActive.value.type=='date'){

            this.$refs['date'+nodeArrayActive.value.dateIndex].hidePicker()

          }
          activeNode["__vue__"].blur();
        } else {
          x = 0;
          y += 1;
          if (nodeArr.length - 1 >= y) {
            let nextIndexRow = nodeArr[y].findIndex(item => {
              return item.value.x == x && item.value.y == y
            })
            console.log(nextIndexRow)
            if (nextIndexRow != -1) {
              $(nodeArr[y][nextIndexRow].node).find('input').focus();
              if (nodeArr[y][nextIndexRow].value.type == 'select') {
                nodeArr[y][nextIndexRow].node["__vue__"].toggleMenu()
              }
              if(nodeArrayActive.value.type=='date'){

                this.$refs['date'+nodeArrayActive.value.dateIndex].hidePicker()

              }
              activeNode["__vue__"].blur();
            } else {
              return;
            }
          }
        }
      }
      // 左
      if (e.keyCode === 37) {
        x -= 1;
        if (x >= 0) {
          let nextIndex = nodeArr[y].findIndex(item => {
            return item.value.x == x && item.value.y == y
          })
          if (nextIndex != -1) {

            $(nodeArr[y][nextIndex].node).find('input').focus();
            if (nodeArr[y][nextIndex].value.type == 'select') {
              nodeArr[y][nextIndex].node["__vue__"].toggleMenu()
            }
            if(nodeArrayActive.value.type=='date'){

              this.$refs['date'+nodeArrayActive.value.dateIndex].hidePicker()

            }

            activeNode["__vue__"].blur();

          } else {
            return

          }
        } else {
          y -= 1;
          if (y >= 0) {
            x = nodeArr[y][nodeArr[y].length - 1].value.x;
            let nextIndexRow = nodeArr[y].findIndex(item => {
              return item.value.x == x && item.value.y == y
            })
            console.log(nextIndexRow, x, y)
            if (nextIndexRow != -1) {
              $(nodeArr[y][nextIndexRow].node).find('input').focus();
              if (nodeArr[y][nextIndexRow].value.type == 'select') {
                nodeArr[y][nextIndexRow].node["__vue__"].toggleMenu()
              }
              if(nodeArrayActive.value.type=='date'){

                this.$refs['date'+nodeArrayActive.value.dateIndex].hidePicker()

              }

              activeNode["__vue__"].blur();
            }
          }
        }
      }
      // 上
      if (e.keyCode === 38) {
        y -= 1;
        if (y >= 0) {
          let nextIndexRow = nodeArr[y].findIndex(item => {
            return item.value.x == x && item.value.y == y
          })
          if (nextIndexRow != -1) {
            $(nodeArr[y][nextIndexRow].node).find('input').focus();
            if (nodeArr[y][nextIndexRow].value.type == 'select') {
              nodeArr[y][nextIndexRow].node["__vue__"].toggleMenu()
            }
            if(nodeArrayActive.value.type=='date'){

              this.$refs['date'+nodeArrayActive.value.dateIndex].hidePicker()

            }

            activeNode["__vue__"].blur();
          } else {
            x = 0;
            let nextIndexCol = nodeArr[y].findIndex(item => {
              return item.value.x == x && item.value.y == y
            })
            if (nextIndexCol != -1) {
              $(nodeArr[y][nextIndexCol].node).find('input').focus();
              if (nodeArr[y][nextIndexCol].value.type == 'select') {
                nodeArr[y][nextIndexCol].node["__vue__"].toggleMenu()
              }
              if(nodeArrayActive.value.type=='date'){

                this.$refs['date'+nodeArrayActive.value.dateIndex].hidePicker()

              }

              activeNode["__vue__"].blur();
            }
          }
        }

      }
      // 下
      if (e.keyCode === 40) {
        y += 1;
        if (y <= nodeArr.length - 1) {
          let nextIndexRow = nodeArr[y].findIndex(item => {
            return item.value.x == x && item.value.y == y
          })
          if (nextIndexRow != -1) {
            $(nodeArr[y][nextIndexRow].node).find('input').focus();
            if (nodeArr[y][nextIndexRow].value.type == 'select') {
              nodeArr[y][nextIndexRow].node["__vue__"].toggleMenu()
            }
            if(nodeArrayActive.value.type=='date'){

              this.$refs['date'+nodeArrayActive.value.dateIndex].hidePicker()

            }

            activeNode["__vue__"].blur();
          } else {
            x = 0;
            let nextIndexCol = nodeArr[y].findIndex(item => {
              return item.value.x == x && item.value.y == y
            })
            if (nextIndexCol != -1) {
              $(nodeArr[y][nextIndexCol].node).find('input').focus();
              if (nodeArr[y][nextIndexCol].value.type == 'select') {
                nodeArr[y][nextIndexCol].node["__vue__"].toggleMenu()
              }
              if(nodeArrayActive.value.type=='date'){

                this.$refs['date'+nodeArrayActive.value.dateIndex].hidePicker()

              }

              activeNode["__vue__"].blur();
            }
          }
        }
      }
    })
  },

由于是项目比较急搞得,有一些地方处理没有太好,基本就只是实现自己的目的,但基本通过这种方法能实现功能,基本思路就是通过节点和direction的nodeArr去操作聚焦,失焦,关闭,其中date我发现只能通过强行去操作ref去关闭,否则使用nodeArrayActive[“vue”]关闭一次后,就调用不了hidePicker方法,至于其他的框和类型,暂时还没做,以后有时间再做修改吧,只是提供一个思路,不一定适用所有人项目

### 关于 Vue3 Seamless Scroll 插件的文字抖动问题 文字抖动问题是许多开发者在使用 `vue3-seamless-scroll` 或其他类似的无缝滚动插件时可能会遇到的一个常见现象。这种问题通常由以下几个原因引起: #### 1. **CSS 属性设置不当** 如果未正确设置 CSS 的属性,可能导致渲染过程中出现视觉上的不连贯效果。例如,某些浏览器可能对 `transform` 和 `transition` 的处理方式不同,从而引发抖动。 解决方法之一是确保所有的动画都通过 GPU 加速来完成。可以通过添加以下样式到滚动容器中来优化性能[^1]: ```css .seamless-container { will-change: transform; backface-visibility: hidden; } ``` #### 2. **帧率不足** 当设备无法维持高刷新率(通常是 60fps)时,也可能导致滚动过程中的卡顿或抖动。这可能是由于计算量过大或其他资源占用引起的。 为了缓解这一问题,可以尝试减少每秒更新次数或将数据分批加载以降低 DOM 更新频率[^2]。具体操作可以在初始化参数时调整速度选项: ```javascript options: { step: 0.8, // 控制滚动的速度 limitMoveNum: 5 // 当显示列数小于该数值时不触发滚动 } ``` #### 3. **版本兼容性** 有时,特定版本的库可能存在 bug 导致异常行为。建议查看官方仓库是否有已知 issue 并升级至最新稳定版[^3]。例如,在 GitHub 上搜索关键词 “jitter” 或者 “flicker”,了解社区反馈并应用补丁修复方案。 另外需要注意的是,虽然当前项目名为 `vue3-seamless-scroll` ,但其实际依赖关系和功能实现细节仍需参照文档说明确认是否存在差异之处[^4]。 以下是完整的代码片段展示如何正确集成及调优此组件: ```html <template> <div class="seamless-wrap"> <vue-seamless-scroll :data="scrollData" :class-option="optionSingleHeightTime"> <ul class="item-list"> <li v-for="(item,index) in scrollData" :key="index">{{ item }}</li> </ul> </vue-seamless-scroll> </div> </template> <script> import vueSeamlessScroll from 'vue-seamless-scroll'; export default { components: { vueSeamlessScroll }, data() { return { scrollData: ['Item A', 'Item B', 'Item C'], optionSingleHeightTime: { singleHeight: 0, waitTime: 1500, hoverStop: true, direction: 1, openWatch: true, switchDelay: 3000, autoPlay: true, speed: 60 } }; } }; </script> <style scoped lang="scss"> @import url('~vue-seamless-scroll/vue-seamless.css'); .seamless-wrap { height: 200px; /* 设置固定高度 */ } .item-list li { line-height: normal !important; white-space: nowrap; &::after{ content:""; clear:both;display:block; } } /* 添加平滑过渡效果 */ .seamless-container .seamless-content ul { transition-timing-function: linear!important ; } </style> ``` --- ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值