web-dev-qa-db-fra.com

jQuery Définit la position du curseur dans la zone de texte

Comment définir la position du curseur dans un champ de texte à l'aide de jQuery? J'ai un champ texte avec du contenu et je veux que le curseur des utilisateurs soit positionné à un certain décalage lorsqu'ils se concentrent sur le champ. Le code devrait ressembler à ceci:

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

À quoi ressemblerait l'implémentation de cette fonction setCursorPosition? Si vous aviez un champ texte avec le contenu abcdefg, cet appel aurait pour effet de positionner le curseur comme suit: abcd ** | ** efg.

Java a une fonction similaire, setCaretPosition. Existe-t-il une méthode similaire pour javascript?

Mise à jour: j'ai modifié le code de CMS pour fonctionner avec jQuery comme suit:

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);
431
jcnnghm

J'ai deux fonctions:

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);
}

Ensuite, vous pouvez utiliser setCaretToPos comme ceci:

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

Exemple en direct avec à la fois un textarea et un input, montrant l'utilisation de jQuery:

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);
}

$("#set-textarea").click(function() {
  setCaretToPos($("#the-textarea")[0], 10)
});
$("#set-input").click(function() {
  setCaretToPos($("#the-input")[0], 10);
});
<textarea id="the-textarea" cols="40" rows="4">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</textarea>
<br><input type="button" id="set-textarea" value="Set in textarea">
<br><input id="the-input" type="text" size="40" value="Lorem ipsum dolor sit amet, consectetur adipiscing elit">
<br><input type="button" id="set-input" value="Set in input">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

À partir de 2016, testé et fonctionnant sous Chrome, Firefox, IE11 et même IE8 (voir ce dernier ici ; Les extraits de pile ne prennent pas en charge IE8).

252
CMS

Voici une solution 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();
        }
    });
};

Avec cela, vous pouvez faire

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

Les solutions ici sont correctes sauf le code d'extension jQuery.

La fonction d'extension doit parcourir chaque élément sélectionné et renvoyer this pour prendre en charge le chaînage. Voici le a version correcte:

$.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;
};
37
HRJ

J'ai trouvé une solution qui fonctionne pour moi:

$.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;
    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;
}

Maintenant, vous pouvez déplacer le focus à la fin de n'importe quel élément en appelant:

$(element).focusEnd();
22
AVProgrammer

Cela a fonctionné pour moi sur Safari 5 sur Mac OSX, jQuery 1.4:

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

Je réalise qu’il s’agit d’un très vieux billet, mais j’ai pensé que je devrais peut-être proposer une solution plus simple pour le mettre à jour en utilisant uniquement 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;
}

Utilisation pour utiliser ctrl-enter pour ajouter une nouvelle ligne (comme dans 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);
    }
});

Je suis ouvert à la critique. Je vous remercie.

MISE À JOUR: Cette solution ne permet pas aux fonctionnalités normales de copier/coller de fonctionner (c.-à-d. Ctrl-c, ctrl-v), je vais donc devoir l'éditer à l'avenir pour m'assurer que cette partie fonctionnera à nouveau. Si vous avez une idée de la façon de procéder, veuillez commenter ici et je me ferai un plaisir de la tester. Merci.

8
tofirius
7
Ben Noland

Dans IE pour déplacer le curseur sur une position, ce code suffit:

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

Définir le focus avant d’avoir inséré le texte dans la zone de texte ainsi?

$("#comments").focus();
$("#comments").val(comments);
6
Steven Whitby

Cela fonctionne pour moi en chrome

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

Apparemment, vous avez besoin d’un délai d’au moins une microseconde, car un utilisateur se concentre généralement sur le champ de texte en cliquant à un emplacement du champ (ou en appuyant sur la touche de tabulation) que vous souhaitez ignorer. Vous devez donc attendre que la position soit défini par l'utilisateur, cliquez dessus puis modifiez-le.

5
Hung Tran

Petite modification du code trouvé dans bitbucket

Le code est maintenant capable de sélectionner/mettre en surbrillance avec les points de début/fin si 2 positions sont données. Testé et fonctionne bien dans FF/Chrome/IE9/Opera.

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

Le code est répertorié ci-dessous, seules quelques lignes ont été modifiées:

(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)
4
twig

Rappelez-vous simplement de renvoyer false juste après l'appel de la fonction si vous utilisez les touches fléchées, car Chrome fricks la fracture sinon.

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

Sur la base de cette question , la réponse ne fonctionnera pas parfaitement pour ie et opera lorsqu'il y aura une nouvelle ligne dans la zone de texte. Le réponse explique comment ajuster selectionStart, selectionEnd avant d'appeler setSelectionRange.

J'ai essayé le adjustOffset de l'autre question avec la solution proposée par @AVProgrammer et ça marche.

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);
}
3
Ghislain Hivon

Je devais faire en sorte que cela fonctionne pour les éléments contenteditables et jQuery et j'ai pensé que quelqu'un pourrait le vouloir prêt à être utilisé:

$.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;
};

Utilisation $(selector).getCaret() renvoie le décalage de numéro et $(selector).setCaret(num) établit le décalage et active l'élément.

Également, un petit conseil: si vous exécutez $(selector).setCaret(num) à partir de la console, le fichier console.log sera renvoyé, mais vous ne visualiserez pas le focus car il est défini dans la fenêtre de la console.

Bests; D

2
FGZ

Vous pouvez directement changer le prototype si setSelectionRange n'existe pas.

(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 lien

1
Anoop