Запретить добавление содержимого <div> на ENTER - Chrome


131

У меня есть contenteditableэлемент, и всякий раз, когда я набираю что-то и нажимаю, ENTERон создает новый <div>и помещает туда новый текст строки. Мне это немного не нравится.

Можно ли этого предотвратить или хотя бы просто заменить на <br>?

Вот демо http://jsfiddle.net/jDvau/

Примечание. В firefox это не проблема.


1
firefox добавляет <br>, хром - нет, но после исправления ваших стилей лишние div не нарушают левый отступ. Вопрос в том, почему тебе это не нравится? Думаю, это br ... jsfiddle.net/jDvau/1 Также вы можете использовать событие DOMSubtreeModified для захвата этих div и их удаления.
ViliusL 05

stackoverflow.com/questions/6024594/… это может вам помочь, удачи!
Sirikon 05

1
Для меня решение Блейка Пламба здесь самое простое и далеко не лучшее.
svassr

1
@svassr дело не в этом, это не вы или я будем его использовать, это клиент, который может даже не знать, что такое смещение.
iConnor

2
На самом деле это меняет все. Тем не менее, это обычное поведение, и небольшое справочное сообщение не поможет. «Дайте человеку рыбу, и вы накормите его на день. Научите человека ловить рыбу, и вы накормите его на всю жизнь».
svassr

Ответы:


161

Попробуй это:

$('div[contenteditable]').keydown(function(e) {
    // trap the return key being pressed
    if (e.keyCode === 13) {
        // insert 2 br tags (if only one br tag is inserted the cursor won't go to the next line)
        document.execCommand('insertHTML', false, '<br/>');
        // prevent the default behaviour of return key pressed
        return false;
    }
});

Нажмите здесь для демонстрации


Но я нахожу здесь небольшую разницу. Поместите курсор на пустую строку (в верхней части «Введите что-нибудь») и нажмите Enter. Курсор теперь находится непосредственно перед «Типом», а не на новой пустой строке.
Эндрю

3
Это не работает в IE11, так как он не поддерживает insertHTML. См. Ответ ниже!
веб-программист 01

4
Если вы поместите курсор между символами, например. «Ty [курсор] pe some stuff» и нажмите Enter, вы получите на 1 строку слишком много.
Чандрю

13
Ответ неприемлем.
Решением

3
это возвращает как <br>, так и <div>
Nishad Up

51

Вы можете сделать это, просто изменив CSS:

div{
    background: skyblue;
    padding:10px;
    display: inline-block;
}

pre{
    white-space: pre-wrap;
    background: #EEE;
}

http://jsfiddle.net/ayiem999/HW43Q/


1
Возникла проблема, когда я использовал встроенный блок, выполнял execCommand ("insertHTML", xxx) для вставки чего-либо, в конце вставленного элемента добавлялся "<br>", проверено в Chrome33.
Imskull

5
Хорошая находка. К сожалению, это не сработает с элементами position: absolute или элементами, которые являются прямыми дочерними элементами родительского элемента с display: flex. Вы можете взломать его, но помните об этом. Просто убедитесь, что он не является прямым потомком гибких элементов. Если вам нужно position: absolute, просто дайте ему дополнительного родителя.
Skeptic

@ReinoutvanKempen начал использовать flex уже 3 месяца назад. Думаю, этот хакер не сработает
Китту

это действительно отличное решение, оно предельно чистое и ясное, ничего не будет вставлено, даже включая br. и особенно это решение без js.
защищать orca

2
Вау ... это решает проблему Chrome, но заставляет Firefox начинать добавлять div при вводе, чего по умолчанию не происходит.
cbdeveloper

40

Добавить стиль display:inline-block;в contenteditable, он не будет создавать div, pи spanавтоматически в Chrome.


6
Это отличное решение. *[contenteditable="true"]{display: inline-block;}
ericjbasti 02

Люблю это, просто, но эффективно
user25794

В IE11 это добавит <p></p> :(
Betty St

1
но это создаст еще одну очень надоедливую ошибку Chrome (какой дерьмовый браузер)
vsync

4
Больше не работает с версией Chrome 63.0.3239.84
Микаэль Майер

21

Попробуй это:

$('div[contenteditable="true"]').keypress(function(event) {

    if (event.which != 13)
        return true;

    var docFragment = document.createDocumentFragment();

    //add a new line
    var newEle = document.createTextNode('\n');
    docFragment.appendChild(newEle);

    //add the br, or p, or something else
    newEle = document.createElement('br');
    docFragment.appendChild(newEle);

    //make the br replace selection
    var range = window.getSelection().getRangeAt(0);
    range.deleteContents();
    range.insertNode(docFragment);

    //create a new range
    range = document.createRange();
    range.setStartAfter(newEle);
    range.collapse(true);

    //make the cursor there
    var sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);

    return false;
});

