42

前の入力が最大長の値に達した後、どうすれば次の入力に焦点を合わせることができますか?

a: <input type="text" maxlength="5" />
b: <input type="text" maxlength="5" />
c: <input type="text" maxlength="5" />

ユーザーがmaxlengthより大きいテキストを貼り付ける場合、理想的には次の入力にスピルする必要があります。

jsFiddle: http: //jsfiddle.net/4m5fg/1/

プラグインを使用したくないことを強調する必要があります。既存のものを使用するよりも、プラグインの背後にあるロジックを学習したいからです。理解に感謝。

4

10 に答える 10

61

jQueryは使用されておらず、非常にクリーンな実装です。

  • maxlength属性から読み取ります。
  • コンテナ内の任意の数の入力にスケーリングします。
  • フォーカスする次の入力を自動的に見つけます。
  • jQueryはありません。

http://jsfiddle.net/4m5fg/5/

<div class="container">
a: <input type="text" maxlength="5" />
b: <input type="text" maxlength="5" />
c: <input type="text" maxlength="5" />
</div>

..

var container = document.getElementsByClassName("container")[0];
container.onkeyup = function(e) {
    var target = e.srcElement || e.target;
    var maxLength = parseInt(target.attributes["maxlength"].value, 10);
    var myLength = target.value.length;
    if (myLength >= maxLength) {
        var next = target;
        while (next = next.nextElementSibling) {
            if (next == null)
                break;
            if (next.tagName.toLowerCase() === "input") {
                next.focus();
                break;
            }
        }
    }
    // Move to previous field if empty (user pressed backspace)
    else if (myLength === 0) {
        var previous = target;
        while (previous = previous.previousElementSibling) {
            if (previous == null)
                break;
            if (previous.tagName.toLowerCase() === "input") {
                previous.focus();
                break;
            }
        }
    }
}
于 2013-03-24T06:10:55.180 に答える
25

フィールドへの入力を監視し、その値をテストできます。

$("input").bind("input", function() {
    var $this = $(this);
    setTimeout(function() {
        if ( $this.val().length >= parseInt($this.attr("maxlength"),10) )
            $this.next("input").focus();
    },0);
});

作業デモ

入力が完了して値が更新された後setTimeoutのみコードが実行されるようにするためにあります。バインドにより、キーの押下、コピー/貼り付け(マウスからでも)、ドラッグアンドドロップなど、ほとんどの種類の入力でイベントがトリガーされます(ただし、この場合、フォーカスがドラッグアンドドロップではなくドラッグアンドドロップであるため、後者は機能しません。ドロップ可能)。input

:一部の古いブラウザでは、バインドする必要がある場合もありますpropertychange


ユーザーがmaxlengthより大きいテキストを貼り付ける場合、理想的には次の入力にスピルする必要があります。

これを行うには、JavaScriptを使用して属性を削除しmaxlength(完全な入力をキャプチャできるようにするため)、その機能を自分で実装する必要がある場合があります。私は小さな例を作りました、以下の関連部分:

$("input").each(function() {
    var $this = $(this);
    $(this).data("maxlength", $this.prop("maxlength"));
    $(this).removeAttr("maxlength");
})

これにより属性は削除されますが、に保存されるdataため、後でアクセスできます。

function spill($this, val) {
    var maxlength = $this.data("maxlength");
    if ( val.length >= maxlength ) {
        $this.val(val.substring(0, maxlength));
        var next = $this.next("input").focus();
        spill(next, val.substring(maxlength));
    }
    else
        $this.val(val);
}

ここで、最大長ロジックがJavaScriptに再導入され、「破棄された」部分を取得して、への再帰呼び出しで使用しspillます。次の要素がない場合、toの呼び出しdataが戻りundefined、ループが停止するため、最後のフィールドで入力が切り捨てられます。

于 2013-03-24T05:58:21.150 に答える
10

