テキスト領域のjQueryセットカーソル位置


435

jQueryを使用してテキストフィールドのカーソル位置をどのように設定しますか?コンテンツを含むテキストフィールドがあり、ユーザーがフィールドにフォーカスしたときに、ユーザーのカーソルを特定のオフセットに配置したいと考えています。コードは次のようになります。

$('#input').focus(function() {
  $(this).setCursorPosition(4);
});

そのsetCursorPosition関数の実装はどのようになりますか?abcdefgという内容のテキストフィールドがある場合、この呼び出しにより、カーソルは次のように配置されます:abcd ** | ** efg。

Javaにも同様の関数setCaretPositionがあります。JavaScriptにも同様の方法はありますか?

更新:次のように、jQueryで動作するようにCMSのコードを変更しました。

new function($) {
  $.fn.setCursorPosition = function(pos) {
    if (this.setSelectionRange) {
      this.setSelectionRange(pos, pos);
    } else if (this.createTextRange) {
      var range = this.createTextRange();
      range.collapse(true);
      if(pos < 0) {
        pos = $(this).val().length + pos;
      }
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  }
}(jQuery);

78
$(this).get(0).setSelectionRange)?あなたはそれがとまったく同じであることを知っていthis.setSelectionRangeますか?jQueryはここでは文字通り何もしていません。
ボビンス

2
@bobinceコメントに追加するには、関数は選択された要素ごとに反復し、これを返す必要があります。正しいコードは私の答えにあります。
HRJ

21
@bobinceも実際にはまったく正しくありません。「これ」はDOMノードではなく、jQueryオブジェクトです。したがって、$(this).get(0).setSelectionRangeはthis.get(0).setSelectionRangeと同じであり、this.setSelectionRangeと同じではありません。
Prestaul

$(this)[0]は$(this).get(0)より高速です
EminezArtus 2014年

完全なソリューションについては、このチュートリアルを確認してください。webdesignpluscode.blogspot.com/2017/05/...
ワカス・アリ

回答:


254

私には2つの機能があります。

function setSelectionRange(input, selectionStart, selectionEnd) {
  if (input.setSelectionRange) {
    input.focus();
    input.setSelectionRange(selectionStart, selectionEnd);
  }
  else if (input.createTextRange) {
    var range = input.createTextRange();
    range.collapse(true);
    range.moveEnd('character', selectionEnd);
    range.moveStart('character', selectionStart);
    range.select();
  }
}

function setCaretToPos (input, pos) {
  setSelectionRange(input, pos, pos);
}

その後、次のようにsetCaretToPosを使用できます。

setCaretToPos(document.getElementById("YOURINPUT"), 4);

jQueryからの使用法を示す、a textareaとの両方inputを使用したライブの例:

2016年現在、テスト済みで、Chrome、Firefox、IE11、IE8でも動作してます(最後の記事をご覧ください。スタックスニペットはIE8をサポートしていません)。


3
選択の終了オフセットと開始オフセットを設定するので、折りたたみ(true)が必要なのはなぜですか。
Alexis Wilke

@mareoraft:上の作品textarea(とinputクロームやFirefox、IE8、及びIE11に私のために)。
TJクラウダー2016年

これを自分のスクリプトで動作させることができないようです。ページの読み込み時にテキスト領域が空になり、アプリケーションが使用されるときにJavaScriptで入力されます。新しい書き込み(使用法の記録)の前にキャレットを0に戻したい。問題を引き起こしているのは動的データですか?もしそうなら、どうすればそれを回避できますか?
クリス

文字列リテラル「文字」の意味は何ですか?その特定の文字列を使用する必要がありますか?
Jon Schneider

299

ここにjQueryソリューションがあります:

$.fn.selectRange = function(start, end) {
    if(end === undefined) {
        end = start;
    }
    return this.each(function() {
        if('selectionStart' in this) {
            this.selectionStart = start;
            this.selectionEnd = end;
        } else if(this.setSelectionRange) {
            this.setSelectionRange(start, end);
        } else if(this.createTextRange) {
            var range = this.createTextRange();
            range.collapse(true);
            range.moveEnd('character', end);
            range.moveStart('character', start);
            range.select();
        }
    });
};

これで、あなたはできる

$('#elem').selectRange(3,5); // select a range of text
$('#elem').selectRange(3); // set cursor position

2
@Jesse:Dunnoどうやって起こったのか、私は通常4を使います。修正されました。
mpen

1
@UberNeet:提案に基づいて更新されます。
mpen 2013年

1
@Enve:テストするIE 5.5のコピーはありませんが、jQueryがIE 5.5をサポートしていないためと思われます。
mpen 2013

1
@JaroslavZáruba:はい。そうです。しかし、あなたがすることができない記述する必要がありselectRange($('.my_input')[0], 3, 5)ますが、すでにjQueryのを使用している場合。さらに、何らかの理由で、必要に応じて複数の要素で機能する必要があります。純粋なネイティブが必要な場合は、CMSのソリューションを使用してください。
mpen 2014年