http://jsfiddle.net/rooseve/jDvau/3/


Хорошо, работает :) Подожду еще внимания, прежде чем решу, спасибо.
iConnor 05

не работает должным образом в firefox. он добавляет одну дополнительную строку.
agpt 01

Это делает так, что inputпри нажатии клавиши ВВОД не запускается. Простое решение: добавить что-то вроде$(this).trigger('input')
LarsW

insertHTMLРешение делает некоторые странные вещи , когда Есть вложенные contenteditableэлементы, ваше решение , что обходит , но есть еще несколько вопросов, я добавил его в качестве нового возможного решения.
skerit

Не работает в Chrome. В первый раз, когда вы нажимаете Enter в конце строки, он добавляет пробел. Во второй раз все же работает.

20
document.execCommand('defaultParagraphSeparator', false, 'p');

Вместо этого он переопределяет поведение по умолчанию.

В Chrome поведение по умолчанию при вводе:

<div>
    <br>
</div>

С этой командой это будет

<p>
    <br>
</p>

Теперь, когда он более линейный, его легко получить, только <br>если вам нужно.


Когда вы нажимаете Enter, вместо div и br в браузере будут отображаться p и br. Попытайся.
Ced

Спасибо! Объяснения всегда полезны
jpaugh

@jpaugh np, я отредактировал свой ответ, чтобы он лучше объяснял.
Ced

это не работает в firefox (я тестировал только в chrome и firefox)
medBouzid

FireFox был исправлен, чтобы теперь уважать defaultParagraphSeparator. ИМХО, это делает этот ответ лучшим, поскольку он делает все браузеры согласованными и соответствующими спецификации. Если вы не хотите, чтобы у тега P был интервал поля от предыдущего текстового блока в редактируемом содержимом, вы можете использовать css для его изменения.
blackmamba

9

Используйте shift+ enterвместо того, enterчтобы просто вставить один <br>тег или обернуть текст <p>тегами.


9
+1 Спасибо, это очень удобно, но если у вас есть клиент, который пишет книгу, это будет
головной

1
Это не помогает, если вы
вставляете

5

То, contenteditableкак вы нажимаете, enterзависит от браузеров, это <div>происходит в webkit (chrome, safari) и IE.

Я боролся с этим несколько месяцев назад и исправил это следующим образом:

//I recommand you trigger this in case of focus on your contenteditable
if( navigator.userAgent.indexOf("msie") > 0 || navigator.userAgent.indexOf("webkit") > 0 ) {
    //Add <br> to the end of the field for chrome and safari to allow further insertion
    if(navigator.userAgent.indexOf("webkit") > 0)
    {
        if ( !this.lastChild || this.lastChild.nodeName.toLowerCase() != "br" ) {
            $(this).html( $(this).html()+'<br />' );
        }
    }

    $(this).keypress( function(e) {
        if( ( e.keyCode || e.witch ) == 13 ) {
            e.preventDefault();

            if( navigator.userAgent.indexOf("msie") > 0 ) {
                insertHtml('<br />');
            }
            else {
              var selection = window.getSelection(),
              range = selection.getRangeAt(0),
              br = document.createElement('br');

              range.deleteContents();
              range.insertNode(br);
              range.setStartAfter(br);
              range.setEndAfter(br);
              range.collapse(false);

              selection.removeAllRanges();
              selection.addRange(range);
            }
        }
    });
}

Я надеюсь, что это поможет, и извините за мой английский, если он не так понятен, как нужно.

РЕДАКТИРОВАТЬ : Исправление удаленной функции jQueryjQuery.browser


Просто чтобы вы знали, jQuery.browserбольше не является частью jQuery.
iConnor 06

Вы правы, я должен упомянуть об этом и использовать что-то вроде navigator.userAgent.indexOf("msie") > 0иnavigator.userAgent.indexOf("webkit") > 0
Эли

1
if( ( e.keyCode || e.witch ) == 13 ) { ... }должно бытьif (e.keyCode === 13 || e.which === 13) { ... }
Себастьян Сандквист

5

Вы можете иметь отдельные <p>теги для каждой строки вместо использования<br> теги, и получить большую совместимость с браузером прямо из коробки.

Для этого нужно поставить <p> тег с некоторым текстом по умолчанию внутри contenteditable div.

