Почему мой контент-ориентированный курсор прыгает до конца в Chrome?
Сценарий
У меня есть contenteditable <div>
область, и внутри этой области у меня может быть некоторый <span contenteditable="false"></span>
содержащий некоторый текст. Идея состоит в том, что эти элементы span будут представлять собой стилизованный текст, который нельзя редактировать, но его можно удалить из области <div contenteditable="true"></div>
, нажав клавишу возврата.
Проблема
Размещение курсора здесь большое. если вы удалите один из этих элементов <span>
, курсор переместится в конец <div>
. Более интересно, если вы набираете текст, когда курсор находится "в конце", размещение текста просто отлично... Затем, если вы удаляете только что напечатанный текст, курсор отскакивает назад!
Я подготовил скрипку, которая продемонстрирует это. Мне нужно, чтобы это работало только в Chrome, а другие браузеры сейчас либо неактуальны, либо имеют обходные пути. (Также обратите внимание, что подготовленный Fiddle создан для демонстрации этого только в Chrome).
Fiddle
Инструкция Fiddle: Версия Chrome версии 39.0.2171.95 м (64-разрядная версия), воспроизводимая также в 32-разрядной версии
- Нажмите
<div>
область
- Введите "123"
- Backspace "3" Backspace "2" Backspace "1"
![enter image description here]()
Дополнительные сведения
Внимательно изучив это, я столкнулся с различными вопросами SO, которые похожи, но заимствование связанных решений не оказалось серебряной пулей, которой я пользуюсь. Я также обнаружил проблемы для проекта Chrome, которые, похоже, нацелены (возможно, не в точном порядке) на проблему, описанную выше, и могут быть просмотрены ниже.
Ближайшее решение SO, которое я нашел, может быть здесь. Идея в этом решении состоит в размещении ‌
символов после элементов <span>
, но если я хочу удалить мой <span>
, вместо этого я удалю ‌
... заставляя мой курсор прыгать до конца, предлагая странный опыт пользовательского интерфейса, не удаляя мой <span>
по моему "начальному удалению ключа".
Вопрос
Кто-нибудь испытал эту проблему и нашел работу? Я приветствую любое возможное решение, даже когда JS взломан, когда они приходят. Я пришел к выводу, что использование contenteditable
сопровождается списком белья, но это, по-видимому, последняя оставшаяся трудность, которую я сейчас испытываю.
Ответы
Ответ 1
Я не знаю, почему это происходит, но у меня было ощущение, что это имеет отношение к размеру <div>
, поэтому я попытался сыграть с свойством display
. Установив его на inline-block
и немного поиграв с текстом, я обнаружил, что проблема исчезла после внесения некоторых изменений в нее, в частности, добавив новую строку.
Я видел, что по какой-то причине тег <br/>
хранится в div.main
после удаления моей новой строки, но внешний вид <div>
и способ, которым он отвечает на клавиши со стрелками, такие же, как если бы в нем нет новой линии.
Итак, я перезапустил скрипт с изменением CSS и тегом <br/>
в div.main
и альта!
Итак, заключаем:
- Добавить
display: inline-block
в div.main
- добавить
<br/>
в конец div.main
ссылка JSFiddle
Ответ 2
Проблема заключается в том, что ваш элемент contenteditable
является div
, который по умолчанию - display: block
. Это то, что вызывает проблему с позицией каретки. Это можно устранить, сделав внешний div
нередактируемым и добавив новый редактируемый div
, который будет обрабатываться как inline-block
.
Новый HTML будет иметь новый div
только внутри внешнего (и соответствующий закрывающий тег в конце):
<div id="main" class="main"><div id="editable" contenteditable="true">...
И добавьте это в свой CSS:
div#editable {
display: inline-block;
}
Для того, чтобы лучше видеть карету, когда она находится между элементами span
, я также добавил margin: 2px
в правило для div.main span
в CSS, но это не обязательно для предотвращения сообщения о проблеме с кареткой в вопросе.
Вот fiddle.
По мере того как вы начали обнаруживать, contenteditable
обрабатывается непоследовательно в браузерах. Несколько лет назад я начал работать над проектом (в редакторе XML в браузере), где, как я думал, contenteditable
сделает все проще. Затем, когда я разработал приложение, я вскоре обнаружил, что беру на себя функции, которые, как я думал, contenteditable
предоставит мне бесплатно. Сегодня только contenteditable
дает мне то, что он включает события клавиатуры на элементах, которые я хочу редактировать. Все остальное, включая движение каретки и отображение каретки, управляется пользовательским кодом.
Ответ 3
Итак, у меня есть немного более чистая реализация вашего подхода, который опирается на событие input
, которое запускается, когда a contenteditable
обновляется. Это событие не поддерживается IE, но похоже, что contenteditable
в любом случае довольно неуловимо в IE.
Он в основном вводит элементы вокруг каждого элемента, помеченного как contenteditable="false"
. Вероятно, это может быть сделано при начальной загрузке, а не только в событии input
, но я решил, что у вас могут быть способы ввода большего количества span
в область, поэтому input
должен учитывать это.
Ограничения включают некоторое странное поведение, окружающее клавиши со стрелками, как вы видели себя. В основном то, что я видел, заключается в том, что курсор сохраняет свое правильное положение, когда вы перемещаетесь назад через промежутки, но не тогда, когда вы двигаетесь вперед.
ссылка JSFiddle
Javascript
$('#main').on('input', function() {
var first = true;
$(this).contents().each(function(){
if ($(this).is('[contenteditable=false]')) {
$("<i class='wrapper'/>").insertAfter(this);
if (first) {
$("<i class='wrapper'/>").insertBefore(this);
first = false
}
}
});
}).trigger('input');
CSS
div.main {
width: 400px;
height: 250px;
border: solid 1px black;
}
div.main span {
width:40px;
background-color: red;
border-radius: 5px;
color: white;
cursor: pointer;
}
i.wrapper {
font-style: normal;
}
Ответ 4
Я нашел хакерский способ решить начальную проблему с ошибкой в конце <div>
с некоторым JQuery. Я в основном вставляю пустой <i>
для курсора для "фиксации" в конце содержимого <div>
. Этот тег работает для меня, потому что для конечного пользователя нет разницы в пользовательском интерфейсе, если отменить его из обычного текста из-за переопределения font-style: normal
(см. Скрипку), и мне также понадобилось что-то другое, чем <span>
, чтобы вставить
Я не особенно взволнован этим обходным решением, особенно выбрав <i>
только потому, что, но у меня нет лучшей альтернативы, и я по-прежнему приветствую лучшие решения, если они существуют!. Я планирую продолжать работать над этим, чтобы, надеюсь, выяснить стрелки, но, к счастью, меня беспокоит только этот глюк в скрипке, а не мой код.
Fiddle (только для Chrome)
<div id="main" contenteditable="true">
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
</div>
function hackCursor() {
return $('#main :last-child').get(0).tagName === 'SPAN' ?
$('#main span:last-child').after('<i style="font-style: normal"></i>') :
false;
}
$(function(){
hackCursor();
$('#main').bind({
'keyup': function(e) {
hackCursor();
}
})
});
Ответ 5
Просто добавьте новую строку char (\n
) перед закрытием тега contenteditable
.
Например, в JavaScript:
var html = '<div id="main" contenteditable="true">' + content + "\n" + '</div>'