2
$('#elem').focus()点滅するカーソルを表示させるには、事前に追加する必要がありました。
mareoraft 2015年

37

ここでのソリューションは、jQuery拡張コードを除いて正しいです。

拡張機能は、選択された各要素を反復処理し、チェーニングthisをサポートするように戻る必要があります。ここで、A、正しいバージョンは:

$.fn.setCursorPosition = function(pos) {
  this.each(function(index, elem) {
    if (elem.setSelectionRange) {
      elem.setSelectionRange(pos, pos);
    } else if (elem.createTextRange) {
      var range = elem.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  });
  return this;
};

4
each関数はjqueryオブジェクトを返します。あなたは実際に行うことができます:return this.each(function...)そしてスタンドアロン行を削除します。
jhummel 14

23

私のために働く解決策を見つけました:

$.fn.setCursorPosition = function(position){
    if(this.length == 0) return this;
    return $(this).setSelection(position, position);
}

$.fn.setSelection = function(selectionStart, selectionEnd) {
    if(this.length == 0) return this;
    var input = this[0];

    if (input.createTextRange) {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    } else if (input.setSelectionRange) {
        input.focus();
        input.setSelectionRange(selectionStart, selectionEnd);
    }

    return this;
}

$.fn.focusEnd = function(){
    this.setCursorPosition(this.val().length);
            return this;
}

これで、次のように呼び出して、フォーカスを任意の要素の最後に移動できます。

$(element).focusEnd();

または、位置を指定します。

$(element).setCursorPosition(3); // This will focus on the third character.

3
textarea要素の場合、focusEndの改善点はを追加this.scrollTop(this[0].scrollHeight);することです。これにより、textareaが確実にスクロールされて挿入ポイントが表示されます。
2015年

12

これはMac OSX、jQuery 1.4上のSafari 5で私のために働きました:

$("Selector")[elementIx].selectionStart = desiredStartPos; 
$("Selector")[elementIx].selectionEnd = desiredEndPos;

私にとっては、直接アクセスではうまく機能しませんでしたが、これは完全に機能しました。$(myID).prop( 'selectionStart'、position); $(myID).prop( 'selectionEnd'、position);
アムダン

9

私はこれが非常に古い投稿であることを理解していますが、jQueryのみを使用して更新するためのおそらくより簡単なソリューションを提供する必要があると思いました。

function getTextCursorPosition(ele) {   
    return ele.prop("selectionStart");
}

function setTextCursorPosition(ele,pos) {
    ele.prop("selectionStart", pos + 1);
    ele.prop("selectionEnd", pos + 1);
}

function insertNewLine(text,cursorPos) {
    var firstSlice = text.slice(0,cursorPos);
    var secondSlice = text.slice(cursorPos);

    var new_text = [firstSlice,"\n",secondSlice].join('');

    return new_text;
}

ctrl-enterを使用して新しい行を追加するための使用法(Facebookなど):

$('textarea').on('keypress',function(e){
    if (e.keyCode == 13 && !e.ctrlKey) {
        e.preventDefault();
        //do something special here with just pressing Enter
    }else if (e.ctrlKey){
        //If the ctrl key was pressed with the Enter key,
        //then enter a new line break into the text
        var cursorPos = getTextCursorPosition($(this));                

        $(this).val(insertNewLine($(this).val(), cursorPos));
        setTextCursorPosition($(this), cursorPos);
    }
});

私は批判を受け入れています。ありがとうございました。

更新:このソリューションでは、通常のコピーアンドペースト機能(ctrl-c、ctrl-vなど)が機能しないため、将来、このパーツを確実に機能させるために編集する必要があります。それを行う方法についてアイデアがある場合は、ここにコメントしてください。私はテストしていきます。ありがとう。


7

IEでは、カーソルをある位置に移動するには、次のコードで十分です。

var range = elt.createTextRange();
range.move('character', pos);
range.select();



6

これはクロムで私のために働きます

$('#input').focus(function() {
    setTimeout( function() {
        document.getElementById('input').selectionStart = 4;
        document.getElementById('input').selectionEnd = 4;
    }, 1);
});

どうやらマイクロ秒以上の遅延が必要なようです。通常、ユーザーは上書きしたいテキストフィールド内のある位置をクリックする(またはタブを押す)ことでテキストフィールドにフォーカスするため、その位置が表示されるまで待つ必要があります。ユーザーが設定し、クリックして変更します。


厳密モードでは読み取り専用プロパティへの割り当ては許可されていません
Ivan Rubinson

4

矢印キーを使用している場合は、関数呼び出しの直後にfalseを返すことを忘れないでください。それ以外の場合は、Chromeがパチパチ音を立てます。

{
    document.getElementById('moveto3').setSelectionRange(3,3);
    return false;
}

2
することはベストプラクティスではありませんreturn false;event.preventDefault();代わりにしたいです。falseを返す場合、event.stopPropagation()それは必ずしも望ましいことではないことを暗示しています
Alan H.

4

この質問に基づくと、textareaに新しい行がある場合、IEやオペラでは完全に機能しません。答えは setSelectionRangeを呼び出す前にしたselectionStart、selectionEndにを調整する方法について説明します。

@AVProgrammerによって提案されたソリューションで他の質問からadjustOffsetを試してみましたが、うまくいきました。

function adjustOffset(el, offset) {
    /* From https://stackoverflow.com/a/8928945/611741 */
    var val = el.value, newOffset = offset;
    if (val.indexOf("\r\n") > -1) {
        var matches = val.replace(/\r\n/g, "\n").slice(0, offset).match(/\n/g);
        newOffset += matches ? matches.length : 0;
    }
    return newOffset;
}

$.fn.setCursorPosition = function(position){
    /* From https://stackoverflow.com/a/7180862/611741 */
    if(this.lengh == 0) return this;
    return $(this).setSelection(position, position);
}

$.fn.setSelection = function(selectionStart, selectionEnd) {
    /* From https://stackoverflow.com/a/7180862/611741 
       modified to fit https://stackoverflow.com/a/8928945/611741 */
    if(this.lengh == 0) return this;
    input = this[0];

    if (input.createTextRange) {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    } else if (input.setSelectionRange) {
        input.focus();
        selectionStart = adjustOffset(input, selectionStart);
        selectionEnd = adjustOffset(input, selectionEnd);
        input.setSelectionRange(selectionStart, selectionEnd);
    }

    return this;
}

$.fn.focusEnd = function(){
    /* From https://stackoverflow.com/a/7180862/611741 */
    this.setCursorPosition(this.val().length);
}

4

bitbucketで見つけたコードへの小さな変更

コードは、2つの位置が指定されている場合、開始/終了ポイントで選択/強調表示できるようになりました。テストされ、FF / Chrome / IE9 / Operaで正常に動作します。

$('#field').caret(1, 9);

コードを以下に示しますが、数行だけが変更されています。

(function($) {
  $.fn.caret = function(pos) {
    var target = this[0];
    if (arguments.length == 0) { //get
      if (target.selectionStart) { //DOM
        var pos = target.selectionStart;
        return pos > 0 ? pos : 0;
      }
      else if (target.createTextRange) { //IE
        target.focus();
        var range = document.selection.createRange();
        if (range == null)
            return '0';
        var re = target.createTextRange();
        var rc = re.duplicate();
        re.moveToBookmark(range.getBookmark());
        rc.setEndPoint('EndToStart', re);
        return rc.text.length;
      }
      else return 0;
    }

    //set
    var pos_start = pos;
    var pos_end = pos;

    if (arguments.length > 1) {
        pos_end = arguments[1];
    }

    if (target.setSelectionRange) //DOM
      target.setSelectionRange(pos_start, pos_end);
    else if (target.createTextRange) { //IE
      var range = target.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos_end);
      range.moveStart('character', pos_start);
      range.select();
    }
  }
})(jQuery)