プレーンJavaScriptを使用できます。

DEMOを参照してください。

文字の長さを。で確認してくださいel.value.length。最大値と等しい場合は、を使用して次のフィールドに移動しfocus()ます。この関数をキーアップイベントにバインドしてonkeyup、ユーザーが文字を入力した後に関数が毎回起動するようにします。

var a = document.getElementById("a"),
    b = document.getElementById("b"),
    c = document.getElementById("c");

a.onkeyup = function() {
    if (this.value.length === parseInt(this.attributes["maxlength"].value)) {
        b.focus();
    }
}

b.onkeyup = function() {
    if (this.value.length === parseInt(this.attributes["maxlength"].value)) {
        c.focus();
    }
}
于 2013-03-24T06:00:45.340 に答える
7

あなたが多くのフィールドを持っているつもりなら、あなたはこのようなことをすることができます。

基本的にkeyupは、入力の長さを取得し、それをmaxlengthと比較し、一致する場合focusは次の入力フィールドに比較します。

http://jsfiddle.net/btevfik/DVxDA/

$(document).ready(function(){
    $('input').keyup(function(){
        if(this.value.length==$(this).attr("maxlength")){
            $(this).next().focus();
        }
    });
});
于 2013-03-24T06:09:57.910 に答える
3

更新されたbtevfikコード、Onkeyupまたはonkeydownは、タブナビゲーションで以前の入力を削除できないため、問題を引き起こします。最大長に制限されるため、入力ボックス内のテキストを編集または変更するのは困難です。したがって、oninputイベントを使用してタスクを実行できます。

デモ

HTML

<ul>
<li>a: <input type="text" maxlength="5" /></li>
<li>b: <input type="text" maxlength="3" /></li>
<li>c: <input type="text" maxlength="5" /></li>
<li>d: <input type="text" maxlength="3" /></li>
<li>e: <input type="text" maxlength="6" /></li>
<li>f: <input type="text" maxlength="10" /></li>
<li>g: <input type="text" maxlength="7" /></li>
</ul>

Javascript

$(document).ready(function(){
    $('input').on("input", function(){
        if($(this).val().length==$(this).attr("maxlength")){
            $(this).next().focus();
        }
    });
});

CSS

ul {list-style-type:none;}
li {padding:5px 5px;}
于 2018-01-18T14:16:22.247 に答える
3

let otp = document.querySelector('#otp-screen');

for(let pin of otp.children) {
    pin.onkeyup = function() {
        if(pin.nextElementSibling) {
            pin.nextElementSibling.focus();
        }
    }
}
<div class="otp-screen" id="otp-screen">
    <input type="text" placeholder="0" maxlength="1"/> 
    <input type="text" placeholder="0" maxlength="1"/> 
    <input type="text" placeholder="0" maxlength="1"/> 
    <input type="text" placeholder="0" maxlength="1"/> 
</div>

于 2020-07-10T13:07:01.243 に答える
1

他の回答は、これをどのように実装できるかについてある程度の考えを示していますが、次のようないくつかのマイナーなことを考慮していないことがわかりました。

  1. ページ全体ではなく、特定のフォーム内の要素にオートフォーカスを設定する必要があるという事実。
  2. 入力要素は他の要素でラップすることができます(たとえば、CSSでラップするspandiv、フローティングラベルを許可し、構造体に使用するフォームを見てきましたtable)。
  3. 自動的にこぼれたり、次のフィールドに移動したりするときのフィールドの有効性。
  4. こぼれたときにイベントを入力します。
  5. 前のフィールドに戻るときのカーソル位置(ブラウザで保存できるように見えるため、バックスペースはフィールドの最後ではなく、たとえば中央にフォーカスできます)。

以下のコードは、少なくともこれらすべてを説明しようとしています。そのほとんどはcodepenでテストできます:paste-spillingはそこでは機能せず、Clipboard APIが原因のように見えます(他のcodepenも機能しません)。
コードに不明な点がある場合はお知らせください。回答とコードを更新します。カバーされていないエッジケースを見つけた場合は、私にも知らせてください。