Например, вместо:

<div contenteditable></div>

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

<div contenteditable>
   <p>Replace this text with something awesome!</p>
</div>

jsfiddle

Протестировано в Chrome, Firefox и Edge, второй работает одинаково в каждом.

Первый, однако, создает div в Chrome, создает разрывы строк в Firefox, а в Edge создает div, и курсор возвращается в начало текущего div, а не перемещается в следующий.

Протестировано в Chrome, Firefox и Edge.


на самом деле это неплохое решение
AaronHS

5

Мне нравится использовать Mousetrap для работы с горячими клавишами: https://craig.is/killing/mice

Затем я просто перехватываю событие ввода, выполняя команду insertLineBreak :

Mousetrap.bindGlobal('enter', (e)=>{
  window.document.execCommand('insertLineBreak', false, null);
  e.preventDefault();
});

Все команды: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

Он работает с использованием Chrome 75 и следующего редактируемого элемента:

<pre contenteditable="true"></pre>

Также можно использовать insertHTML :

window.document.execCommand('insertHTML', false, "\n");

4

добавить предотвращение по умолчанию в div

document.body.div.onkeydown = function(e) {
    if ( e.keycode == 13 ){
        e.preventDefault();
            //add a <br>
        div = document.getElementById("myDiv");
        div.innerHTML += "<br>";
    }
}

@connorspiracist извините за это document.body.div(вам, вероятно, нужно будет ввести какой-то другой код, чтобы указать, чтобы исправить divего только общую идею)
Math chiller

4

Я бы использовал стиль (CSS), чтобы исправить проблему.

div[contenteditable=true] > div {
  padding: 0;
} 

Firefox действительно добавляет разрыв элемента блока
, тогда как Chrome оборачивает каждый раздел в тег. Ваш css дает divs отступ в 10 пикселей вместе с цветом фона.

div{
  background: skyblue;
  padding:10px;
}

В качестве альтернативы вы можете воспроизвести тот же желаемый эффект в jQuery:

var style = $('<style>p[contenteditable=true] > div { padding: 0;}</style>');
$('html > head').append(style);

Вот вилка вашей скрипки http://jsfiddle.net/R4Jdz/7/


1
Некоторым это может помочь, но меня больше беспокоила ненужная разметка, так как я бы взял окончательный HTML- contenteditable
код

3

Вы можете обернуть свои абзацы <p>тегом, например, он будет вставлен в новую строку вместо div. Пример:
<div contenteditable="true"><p>Line</p></div>
после вставки новой строки:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>


3

inserHTMLРешение команды делает некоторые странные вещи , когда у вас есть вложенные contenteditableэлементы.

Я взял несколько идей из нескольких ответов здесь, и сейчас это, похоже, соответствует моим потребностям:

element.addEventListener('keydown', function onKeyDown(e) {

    // Only listen for plain returns, without any modifier keys
    if (e.which != 13 || e.shiftKey || e.ctrlKey || e.altKey) {
        return;
    }

    let doc_fragment = document.createDocumentFragment();

    // Create a new break element
    let new_ele = document.createElement('br');
    doc_fragment.appendChild(new_ele);

    // Get the current selection, and make sure the content is removed (if any)
    let range = window.getSelection().getRangeAt(0);
    range.deleteContents();

    // See if the selection container has any next siblings
    // If not: add another break, otherwise the cursor won't move
    if (!hasNextSibling(range.endContainer)) {
        let extra_break = document.createElement('br');
        doc_fragment.appendChild(extra_break);
    }

    range.insertNode(doc_fragment);

    //create a new range
    range = document.createRange();
    range.setStartAfter(new_ele);
    range.collapse(true);

    //make the cursor there
    let sel = window.getSelection();
    sel.removeAllRanges();
    sel.addRange(range);

    e.stopPropagation();
    e.preventDefault();

    return false;
});

// See if the given node has a next sibling.
// Either any element or a non-empty node
function hasNextSibling(node) {

    if (node.nextElementSibling) {
        return true;
    }

    while (node.nextSibling) {
        node = node.nextSibling;

        if (node.length > 0) {
            return true;
        }
    }

    return false;
}


2

Сначала нам нужно захватить каждый ввод ключевого пользователя, чтобы увидеть, нажата ли клавиша ввода, затем мы предотвращаем <div>создание и создаем свой собственный<br> тег.

Есть одна проблема: когда мы создаем его, наш курсор остается в той же позиции, поэтому мы используем Selection API, чтобы поместить его в конец.

Не забудьте добавить <br>тег в конце вашего текста, потому что, если вы этого не сделаете, первый ввод не приведет к новой строке.

