乐趣区

实现-Enter-键切换表单内-input-元素焦点

写登录注册功能时, 在一个输入框输入完毕后, 习惯性按下 Enter 键来切换到下一个输入框, 但是此时这个功能我还没有实现 …emm

尝试一 (搁浅)

既然 Tab 键可以切换焦点, 那么将 Tab 键的功能转接到 Enter 键上不就好了嘛, 也就是表面按下的是 Enter 键, 但 “ 实际 ” 按下的是 Tab 键, 于是试图通过人造事件 (synthetic events) 来实现.

创建与触发事件: https://developer.mozilla.org…

父组件: (在这个尝试中没排上用场, 可以不看)

<template>   
  <div id="login-box"> 
    <mo-form class="login-form">
      <mo-form-item>
        <mo-input
          type="text" 
          text="用户名" 
          v-model="loginInfo.username"     
          ></mo-input>        
      </mo-form-item>
      <mo-form-item>
        <mo-input
          type="password" 
          text="密码" 
          v-model="loginInfo.password"        
          ></mo-input>        
      </mo-form-item>      
    </mo-form>
  </div>    
</template>

子组件 mo-input : (看最后四个键盘事件监听即可)

<template>
  <div class="mo-input">
    <span class="text">{{text}}: </span>
    <input :type="type" class="input"
      :class="{focused: isFocused}"           
      @focus="isFocused = true" @blur="isFocused = false"
      :value="value"
      @change="$emit('change', $event.target.value)"
      @keyup.enter.prevent="moveFocus"    
      @keydown.tab="tabClick"
      @keypress.tab="tabClick"
      @keyup.tab="tabClick"
      >   
  </div>
</template>
methods: {
// moveFocus 方法监听在 input 输入框中按下 Enter 键
    moveFocus(e){console.log(e)
      const key = {
        key: 'Tab',
        code: 'Tab',
        keyCode: '9'
      }
      const e1 = new KeyboardEvent('keydown', key)
      const e2 = new KeyboardEvent('keypress', key)
      const e3 = new KeyboardEvent('keyup', key)
      e.currentTarget.dispatchEvent(e1)    
      e.currentTarget.dispatchEvent(e2)    
      e.currentTarget.dispatchEvent(e3) 
    },
    tabClick(e){console.log(e)
      console.log(e.currentTarget)
      console.log('tabClick')
    }
}

在第一个输入框中按下 Enter 键:

结果: 三个事件均发送成功, 并可以成功监听, 但是并没有出现 Tab 键切换焦点的效果.


接着, 按 Tab 键:

结果: 第一个输入框发生 keydown 事件; 第二输入框发生 keyup 事件. 也就是之前的想法是错的, 按下 Tab 键并不是触发了三个事件

这个不知道怎么模拟, 使用另一个感觉简单一些的按键 — 字母 A 键 — 试一试

// 修改事件监听
@keyup.enter.prevent="moveFocus"    
@keydown="aClick"
@keypress="aClick"
@keyup="aClick"  

// 修改 moveFocus 方法中的 key 对象
const key = {
  key: 'a',
  code: 'KeyA',
  keyCode: '65'
}

// 修改事件处理函数
aClick(e){if(e.key == 'a'){console.log(e)
    console.log(e.currentTarget)
    console.log('aClick') 
  }
}

结果: 正常按下 A 键会发生 keydown, keypress, keyup 事件, 但是反过来按下 Enter 键人工触发这三个事件并不会在输入框中 “ 写出 ” a, 要自己在事件处理函数中为 e.currentTarget.value 赋值才行

aClick(e){if(e.key == 'a' && e.type == "keyup"){e.currentTarget.value += e.key}      
}

目前看来, 这条路走不通.

尝试二 (成功)

找到当前聚焦的元素和下一个要聚焦的元素, 使用 focus()
在输入框中按下 Enter 键后发送自定义事件到父组件; 父组件通过 ref 获取 mo-form 组件实例, 该实例的 $el 属性中最前面的数字键值对, 就是可聚焦的元素 (console.dir 可以看到, console.log 打印出 DOM 结构)

父组件:

<template>   
  <div id="login-box"> 
    <mo-form class="login-form" ref="formRef">
      <mo-form-item>
        <mo-input
          type="text" 
          text="用户名" 
          v-model="loginInfo.username"
          @moveFocus="moveFocus"
          ></mo-input>        
      </mo-form-item>
      <mo-form-item>
        <mo-input
          type="password" 
          text="密码" 
          v-model="loginInfo.password"        
          ></mo-input>        
      </mo-form-item>      
    </mo-form>
  </div>    
</template>
methods: {   
// moveFocus 方法实现焦点切换
    moveFocus(){ 
      const form = this.$refs.formRef
      const active = document.activeElement
      let flag = true
      let key = 0
      while(flag){if(form.$el[key] == active){
          flag = false         
          form.$el[key + 1].focus()}else{key ++}
      }
    }
}

mo-input 子组件:

<template>
  <div class="mo-input">
    <span class="text">{{text}}: </span>
    <input :type="type" class="input"
      :class="{focused: isFocused}"           
      @focus="isFocused = true" @blur="isFocused = false"
      :value="value"
      @change="$emit('change', $event.target.value)"
      @keyup.enter.prevent="moveFocus"     
      >   
  </div>
</template>
methods: {
// moveFocus 方法监听在 input 输入框中按下 Enter 键
  moveFocus(e){this.$emit('moveFocus')
  }
}
退出移动版