粘贴长数字并将其拆分为多个输入

Paste and split long number to multiple input

提问人:Freddan 提问时间:8/30/2023 最后编辑:Freddan 更新时间:8/30/2023 访问量:92

问:

我正在尝试开发一种多输入形式,其中我粘贴了一个长数字,该数字自动拆分为每个输入,每个输入有 2 个数字。

一切正常,直到用户粘贴一个只有 5 位数字的数字,例如,而不是报告错误,而是在第一个输入中创建另一个数字。我无法理解表单如何在第一个输入中留下空白,然后通过发明一个数字来填充空白,而不是在最后一个输入中留下空白。45896

此外,如果输入只有一个数字,但仅当用户输入数字时,我开发在数字前面添加一个。else if (input.value.length !== 2 ) input.value = '0' + input.value;0

我希望粘贴函数显示错误,如果其中一个输入包含少于 2 位数字,并且当粘贴长度小于 6 位的数字时,空格保留在最后一个输入上,而不是第一个输入上。

我的代码是否有问题,或者我应该改进它以达到我的目标?

<style>
.circle input {
  border-radius: 999px;
  float: left;
  max-width: 100px;
  font-size: 2em;
  text-align: center;
  height: 100px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<form id="tkt_1">
  <div class="circle">
    <input type="tel" min="1" max="99" minlength="2" maxlength="2" oninput="if((this.value.length) > 2) {this.value = this.value.substring(0, 2);}" onchange="handleChange(this);" placeholder="00" />
  </div>
  <div class="circle">
    <input type="tel" min="1" max="99" minlength="2" maxlength="2" oninput="if((this.value.length) > 2) {this.value = this.value.substring(0, 2);}" onchange="handleChange(this);" placeholder="00" />
  </div>
  <div class="circle">
    <input type="tel" min="1" max="99" minlength="2" maxlength="2" oninput="if((this.value.length) > 2) {this.value = this.value.substring(0, 2);}" onchange="handleChange(this);" placeholder="00" />
  </div>
</form>

<script>
// Paste numbers from clipboard in multiple input 
document.addEventListener("paste", function (e) {
    // if the target is a text input
    if (e.target.type === "tel") {
        var data = e.clipboardData.getData('Text');
        // split clipboard text into single characters
        data = data.replace(/[^0-9]/g, "").split(/(?=(?:..)*$)/g);

        // find all other text inputs
        [].forEach.call(document.querySelectorAll("input[type=tel]"), (node, index) => {
            // And set input value to the relative character
            node.value = data[ index ] ?? "";

        });
    }
});

// Validation
function handleChange(input) {
    if (input.value < 0) input.value = "";
    else if (input.value.length !== 2 ) input.value = '0' + input.value;
    else if (input.value < 0.9 || input.value > 99 || input.value.length === 1 || input.value.length === 0) {
        input.style.backgroundColor = 'red';
        return false;
    } else {
        input.style.backgroundColor = '';
        return true;
    }
}

// Input only Numbers 
$('.circle input').keypress(function (event) {
    event = event || window.event;
    var charCode = event.which || event.keyCode;
    var charStr = String.fromCharCode(charCode);
    // FireFox key Del - Supr - Up - Down - Left - Right
    if (event.key !== undefined && event.charCode === 0) {
        return;
    }
    //Only Num
    if (!/^([0-9])*$/.test(charStr)) {
        event.preventDefault();
    }
    //Num and letters
    if (!/^[a-zA-Z0-9]+$/.test(charStr)) {
        event.preventDefault();
    }
});
</script>

JavaScript HTML 验证 输入

评论

0赞 Mike 'Pomax' Kamermans 8/30/2023
JS 注意:这会产生一个带有函数的对象。但这是非常值得怀疑的部分。你打算让这条线做什么?(注意:将脚本放在自己的文件中,并使用 加载它,以便您可以在代码编辑器中加载该 .js 并获得适当的警告、提示和格式)document.querySelectorAll("input[type=tel]").forEachnode.value = data[ index ] ||= ""; node.value = data[ index ];<script src="myfile.js" async defer></script>
0赞 Freddan 8/30/2023
感谢@Mike 'Pomax' Kamermans 的回答。该行将复制的数字从剪贴板拆分为每个输入,每个数字为 2 位数字。'node.value = data[ 索引 ] ||= “”;' 删除输入中的 'undefined',该输入仍为空 'Firefox compatibility'。我实际上不知道粘贴脚本是否正确,但它似乎工作正常。你知道有什么方法可以做得更好吗?
0赞 Mike 'Pomax' Kamermans 8/30/2023
是的,那是在现代 JS 中,使用 nullish 合并运算符。没有理由双重分配 node.valuea = b ?? "something else"
0赞 Mark Schultheiss 8/30/2023
您的表单采用“fu”、“rr”、“ey”的值值来处理
1赞 Mark Schultheiss 8/30/2023
粘贴“e12345”,您可以看到它创建了“1e”、“23”、“45”以在此处提供线索

答:

0赞 deepanshu223 8/30/2023 #1

拆分描述的主要问题是由于正则表达式拆分而发生的,它留下了第一个输入单个而不是最后一个输入。

此外,另一个问题是粘贴值不会触发,因此在粘贴值时永远不会调用该函数。onchangehandleChange

<style>
.circle input {
  border-radius: 999px;
  float: left;
  max-width: 100px;
  font-size: 2em;
  text-align: center;
  height: 100px;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="tkt_1">
  <div class="circle">
    <input type="tel" value="00" min="0" minlength="2" maxlength="2" oninput="if((this.value.length) > 2) {this.value = this.value.substring(0, 2);}" onchange="handleChange(this);" />
  </div>
  <div class="circle">
    <input type="tel" value="00" min="0" minlength="2" maxlength="2" oninput="if((this.value.length) > 2) {this.value = this.value.substring(0, 2);}" onchange="handleChange(this);" />
  </div>
  <div class="circle">
    <input type="tel" value="00" min="0" minlength="2" maxlength="2" oninput="if((this.value.length) > 2) {this.value = this.value.substring(0, 2);}" onchange="handleChange(this);" />
  </div>
</form>

<script>
// Paste numbers from clipboard in multiple input 
document.addEventListener("paste", function (e) {
    // if the target is a text input
    if (e.target.type === "tel") {
        var data = e.clipboardData.getData('Text');
        // split clipboard text into single characters
        data = data.replace(/[^0-9]/g, "");
        // Modified approach to split data into pairs
        var pairs = [];
        for (var i = 0; i < data.length; i += 2) {
            pairs.push(data.slice(i, i + 2));
        }
        data = pairs;

        // find all other text inputs
        [].forEach.call(document.querySelectorAll("input[type=tel]"), (node, index) => {
            // And set input value to the relative character
            node.value = data[ index ] ?? "";
            handleChange(node); //Added to trigger validation rules for pasted data

        });
    }
});

// Validation
function handleChange(input) {
    if (input.value < 0) input.value = "";
    else if (input.value.length !== 2 ) input.value = '0' + input.value;
    else if (input.value < 0.9 || input.value > 99 || input.value.length === 1 || input.value.length === 0) {
        input.style.backgroundColor = 'red';
        return false;
    } else {
        input.style.backgroundColor = '';
        return true;
    }
}

var pasteModifier = false; // Store if control or the meta key is pressed state
// Need to handle the paste functionality
$('.circle input').keydown(function (event) {
    if (event.metaKey || event.ctrlKey){
        pasteModifier = true;
    }
});
$('.circle input').keyup(function (event) {
    if (event.metaKey || event.ctrlKey){
        pasteModifier = false;
    }
});
// Input only Numbers 
$('.circle input').keypress(function (event) {
    event = event || window.event;
    var charCode = event.which || event.keyCode;
    var charStr = String.fromCharCode(charCode);
    // FireFox key Del - Supr - Up - Down - Left - Right
    if (event.key !== undefined && event.charCode === 0) {
        return;
    }
    // Handle paste command
    if (charCode == 118 && pasteModifier){
      return;
    }
    //Only Num
    else if (!/^([0-9])*$/.test(charStr)) {
        event.preventDefault();
    }
    //Num and letters
    else if (!/^[a-zA-Z0-9]+$/.test(charStr)) {
        event.preventDefault();
    }
});
</script>

我修改了代码,使用常规切片方法将数据字符串拆分为 2 位数字,并在最后一个输入中保留一个数字(如果适用)。该函数也在循环中触发,为每个输入设置值,以便它可以对粘贴的数据采取行动。handleChange

目前,如果您粘贴 5 位数字,它不会给出错误,但由于函数中设置的规则,它会在最后一个输入的开头附加一个 0。handleChange

如果删除此行

else if (input.value.length !== 2 ) input.value = '0' + input.value;

您将遇到红色错误。

在某些浏览器(包括 Safari)中,按键事件的优先级高于粘贴命令,在这种情况下会导致粘贴功能中断。

此外,只能看到可见的按键触发器,这与 和 不同。因此,我包含了附加和事件处理程序,以检查按下的键是 Mac 的键还是 Windows 的键,并将其作为状态存储在变量中。keypresskeydownkeyupkeydownkeyupMetaCtrlpasteModifier

这可以是处理程序中的一个条件,如果仍然按下键(未触发)然后按下 a,它会返回,因为粘贴处理程序不需要执行任何操作。keypressMeta or CtrlkeyupV

评论

0赞 Freddan 8/30/2023
非常感谢@deepanshu223!这就是我几天来一直在挣扎的事情,你的解释教会了我很多。是的,你是对的,我没有想过在粘贴函数中也包含 handleChange,我可能不会成功。输入应该只允许数字,并且项目包括我刚刚在我的第一篇文章中集成的脚本。在 Safari 上测试它,它阻止了键盘操作的粘贴功能 (ctrl+v)。各种正则表达式之间是否存在冲突或其他错误?
0赞 deepanshu223 8/30/2023
@Freddan 很高兴我的回答有所帮助。我听说过 Safari 限制了一些粘贴功能,尽管我在 MacBook Safari 上对其进行了测试,但我发布的示例似乎工作正常。您能否详细说明问题是什么以及在哪个设备上?
0赞 Freddan 8/30/2023
我不能感谢你@deepanshu223!您发布的解决方案仍然允许用户在用户从键盘键入时输入字母和其他字符,因为我一开始没有包含脚本。我在我的第一篇文章中完成了它,所以现在你可以在 Safari 上测试它,事实证明,仅按键数字的块破坏了粘贴功能。
0赞 deepanshu223 8/30/2023
@Freddan 我已经更新了处理此问题的代码并添加了解释。正如你所看到的,问题不在于代码,而在于浏览器处理事件的方式。
1赞 Freddan 8/30/2023
你是大师!你处理整个代码的方式对于我对 JS 的有限知识来说太复杂了。所以你写了完整的代码,包括所有元素,因为 Safari 需要“长版本”,不是吗?再次非常感谢你所做的一切,我去更深入地挖掘JS