$('div[contenteditable]').on('keydown', function(e) {
    var key = e.keyCode,
        el  = $(this)[0];
    // If Enter    
    if (key === 13) {
        e.preventDefault(); // Prevent the <div /> creation.
        $(this).append('<br>'); // Add the <br at the end

        // Place selection at the end 
        // http://stackoverflow.com/questions/4233265/contenteditable-set-caret-at-the-end-of-the-text-cross-browser
        if (typeof window.getSelection != "undefined"
            && typeof document.createRange != "undefined") {
            var range = document.createRange();
            range.selectNodeContents(el);
            range.collapse(false);
            var sel = window.getSelection();
            sel.removeAllRanges();
            sel.addRange(range);
        } else if (typeof document.body.createTextRange != "undefined") {
            var textRange = document.body.createTextRange();
            textRange.moveToElementText(el);
            textRange.collapse(false);
            textRange.select();
        }
    }
});

скрипка


2

Это редактор HTML5, управляемый браузером. Вы можете обернуть свой текст <p>...</p>, затем всякий раз, когда вы нажимаете ENTER, вы получаете <p></p>. Кроме того, редактор работает таким образом, что всякий раз, когда вы нажимаете SHIFT + ENTER, он вставляет <br />.

<div contenteditable="true"><p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolor veniam asperiores laudantium repudiandae doloremque sed perferendis obcaecati delectus autem perspiciatis aut excepturi et nesciunt error ad incidunt impedit quia dolores rerum animi provident dolore corporis libero sunt enim. Ad magnam omnis quidem qui voluptas ut minima similique obcaecati doloremque atque!
<br /><br />
Type some stuff, hit ENTER a few times, then press the button.
</p>
</div>

Проверьте это: http://jsfiddle.net/ZQztJ/


2

Это работает во всех основных браузерах (Chrome, Firefox, Safari, Edge).

document.addEventListener('keydown', event => {
  if (event.key === 'Enter') {
    document.execCommand('insertLineBreak')
    event.preventDefault()
  }
})
<div class="element" contenteditable="true">Sample text</div>
<p class="element" contenteditable="true">Sample text</p>

Есть одно неудобство. После завершения редактирования элементы могут содержать окончание <br>внутри. Но вы можете добавить код, чтобы сократить это, если вам нужно.

Отметьте этот ответ, чтобы удалить завершающий <br> https://stackoverflow.com/a/61237737/670839


Какого черта? Как может единственное решение, которое действительно сработало для меня, находиться так далеко на странице? Спасибо.
user12861

1
if (navigator.userAgent.toLowerCase().indexOf('msie') > -1) {
   var range = document.getSelection();
   range.pasteHTML(range.htmlText + '<br><br>');
}
else if(navigator.userAgent.toLocaleLowerCase().indexOf('trident') > -1)                           {
   var range = document.getSelection().getRangeAt(0); //get caret
   var nnode = document.createElement('br');
   var bnode = document.createTextNode('\u00A0'); //&nbsp;
   range.insertNode(nnode);
   this.appendChild(bnode);
   range.insertNode(nnode);                                
}
else
   document.execCommand('insertHTML', false, '<br><br>')

Где thisфактический контекст, что означает document.getElementById('test');.


0

Другой способ сделать это

$('button').click(function(){
    $('pre').text($('div')[0].outerHTML)
});

$("#content-edit").keydown(function(e) {
    if(e.which == 13) {
       $(this).find("div").prepend('<br />').contents().unwrap();
      }
});

http://jsfiddle.net/jDvau/11/


Курсор не может двигаться вперед по мере ввода.
Джек Лу,

Это странно, я только что попробовал в Chrome и IE 11, и он отлично работает. Ссылка Подскажите, пожалуйста, какой браузер вы используете? Более подробная информация о поведении будет полезна для решения проблемы
MrAJ

0

Предотвратить создание нового Div в редактируемом Div для каждой клавиши ввода: Решение, которое я нашел, очень простое:

var newdiv = document.createElement("div"); 
newdiv.innerHTML = "Your content of div goes here";
myEditablediv.appendChild(newdiv);

Это --- содержимое innerHTML предотвращает создание нового Div в редактируемом содержимом Div при каждой клавише ввода.


0

В черновике редактора W3C есть некоторая информация о добавлении состояний в ContentEditable , а также о том, чтобы запретить браузеру добавлять новый элемент при нажатии клавиши ввода, вы можете использовать plaintext-only.

<div contentEditable="plaintext-only"></div>

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.