Chrome 39、IE11、Safari 5.1.7で実行されますが、Firefox 34では実行されません: jsfiddle.net/0t94z82k/6
jbobbins

3

私はこれをcontenteditable要素とjQueryで動作させる必要があり、誰かがすぐに使用できるようにしたいと思った:

$.fn.getCaret = function(n) {
    var d = $(this)[0];
    var s, r;
    r = document.createRange();
    r.selectNodeContents(d);
    s = window.getSelection();
    console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length);
    return s.anchorOffset;
};

$.fn.setCaret = function(n) {
    var d = $(this)[0];
    d.focus();
    var r = document.createRange();
    var s = window.getSelection();
    r.setStart(d.childNodes[0], n);
    r.collapse(true);
    s.removeAllRanges();
    s.addRange(r);
    console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length);
    return this;
};

使用法$(selector).getCaret()はオフセット数を返し、offsetを$(selector).setCaret(num)確立し、要素にフォーカスを設定します。

また、小さなヒントとして、$(selector).setCaret(num)コンソールから実行するとconsole.logが返されますが、フォーカスはコンソールウィンドウで設定されているため、視覚化できません。

ベスト; D


1

setSelectionRangeが存在しない場合は、プロトタイプを直接変更できます。

(function() {
    if (!HTMLInputElement.prototype.setSelectionRange) {
        HTMLInputElement.prototype.setSelectionRange = function(start, end) {
            if (this.createTextRange) {
                var range = this.createTextRange();
                this.collapse(true);
                this.moveEnd('character', end);
                this.moveStart('character', start);
                this.select();
            }
        }
    }
})();
document.getElementById("input_tag").setSelectionRange(6, 7);

jsFiddleリンク

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.