codepenのフォームを使用したペーストスピルテストの場合、次のようなものを使用できます。123456789123456789012345678903454353434534

YouTubeのより「ライブ」な環境でどのように機能するかのビデオサンプル

//List of input types, that are "textual" by default, thus can be tracked through keypress and paste events. In essence,
// these are types, that support maxlength attribute
const textInputTypes = ['email', 'password', 'search', 'tel', 'text', 'url', ];

formInit();

//Add listeners
function formInit()
{
    document.querySelectorAll('form input').forEach((item)=>{
        if (textInputTypes.includes(item.type)) {
            //Somehow backspace can be tracked only on keydown, not keypress
            item.addEventListener('keydown', inputBackSpace);
            if (item.getAttribute('maxlength')) {
                item.addEventListener('input', autoNext);
                item.addEventListener('change', autoNext);
                item.addEventListener('paste', pasteSplit);
            }
        }
    });
}


//Track backspace and focus previous input field, if input is empty, when it's pressed
function inputBackSpace(event)
{
    let current = event.target;
    if ((event.keyCode || event.charCode || 0) === 8 && !current.value) {
        let moveTo = nextInput(current, true);
        if (moveTo) {
            moveTo.focus();
            //Ensure, that cursor ends up at the end of the previous field
            moveTo.selectionStart = moveTo.selectionEnd = moveTo.value.length;
        }
    }
}

//Focus next field, if current is filled to the brim and valid
function autoNext(event)
{
    let current = event.target;
    //Get length attribute
    let maxLength = parseInt(current.getAttribute('maxlength'));
    //Check it against value length
    if (maxLength && current.value.length === maxLength && current.validity.valid) {
        let moveTo = nextInput(current, false);
        if (moveTo) {
            moveTo.focus();
        }
    }
}

async function pasteSplit(event)
{
    let permission = await navigator.permissions.query({ name: 'clipboard-read',});
    //Check permission is granted or not
    if (permission.state === 'denied') {
        //It's explicitly denied, thus cancelling action
        return false;
    }
    //Get buffer
    navigator.clipboard.readText().then(result => {
        let buffer = result.toString();
        //Get initial element
        let current = event.target;
        //Get initial length attribute
        let maxLength = parseInt(current.getAttribute('maxlength'));
        //Loop while the buffer is too large
        while (current && maxLength && buffer.length > maxLength) {
            //Ensure input value is updated
            current.value = buffer.substring(0, maxLength);
            //Trigger input event to bubble any bound events
            current.dispatchEvent(new Event('input', {
                bubbles: true,
                cancelable: true,
            }));
            //Do not spill over if a field is invalid
            if (!current.validity.valid) {
                return false;
            }
            //Update buffer value (not the buffer itself)
            buffer = buffer.substring(maxLength);
            //Get next node
            current = nextInput(current);
            if (current) {
                //Focus to provide visual identification of a switch
                current.focus();
                //Update maxLength
                maxLength = parseInt(current.getAttribute('maxlength'));
            }
        }
        //Check if we still have a valid node
        if (current) {
            //Dump everything we can from leftovers
            current.value = buffer;
            //Trigger input event to bubble any bound events
            current.dispatchEvent(new Event('input', {
                bubbles: true,
                cancelable: true,
            }));
        }
    }).catch(err => {
        //Most likely user denied request. Check status
        navigator.permissions.query({ name: 'clipboard-read',}).then(newPerm => {
            if (newPerm.state === 'granted') {
                console.log('Failed to read clipboard', err);
            } else {
                console.log('Request denied by user. Show him some notification to explain why enabling permission may be useful');
            }
        }).catch(errPerm => {
            console.log('Failed to read clipboard', errPerm);
        });
    });
}

