【问题标题】:Input cursor jumps to end of input field on input event输入光标在输入事件上跳转到输入字段的末尾
【发布时间】:2019-08-24 00:11:42
【问题描述】:

我正在尝试在输入事件中将用户输入转换为大写

所以,每当我在输入字段中键入一个键时,我都会遇到以下问题

  1. 当用户在中间输入时,光标会跳到输入值的末尾。
  2. 最后输入的字符(不是最后一个字符)未转换为大写。

这里是 JS fiddle https://jsfiddle.net/aeL051od/ 的链接以重现问题

new Vue({
  el: "#app",
  data() {
    return {
      input: null
    }
  },
  methods: {
    handleInput(e) {
      this.input = e.target.value ?
        e.target.value.toString().toUpperCase() :
        e.target.value;
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <input type="text" v-model="input" @input="handleInput"> {{ input }}
  <!-- {{ input }} is just for reference -->
</div>

【问题讨论】:

  • 您能解释一下变量inputevent 的用途吗?因为似乎设置了错误的值
  • @anurupr input 是存储用户输入的输入值的 v-model,event 是存储在@input 上发出的事件
  • 预期输出是什么?当您键入每个字母时,显示部分中的每个字母都应该大写吗?
  • @TejaD 所以您希望数据以大写形式存储在input 中?还是您想要用户输入的原始输入?
  • @MabehAl-ZuqYadeek 我希望用户输入的值全部大写(大写),当用户将光标移动到字母之间的某个位置并键入一个字符时,光标位置不应该跳到输入的末尾。

标签: javascript html vue.js


【解决方案1】:

{{ event ? event.target.value : null }}在这里显示目标值。

您必须显示转换后的input 值。应该如下所示

 <div id="app">
      <input type="text" v-model="input" @input="handleInput">
      <p>{{ input }}</p>
    </div>

对于光标跳转问题,在开始时获取光标的位置,然后在更新值后将光标设置回起始位置

  handleInput(e) {
          var start = e.target.selectionStart;
            this.input = this.input.toUpperCase()
          this.$nextTick(()=>{
                  e.target.selectionStart = e.target.selectionEnd = start;
                    })
        }

小提琴:https://jsfiddle.net/r53ecug6/

【讨论】:

  • 我已经更新了问题,但这并没有解决问题
  • 用光标修复问题更新了答案。更新了小提琴jsfiddle.net/r53ecug6
  • 你的新小提琴我仍然面临同样的问题
【解决方案2】:

如果您(或 Vue)将新值复制到输入中,则光标将设置到输入的末尾。如果要保留之前的位置,则需要先捕获位置,进行更改,然后在$nextTick 上恢复位置。

还要注意,如果您要在处理程序中设置this.input,那么使用v-model 也是没有意义的。保存event 也不太明智,但您可以。

new Vue({
  el: "#app",
  data() {
    return {
      input: null,
      event: null
    }
  },
  methods: {
    handleInput(e) {
      const el = e.target;
      const sel = el.selectionStart;
      const upperValue = el.value.toUpperCase();

      el.value = this.input = upperValue;
      this.event = e;
      this.$nextTick(() => {
        el.setSelectionRange(sel, sel);
      });
    }
  }
});
#app {
  background: #fff;
  border-radius: 4px;
  padding: 20px;
  transition: all 0.2s;
}

input {
  margin-bottom: 20px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <input type="text" @input="handleInput">
  <p>{{ event ? event.target.value : null }}</p>
  <p>
    {{input}}
  </p>
</div>

【讨论】:

  • 使用 CSS text-transform: uppercase; 怎么样,这种方法有什么缺点吗?这是小提琴jsfiddle.net/wq1otb0e
  • text-transform: uppercase; 这不会改变input 变量中的数据。在其他功能上使用时,您必须转换输入数据。
  • 我可能遗漏了一些明显的东西,但this.event = e;handleInput(e) 内部的目的是什么?
  • 仅用于填充我在显示中使用的event 数据项。只是证明它可以保存和使用。
【解决方案3】:

我能够解决您的问题,但您需要在代码中引入一个新变量

HTML:

<div id="app">
   <input type="text" v-model="input" @input="handleInput">
   <p>{{ updated_value }}</p>
</div>

JS:

new Vue({
   el: "#app",
   data() {
       return {
           input: null,
           updated_value: null
       }
   },
   methods: {
       handleInput(e) {
           this.input = e.target.value;
           this.updated_value = e.target.value ? e.target.value.toString().toUpperCase() 
         : e.target.value;
       }
   }
});

Link to fiddle

总结:
1) 使用新变量 (updated_value) 存储输入的大写版本并将其用作 &lt;p&gt; 的值
2) 这样可以保证输入的值不会被更新,从而不会导致光标跳转的问题

【讨论】:

  • 我使用{{ input }} 仅供参考,我认为使用两个变量不是一个好主意。如果必须在 10-20 个字段上实现相同的逻辑怎么办?表明我们为每个 v-model 保留重复项?
  • 这是一个很好的观点。这就是为什么你必须在问题中提到这一点。对于你的要求。也会有一些 html 更改
  • 我建议你更新你的问题。因为您所问的与您最初提出的问题不匹配。最好保持答案与问题匹配
  • 是的。但仍然回答了原来的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-03
  • 2020-07-29
  • 1970-01-01
  • 2011-10-25
  • 1970-01-01
  • 1970-01-01
  • 2013-07-20
相关资源
最近更新 更多