【问题标题】:Javascript: Set cursor position when changing the value of inputJavascript:更改输入值时设置光标位置
【发布时间】:2018-02-19 14:14:12
【问题描述】:

当您键入公式时,我试图在我的应用程序中重现类似于 Microsoft Excel/Google 表格的用户体验,并且您可以使用自动完成下拉列表来显示您可以使用的不同公式和变量。

为此,在验证了自动完成功能后,我希望能够控制光标的位置。

例如,如果我键入 =sum(variable1, variable2),在 variable2 的自动完成时,光标应该在最后一个括号之前,而不是在最后。

我了解如何用javascript设置光标的位置,问题是因为我同时修改了输入的值并设置了光标位置,后者不起作用。

我用更简单的上下文重现了这个问题: https://jsfiddle.net/joparisot/j8ourfa1/31/

我的html:

<div id="app">
    <autocomplete v-model="selection"></autocomplete>
</div>

<template id="autocomplete">
  <div>
    <h2>gernerogrnio</h2>
    <input id="my-input" 
           class="form-control" 
           type="text" 
           :value="value"
           @keydown.enter="updateValue($event.target.value)">
    <p>{{ value }}</p>
  </div>
</template>

我的脚本:

    Vue.component('autocomplete', {
    template: '#autocomplete', 
  props: {
    value: {
      type: String,
      required: true
    }
  }, 
  methods: {
    updateValue (value) {
        var new_value = ''
      if (value.length < 4) {
        new_value = 'Inferior'
      } else {
        new_value = 'Superior'
      }

      this.$emit('input', new_value)
      var myInput = document.getElementById('my-input');
      this.setCaretPosition(myInput, 5)
    }, 
    setCaretPosition(ctrl, pos) {
        ctrl.focus();
        ctrl.setSelectionRange(pos, pos);
    }
  }
});

new Vue({
    el: '#app', 
  data: {
    selection: 'test'
  }
});

我不关心自动完成,但根据您输入的内容,当您按下回车键时,输入将填充一个新值。您可以看到,如果您注释第 11 到 16 行并将 new_value 设置为 value,则设置光标位置将起作用。

我似乎无法同时做这两件事。有什么想法吗?

【问题讨论】:

  • 是的,这行得通。非常感谢!
  • 就我而言,setSelectionRange 是我最简单的选择,谢谢!

标签: javascript vue.js input caret


【解决方案1】:

感谢 Roy J 的评论,我能够找到解决方案。

在updateValue函数中添加以下内容:

this.$nextTick(() => {
  this.setCaretPosition(myInput, 5)
});

【讨论】:

  • 请问this 是什么?在 Chrome 中调试时,我的 Vue 对象中没有看到 $nextTick
  • 我试过了,但它不会在文本区域中移动光标:_app._data.sourceText = 'new value'; Vue.nextTick(e.currentTarget.setSelectionRange(2, 2));
【解决方案2】:

我从这个问题中了解到setSelectionRange,并用它来处理信用卡号输入:

模板:

<input
    ref="input"
    v-model="value"
    @input="handleChange"
>

实例方法:

data() {
    return {
        lastValue: '',
    }
},

methods: {
    setCursorPosition(el, pos) {
        el.focus();
        el.setSelectionRange(pos, pos);
    },
    handleChange() {
        // handle backspace event
        if (this.value.length < this.lastValue.length) {
            this.lastValue = this.value;
            this.$emit('input-changed', this.value);
            return;
        }
        // handle value-edit event
        if (this.$refs.input.selectionStart < this.value.length) {
            const startPos = this.$refs.input.selectionStart;
            this.value = this.value.replace(/\W/gi, '').replace(/(.{4})/g, '$1 ').trim();
            this.$nextTick(() => this.setCursorPosition(this.$refs.input, startPos));
            this.lastValue = this.value;
            this.$emit('input-changed', this.value);
            return;
        }
        // handle everything else
        this.value = this.value.replace(/\W/gi, '').replace(/(.{4})/g, '$1 ').trim();
        this.lastValue = this.value;
        this.$emit('input-changed', this.value);
    },
},

上述代码的目标是在信用卡输入中添加空格,因此1234123412341234 会自动重新格式化为1234 1234 1234 1234。冒险进入这个领域的人会注意到在编辑输入值时会出现问题。

您可以在上面的示例中看到三个条件。最后一个是默认值,它简单地使用 2 步组合重新格式化当前值:删除所有空格,然后每 4 个字符添加一个空格。

如果你注释掉这两个if 块,你可以看到问题的出现。

第一个if 块处理退格事件。如您所见,每次输入更改时,都会将值捕获为this.lastValue。当您按退格键时,第一个条件的目标是不运行正则表达式。在我看来,这是更好的用户体验。如果你注释掉那个条件,你就可以看到。

第二个if 块处理编辑事件。测试它的一个好方法是输入一个有效的 CC 但省略第三个字符,这样所有的东西都会减一。然后添加字符。一切都应该是好的。同样,如果您退格多个字符。第二个条件的目标是正确管理光标位置(或插入符号位置,如果您更喜欢该命名法)。

您可以安全地删除第一个条件和对lastValue 的所有引用,代码仍然可以工作。这可以说是更简单但更糟糕的用户体验。

【讨论】:

【解决方案3】:

我找到了解决此问题的简单方法,在 IE 和 Chrome 中测试 100%

在每次按键时调用此函数

function setCaret(eleId)
 {
   var mousePosition = $(elemId)[0].selectionStart;
   var elem = document.getElementById(elemId);
   elem.setSelectionRange(mousePosition + 1, mousePosition + 1);
 }

将文本框 id 传递给此函数,该函数将查找鼠标位置并在每次按键时放置插入符号

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    相关资源
    最近更新 更多