//Find next/previous input
function nextInput(initial, reverse = false)
{
    //Get form
    let form = initial.form;
    //Iterate inputs inside the form. Not using previousElementSibling, because next/previous input may not be a sibling on the same level
    if (form) {
        let previous;
        for (let moveTo of form.querySelectorAll('input')) {
            if (reverse) {
                //Check if current element in loop is the initial one, meaning
                if (moveTo === initial) {
                    //If previous is not empty - share it. Otherwise - false, since initial input is first in the form
                    if (previous) {
                        return previous;
                    } else {
                        return false;
                    }
                }
            } else {
                //If we are moving forward and initial node is the previous one
                if (previous === initial) {
                    return moveTo;
                }
            }
            //Update previous input
            previous = moveTo;
        }
    }
    return false;
}
于 2021-09-02T15:33:11.487 に答える
0

入力テキストフィールドを動的に追加する場合は、これを試すことができます。

これにより、スクリプトがDOMに再挿入され、完全に機能します。

$('body').on('keyup', '#num_1',function(){
  if (this.value.length === parseInt(this.attributes["maxlength"].value)) {
    $('#num_2').focus();
  }
})
$('body').on('keyup','#num_2', function(){
   if (this.value.length === parseInt(this.attributes["maxlength"].value)) {
    $('#num_3').focus();
  }
})
<input type="text" class="form-control" name="number" maxlength="3" id="num_1">
<input type="text" class="form-control" name="number" maxlength="3" id="num_2">
<input type="text" class="form-control" name="number" maxlength="4" id="num_3">

于 2016-08-04T11:18:45.260 に答える
0

カード(デビット/クレジット)番号の入力タイプの作成に重点を置いている場合。次に、簡単に管理できるjQueryバージョンを次のようにクリーンアップします。

/*..............................................................................................
* jQuery function for Credit card number input group
......................................................................................................*/
            // make container label of input groups, responsible
            $('.card-box').on('focus', function(e){
                $(this).parent().addClass('focus-form-control');
            });
            $('.card-box').on('blur', function(e){
                $(this).parent().removeClass('focus-form-control');
            });
            $('.card-box-1').on('keyup', function(e){
                e.preventDefault();
                var max_length = parseInt($(this).attr('maxLength'));
                var _length = parseInt($(this).val().length);
                if(_length >= max_length) {
                    $('.card-box-2').focus().removeAttr('readonly');
                    $(this).attr('readonly', 'readonly');
                }
                if(_length <= 0){
                    return;
                }
            });
            $('.card-box-2').on('keyup', function(e){
                e.preventDefault();
                var max_length = parseInt($(this).attr('maxLength'));
                var _length = parseInt($(this).val().length);
                if(_length >= max_length) {
                    $('.card-box-3').focus().removeAttr('readonly');
                    $(this).attr('readonly', 'readonly');
                }
                if(_length <= 0){
                    $('.card-box-1').focus().removeAttr('readonly');
                    $(this).attr('readonly', 'readonly');
                }
            });
             $('.card-box-3').on('keyup', function(e){
                e.preventDefault();
                var max_length = parseInt($(this).attr('maxLength'));
                var _length = parseInt($(this).val().length);
                if(_length >= max_length) {
                    $('.card-box-4').focus().removeAttr('readonly');
                    $(this).attr('readonly', 'readonly');
                }
                if(_length <= 0){
                    $('.card-box-2').focus().removeAttr('readonly');
                    $(this).attr('readonly', 'readonly');
                }
            });
            $('.card-box-4').on('keyup', function(e){
                e.preventDefault();
                var max_length = parseInt($(this).attr('maxLength'));
                var _length = parseInt($(this).val().length);
                if(_length >= max_length) {
                    return;
                }
                if(_length <= 0){
                    $('.card-box-3').focus().removeAttr('readonly');
                    $(this).attr('readonly', 'readonly');
                }
            });
