Не допускайте додавання <div> на ENTER - Chrome


131

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

Чи можна не допустити цього або хоча б просто замінити його на <br>?

Ось демонстрація http://jsfiddle.net/jDvau/

Примітка. Це не проблема у Firefox.


1
firefox додає <br>, хром - ні, але після виправлення стилів додаткові диви не зламають ліву підкладку. Питання, чому вам це не подобається? Думаю, що це ... jsfiddle.net/jDvau/1 Також ви можете використовувати подію DOMSubtreeModified, щоб спіймати цих дівок та видалити їх.
ViliusL

stackoverflow.com/questions/6024594/… це може допомогти вам, удачі!
Sirikon

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. Дивіться відповідь нижче!
програміст

4
Якщо ви кладете курсор між символами, наприклад. "Введіть [курсор] певний матеріал" і натисніть клавішу Enter, ви отримаєте 1 рядок занадто багато.
Чандрю

13
Відповідь не прийнятна. Рішенням було б мати лише один <br />
raoulinski

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
Виникла проблема, коли я використав inline-block, виконати execCommand ("insertHTML", xxx), щоб вставити що-небудь, в кінці вставленого елемента буде протестовано "<br>", протестований у Chrome33.
Імскулл

5
Приємна знахідка. На жаль, це не буде працювати на позиції: абсолютні елементи або елементи, які є прямими дітьми батьків із дисплеєм: flex. Ви можете зламати його, щоб він працював, маючи це на увазі. Просто переконайтеся, що це не прямий дочірник з гнучких елементів. Якщо вам потрібна позиція: абсолютний просто дайте йому додатковий батько з цим.
Скептик

@ReinoutvanKempen Почав використовувати flex вже 3 місяці тому. Я думаю, цей злом не буде працювати
kittu

це дійсно дійсно найбільше рішення, воно надзвичайно чисте і чітке, нічого не буде вставлено, навіть включити бр. і особливо це рішення без js.
захищати orca

2
Нічого ... це вирішує Chrome, але змушує Firefox починати додавати знаки при введенні, що не за замовчуванням.
cbdeveloper

40

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


6
Це чудове рішення. *[contenteditable="true"]{display: inline-block;}
ericjbasti

Любіть це, просто, але ефективно
користувач25794

У IE11 це зробить додаткове <p></p> :(
Betty St

1
але це створить ще одну дуже дратівливу помилку Chrome (що за
чорткий

4
Більше не працює з версією Chrome 63.0.3239.84
Mikaël Mayer

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

не працює належним чином у Firefox. це додає один додатковий рядок.
agpt

Це робить його таким, що inputне спрацьовує при натисканні клавіші Enter. Просте рішення: додайте що$(this).trigger('input')
небудь на

insertHTMLРішення робить деякі дивні речі , коли Є вкладені contenteditableелементи, ваше рішення , що обходить , але є ще кілька питань, я додав його в якості нового можливого рішення.
skerit

Не працює в Chrome. Перший раз, коли ви натискаєте клавішу Enter в кінці рядка, це додає пробіл. Хоча вдруге це працює.

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

Він переосмислює поведінку за замовчуванням, щоб натомість був абзац.

Що стосується chrome, типова поведінка при введенні:

<div>
    <br>
</div>

З цією командою це буде

<p>
    <br>
</p>

Тепер, коли це лінійніше поперек, це легко мати тільки <br>вам потрібно.


Якщо натиснути клавішу Enter, замість того, щоб мати div та br, ви матимете браузер p і br Across. Спробуй це.
Ced

Дякую! Пояснення завжди корисні
jpaugh

@jpaugh np, я змінив свою відповідь далі, щоб вона пояснила краще.
Сід

це не працює на firefox (я протестував лише на хромі та firefox)
medBouzid,

FireFox був виправлений, щоб тепер поважати defaultParagraphSeparator. IMHO це робить цю відповідь найкращою, оскільки вона робить усі браузери тепер узгодженими та упорядкованими. Якщо ви не хочете, щоб тег P мав "проміжок" на полях від попереднього текстового блоку у вмісті, який можна редагувати, ви можете використовувати css, щоб змінити це.
blackmamba

9

Використовуйте shift+, enterа enterне просто вставляйте один <br>тег або загортайте текст у <p>теги.


9
+1 Спасибі, це дуже зручно знати, але якщо у вас є клієнт, який пише книгу, це буде біль у ***
iConnor

1
Це не допоможе, якщо ви вставляєте вміст
vsync

5

Те, як contenteditableповодиться при натисканні, enterзалежить від веб-переглядачів<div> трапляється в webkit (хром, сафарі) та 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);
            }
        }
    });
}

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

EDIT : Виправлення видаленої функції jQueryjQuery.browser


Тільки щоб повідомити вас, jQuery.browserце вже не частина jQuery.
iConnor

Ви маєте рацію, я повинен згадати це і використовувати щось на кшталт 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>тег з деяким текстом за замовчуванням всередині вмісту, що містить вміст

Наприклад, замість:

<div contenteditable></div>

Використання:

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

jsfiddle

Тестується в Chrome, Firefox та Edge, а другий працює однаково у кожному.

Перший, однак, створює діви в Chrome, створює розриви рядків у Firefox, а в Edge створює divs і курсор ставиться назад на початку поточного div, а не переходить до наступного.

Тестували в Chrome, Firefox та Edge.


це насправді не є поганим рішенням
AaronHS

5

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

Потім я просто перехоплюю подію enter, виконуючи команду 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і використовував його в іншому місці
iConnor

3

Ви можете обернути свої абзаци <p>тегом, наприклад, він буде поміщатися в новому рядку замість діва Приклад:
<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

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

Є одна проблема: коли ми створюємо його, наш курсор залишається в тому ж самому положенні, тому ми використовуємо 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


Якого біса? Як єдиним рішенням, яке насправді працювало для мене, може бути далеко внизу сторінки? Дуже дякую.
користувач12861

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

Цей --- внутрішній вміст HTMLML перешкоджає створенню New Div у вмісті, редагованому Div, на кожній клавіші введення.


0

У проекті редактора W3C міститься деяка інформація про додавання станів у ContentEditable , а також запобігання веб-переглядачу для додавання нового елемента при натисканні клавіші enter, яку ви можете використовувати plaintext-only.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.