Как переместить курсор в конец объекта - PullRequest
70 голосов
/ 14 июля 2009

Мне нужно переместить курсор в конец contenteditable узла, как в виджете заметок Gmail.

Я читаю потоки в StackOverflow, но эти решения основаны на использовании входных данных и не работают с contenteditable элементами.

Ответы [ 6 ]

208 голосов
/ 05 октября 2010

Решение Geowa4 будет работать для текстовой области, но не для contenteditable элемента.

Это решение предназначено для перемещения каретки до конца элемента, подлежащего удовлетворению. Он должен работать во всех браузерах, которые поддерживают contenteditable.

function setEndOfContenteditable(contentEditableElement)
{
    var range,selection;
    if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
    {
        range = document.createRange();//Create a range (a range is a like the selection but invisible)
        range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
        range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
        selection = window.getSelection();//get the selection object (allows you to change selection)
        selection.removeAllRanges();//remove any selections already made
        selection.addRange(range);//make the range you have just created the visible selection
    }
    else if(document.selection)//IE 8 and lower
    { 
        range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
        range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
        range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
        range.select();//Select the range (make it the visible selection
    }
}

Может использоваться кодом, похожим на:

elem = document.getElementById('txt1');//This is the element that you want to move the caret to the end of
setEndOfContenteditable(elem);
22 голосов
/ 25 октября 2013

Есть и другая проблема.

Решение Nico Burns работает, если в contenteditable div нет других многоуровневых элементов.

Например, если div содержит другие div, а эти другие div содержат другие вещи внутри, могут возникнуть некоторые проблемы.

Чтобы решить их, я организовал следующее решение, которое является улучшением Nico :

//Namespace management idea from http://enterprisejquery.com/2010/10/how-good-c-habits-can-encourage-bad-javascript-habits-part-1/
(function( cursorManager ) {

    //From: http://www.w3.org/TR/html-markup/syntax.html#syntax-elements
    var voidNodeTags = ['AREA', 'BASE', 'BR', 'COL', 'EMBED', 'HR', 'IMG', 'INPUT', 'KEYGEN', 'LINK', 'MENUITEM', 'META', 'PARAM', 'SOURCE', 'TRACK', 'WBR', 'BASEFONT', 'BGSOUND', 'FRAME', 'ISINDEX'];

    //From: /206364/kak-proverit-soderzhit-li-massiv-obekt-v-javascript
    Array.prototype.contains = function(obj) {
        var i = this.length;
        while (i--) {
            if (this[i] === obj) {
                return true;
            }
        }
        return false;
    }

    //Basic idea from: https://stackoverflow.com/questions/19790442/test-if-an-element-can-contain-text
    function canContainText(node) {
        if(node.nodeType == 1) { //is an element node
            return !voidNodeTags.contains(node.nodeName);
        } else { //is not an element node
            return false;
        }
    };

    function getLastChildElement(el){
        var lc = el.lastChild;
        while(lc && lc.nodeType != 1) {
            if(lc.previousSibling)
                lc = lc.previousSibling;
            else
                break;
        }
        return lc;
    }

    //Based on Nico Burns's answer
    cursorManager.setEndOfContenteditable = function(contentEditableElement)
    {

        while(getLastChildElement(contentEditableElement) &&
              canContainText(getLastChildElement(contentEditableElement))) {
            contentEditableElement = getLastChildElement(contentEditableElement);
        }

        var range,selection;
        if(document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
        {    
            range = document.createRange();//Create a range (a range is a like the selection but invisible)
            range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
            range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
            selection = window.getSelection();//get the selection object (allows you to change selection)
            selection.removeAllRanges();//remove any selections already made
            selection.addRange(range);//make the range you have just created the visible selection
        }
        else if(document.selection)//IE 8 and lower
        { 
            range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
            range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
            range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
            range.select();//Select the range (make it the visible selection
        }
    }

}( window.cursorManager = window.cursorManager || {}));

Использование:

var editableDiv = document.getElementById("my_contentEditableDiv");
cursorManager.setEndOfContenteditable(editableDiv);

Таким образом, курсор обязательно располагается в конце последнего элемента, в конце концов, вложенного.

РЕДАКТИРОВАТЬ # 1 : Чтобы быть более общим, оператор while должен учитывать также все другие теги, которые не могут содержать текст. Эти элементы называются void elements , и в этот вопрос есть несколько методов проверки того, является ли элемент void. Итак, если предположить, что существует функция с именем canContainText, которая возвращает true, если аргумент не является пустым элементом, следующая строка кода:

contentEditableElement.lastChild.tagName.toLowerCase() != 'br'

следует заменить на:

canContainText(getLastChildElement(contentEditableElement))

РЕДАКТИРОВАТЬ # 2 : приведенный выше код полностью обновляется, все описанные и обсужденные изменения

4 голосов
/ 23 апреля 2019

Если вы не заботитесь о старых браузерах, этот мне помог.

// [optional] make sure focus is on the element
yourContentEditableElement.focus();
// select all the content in the element
document.execCommand('selectAll', false, null);
// collapse selection to the end
document.getSelection().collapseToEnd();
3 голосов
/ 22 января 2018

Можно установить курсор в конец диапазона:

setCaretToEnd(target/*: HTMLDivElement*/) {
  const range = document.createRange();
  const sel = window.getSelection();
  range.selectNodeContents(target);
  range.collapse(false);
  sel.removeAllRanges();
  sel.addRange(range);
  target.focus();
  range.detach(); // optimization

  // set scroll to the end if multiline
  target.scrollTop = target.scrollHeight; 
}
0 голосов
/ 15 января 2019

Перемещение курсора в конец редактируемого диапазона в ответ на событие фокуса:

  moveCursorToEnd(el){
    if(el.innerText && document.createRange)
    {
      window.setTimeout(() =>
        {
          let selection = document.getSelection();
          let range = document.createRange();

          range.setStart(el.childNodes[0],el.innerText.length);
          range.collapse(true);
          selection.removeAllRanges();
          selection.addRange(range);
        }
      ,1);
    }
  }

И вызов его в обработчике событий (Реагируйте здесь):

onFocus={(e) => this.moveCursorToEnd(e.target)}} 
0 голосов
/ 23 августа 2018

У меня была похожая проблема при попытке сделать элемент редактируемым. Это было возможно в Chrome и FireFox, но в FireFox каретка либо шла в начало ввода, либо проходила через один пробел после конца ввода. Я думаю, что очень запутанно для конечного пользователя, пытающегося редактировать контент.

Я не нашел решения, пробующего несколько вещей. Единственная вещь, которая работала для меня, состояла в том, чтобы "обойти проблему", поместив простой старый текстовый ввод ВНУТРИ моего. Теперь это работает. Похоже, «редактируемый контент» по-прежнему является передовой технологией, которая может работать, а может и не работать так, как вам хотелось бы, в зависимости от контекста.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...