removeChild иногда удаляет весь диапазон, а иногда нет

Я работаю над текстовым редактором для iOS, и большая его часть работает, но сталкиваюсь с бесконечными проблемами, обеспечивающими видимость курсора в окне просмотра, когда пользователь начинает печатать.

Я придумал новый подход: вставить диапазон в позицию курсора, прокрутить до диапазона, а затем удалить его. (Я не стал прокручивать только в том случае, если диапазон отображается на экране.) Вот что я написал:

document.addEventListener('keypress', function(e) {            
   jumpToID();
}, false);

function jumpToID() {
  var id = "jumphere2374657";
  var text = "<span id='" + id + "'>&nbsp;</span>"
  document.execCommand('insertHTML', false, text);
  var element = document.getElementById(id);
  element.scrollIntoView();
  element.parentNode.removeChild(element);
}

В некоторых случаях это работает просто отлично, а в некоторых случаях между каждым нажатием клавиши остается неразрывный пробел, удаляя только теги ‹span>‹/span>. Есть идеи? Я открыт для лучших способов сделать это, если у кого-то есть предложения. Я немного шокирован тем, как сложно заставить курсор появляться, но JS для меня новичок.

ИЗМЕНИТЬ

Это код, который работает:

var viewportHeight = 0;

function setViewportHeight(vph) {
  viewportHeight = vph;
  if(viewportHeight == 0 && vph != 0)
    viewportHeight = window.innerHeight;
}

function getViewportHeight() {
  if(viewportHeight == 0)
    return window.innerHeight;
  return viewportHeight;
}

function makeCursorVisible() {
  var sel = document.getSelection();                  // change the selection
  var ran = sel.getRangeAt(0);                        // into a range
  var rec = ran.getClientRects()[0];                  // that we can get coordinates from
  if (rec == null) {
    // Can't get coords at start of blank line, so we
    // insert a char at the cursor, get the coords of that,
    // then delete it again. Happens too fast to see.
    ran.insertNode( document.createTextNode(".") );
    rec = ran.getClientRects()[0];  // try again now that there's text
    ran.deleteContents();
  }
  var top = rec.top;               // Y coord of selection top edge
  var bottom  = rec.bottom;        // Y coord of selection bottom edge
  var vph = getViewportHeight();
  if (top < 0)      // if selection top edge is above viewport top,
    window.scrollBy(0, top);  // scroll up by enough to make the selection top visible
  if (bottom >= vph)   // if selection bottom edge is below viewport bottom,
    window.scrollBy(0, bottom-vph + 1); // scroll down by enough to make the selection bottom visible
}

ViewportHeight сложнее, чем нужно для веб-приложения. Для мобильного приложения нам нужно учитывать клавиатуру, поэтому предлагаем метод для установки viewportHeight вручную, а также автоматическую настройку из window.innerHeight.


person eliajf    schedule 04.10.2012    source источник
comment
Что делает .execCommand('undo', .. вместо использования removeChild?   -  person Paul S.    schedule 05.10.2012
comment
Спасибо за ответ. Я пробовал это. Это тоже не работает.   -  person eliajf    schedule 05.10.2012
comment
Я вижу что-то здесь. В contentEditable он создает тег ‹div›‹/div› вокруг каждой строки, поэтому происходит следующее: заставьте строку 1‹br›строку 2 и отредактируйте там, она этого не делает, но если я ввожу ее в div, она делает.   -  person eliajf    schedule 05.10.2012


Ответы (1)


Я не знаю, будет ли это работать на iOS, но если положение курсора означает, что в этой точке есть выделение..

function moveToSelection(){
    var sel = document.getSelection(), // change the selection
        ran = sel.getRangeAt(0),       // into a range
        rec = ran.getClientRects()[0], // that we can get co-ordinates from
        dy  = rec.top;                 // distance to move down/up
    window.scrollBy( 0, dy );          // actual move

    // console.log( sel, ran, rec, y );   // help debug
}

moveToSelection();

Соответствующие ссылки

  1. getSelection
  2. getRangeAt
  3. getClientRects
  4. scrollBy
person Paul S.    schedule 05.10.2012
comment
Кажется, это совсем близко. Однако я получаю неопределенную ошибку для записи, если я набираю клавишу сразу после новой строки. Это означает, что курсор находится внутри «‹div›‹br›‹div›», и я предполагаю, что он не может сформировать прямоугольник, если нет текста. Любые предложения, как настроить для этого экземпляра? Кроме того, если у вас есть какие-либо идеи, как не прокручивать, если курсор уже находится в окне просмотра, я тоже был бы признателен. В настоящее время он автоматически переходит наверх, даже если курсор уже находился в окне просмотра. Спасибо, что нашли время! - person eliajf; 05.10.2012
comment
Чтобы не прокручивать, проверьте, меньше ли dy высоты области просмотра. Что касается undefined, узнайте значение диапазона в этом случае, добавьте для него проверку и либо игнорируйте этот случай, либо выполните другое действие (например, прокрутите до последнего <br> - person Paul S.; 05.10.2012
comment
Спасибо @shhac! Мы заработали. Я опубликую окончательный код позже, так как сначала нам нужно кое-что почистить. - person eliajf; 05.10.2012
comment
Хм, это определенно работает, но я не совсем понимаю, как rec.top представляет dy? - person Kevin Lee; 20.09.2017
comment
@KevinLee developer.mozilla.org/en-US/docs/ Web/API/DOMRectReadOnly/top таблица поддержки внизу не отражает поддержку приведенного выше кода, поскольку страница mdn относится к разделу дерева прототипов, который не обязательно совпадает, но имеет пересечение реализация - person Paul S.; 20.09.2017