/*..............................................................................................
* End jQuery function for Credit card number input group
......................................................................................................*/
/* Hide HTML5 Up and Down arrows. */
                                input[type="number"]::-webkit-outer-spin-button, input[type="number"]::-webkit-inner-spin-button {
                                    -webkit-appearance: none; margin: 0;
                                }
                                input[type="number"] { -moz-appearance: textfield; }
                                .card-box {
                                    width: 20%; display: inline-block; height: 100%; border: none;
                                }
                                
                                .focus-form-control {
                                    border-color: #66afe9; outline: 0;-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
                                        box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, .6);
                                }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<div class="form-control" style="padding: 0; max-width: 300px; ">
                                        <input class="card-box card-box-1" type="number" id="CreditCard_CardNumber1" required step="1" minlength="4" maxlength="4" pattern="[0-9]{4}" value="" placeholder="0000"
                                            onClick="this.setSelectionRange(0, this.value.length)" oninput="this.value=this.value.slice(0,this.maxLength||'');this.value=(this.value < 1) ? ('') : this.value;"/> 
                                        <input class="card-box card-box-2" type="number" id="CreditCard_CardNumber2" readonly required step="1" minlength="4" maxlength="4" pattern="[0-9]{4}" value="" placeholder="0000"
                                            onClick="this.setSelectionRange(0, this.value.length)" oninput="this.value=this.value.slice(0,this.maxLength||'');this.value=(this.value < 1) ? ('') : this.value;" />
                                        <input class="card-box card-box-3" type="number" id="CreditCard_CardNumber3" readonly required step="1" minlength="4" maxlength="4" pattern="[0-9]{4}" value="" placeholder="0000"
                                            onClick="this.setSelectionRange(0, this.value.length)" oninput="this.value=this.value.slice(0,this.maxLength||'');this.value=(this.value < 1) ? ('') : this.value;" />
                                        <input class="card-box card-box-4" type="number" id="CreditCard_CardNumber4" readonly required step="1" minlength="4" maxlength="4" pattern="[0-9]{4}" value="" placeholder="0000"
                                            onClick="this.setSelectionRange(0, this.value.length)" oninput="this.value=this.value.slice(0,this.maxLength||'');this.value=(this.value < 1) ? ('') : this.value;" />
                                    </div>

于 2016-12-02T16:09:54.360 に答える
0

確認済みの回答には、前のフィールドの長さが有効な場合に前のフィールドに焦点を当てる問題が1つあります

以前のタグの完全な長さを修正するために上記の回答を変更しました

var container = document.getElementsByClassName("container")[0];
    container.onkeyup = function(e) {
    var target = e.srcElement || e.target;
    var maxLength = parseInt(target.attributes["maxlength"].value, 10);
    var myLength = target.value.length;
    if (myLength >= maxLength) {
        var next = target;
        while (next = next.nextElementSibling) {
            if (next == null)
                break;
            if (next.tagName.toLowerCase() === "input") {
                next.focus();
                break;
            }
        }
    }
    // Move to previous field if empty (user pressed backspace)
    else if (myLength === 0) {
         var previous = target;
       // Move to previous field if backspace is pressed
        if (code == 8) {
            previous = previous.previousElementSibling;
            if (previous != null) {
                if (previous.tagName.toLowerCase() === "input") {
                    previous.focus();
                }
            }
        } else {
            while (previous = previous.previousElementSibling) {
                if (previous == null)
                    break;
                if (previous.tagName.toLowerCase() === "input") {
                    var mLength = parseInt(previous.attributes["maxlength"].value, 10);
                    var pMyLength = previous.value.length;
                    // Move to previous field if it does not have required length
                    if (mLength == pMyLength) {
                        break;
                    } else {
                        previous.focus();
                        break;
                    }
                }
            }
        }
    }
}
于 2018-08-30T14:34:02.657 に答える