Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/vue.js/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript:更改输入值时设置光标位置_Javascript_Vue.js_Input_Caret - Fatal编程技术网

Javascript:更改输入值时设置光标位置

Javascript:更改输入值时设置光标位置,javascript,vue.js,input,caret,Javascript,Vue.js,Input,Caret,我试图在我的应用程序中重现一个类似于Microsoft Excel/Google工作表的用户体验,当您键入公式时,您会有一个自动完成下拉列表,显示您可以使用的不同公式和变量 为此,在验证自动完成后,我希望能够控制光标的位置 例如,如果I type=sum(variable1,variable2),在variable2的自动完成上,光标应该在最后一个括号之前,而不是在最末尾 我了解如何使用javascript设置光标的位置,问题是,我同时修改输入值并设置光标位置,后者不起作用 我用更简单的上下文再

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

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

例如,如果I type=sum(variable1,variable2),在variable2的自动完成上,光标应该在最后一个括号之前,而不是在最末尾

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

我用更简单的上下文再现了这个问题:

我的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>

格内罗格尼奥
{{value}}

我的剧本:

    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'
  }
});
Vue.component('autocomplete'{
模板:“#自动完成”,
道具:{
价值:{
类型:字符串,
必填项:true
}
}, 
方法:{
updateValue(值){
var新值=“”
如果(值。长度<4){
新的_值=‘次’
}否则{
新的_值='Superior'
}
此.$emit('input',新值)
var myInput=document.getElementById('my-input');
此.setCaretPosition(myInput,5)
}, 
setCaretPosition(ctrl,pos){
ctrl.focus();
控制设置选择范围(位置,位置);
}
}
});
新Vue({
el:“#应用程序”,
数据:{
选择:“测试”
}
});
我不担心自动完成,但根据您键入的内容,当您按enter键时,输入将填充一个新值。您可以看到,如果对第11行到第16行进行注释,并将new_value设置为value,则设置光标位置将起作用


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

多亏了罗伊·J的评论,我找到了解决办法

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

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

我从这个问题中了解了
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);
    },
},
data(){
返回{
最后一个值:“”,
}
},
方法:{
设置光标位置(el、pos){
el.focus();
el.设置选择范围(位置,位置);
},
handleChange(){
//处理退格事件
if(this.value.lengththis.setCursorPosition(this.$refs.input,startPos));
this.lastValue=this.value;
此.emit('input-changed',此.value);
返回;
}
//处理其他事情
this.value=this.value.replace(/\W/gi',).replace(/(.{4})/g,'$1').trim();
this.lastValue=this.value;
此.emit('input-changed',此.value);
},
},
上述代码的目标是在信用卡输入中添加空格,因此
12341234112341234
会自动重新格式化为
1234 1234 1234
。进入该区域的人会注意到编辑输入值时出现问题

你可以看到在我上面的示例中有三种情况。最后一个是默认值,只需使用两步组合重新格式化当前值:删除所有空格,然后每4个字符添加一个空格

如果您注释掉两个
If
块,您可以看到问题出现

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

第二个
if
块处理编辑事件。测试它的一个好方法是输入一个有效的CC,但省略第三个字符,这样所有内容都将关闭一个。然后在中添加角色。一切都应该是好的。同样,如果您将多个字符退格。第二个条件的目标是正确管理光标位置(或插入符号位置,如果您喜欢该术语)


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

我找到了一个简单的方法来解决这个问题,在IE和Chrome上进行了100%的测试

在每次按键时调用此函数

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

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

请参见“是”,这样做有效。非常感谢!就我而言,setSelectionRange是我最简单的选择,谢谢!请问这是什么?在Chrome中调试时,我没有在我的Vue对象中看到
$nextTick
,我尝试了此操作,但它没有在文本区域移动光标:
\u app.\u data.sourceText='new value';Vue.nextTick(e.currentTarget.setSelectionRange(2,2))为什么要发出“input changed”而不是“input”?我在这里对其进行了一些调整,似乎您不需要这些事件:
function setCaret(eleId)
 {
   var mousePosition = $(elemId)[0].selectionStart;
   var elem = document.getElementById(elemId);
   elem.setSelectionRange(mousePosition + 1, mousePosition + 1);
 }