Impedir a adição editável de conteúdo <div> no ENTER - Chrome


131

Eu tenho um contenteditableelemento, e sempre que digito algumas coisas e clico ENTERnele, cria um novo <div>e coloca o novo texto de linha lá. Eu não gosto disso nem um pouco.

É possível impedir que isso aconteça ou pelo menos apenas substituí-lo por um <br>?

Aqui está a demonstração http://jsfiddle.net/jDvau/

Nota: Este não é um problema no Firefox.


1
o firefox adiciona <br>, chrome - não, mas depois de corrigir seus estilos, divs extras não quebram o preenchimento esquerdo. A pergunta é por que você não gosta? Pense ... jsfiddle.net/jDvau/1 Também é possível usar o evento DOMSubtreeModified para capturar essas divs e removê-las.
precisa saber é o seguinte


1
Para mim, a solução de Blake Plumb é a mais simples e de longe a melhor aqui.
precisa

1
@svassr esse não é o ponto, não é você ou eu que o usaremos, é um cliente que pode nem saber o que é essa mudança.
IConnor

2
De fato, muda tudo. Dito isto, é um comportamento comum e uma pequena mensagem de ajuda não seria aceita. "Dê a um homem um peixe e você o alimentará por um dia. Ensine um homem a pescar e você o alimentará por toda a vida."
svassr

Respostas:


161

Tente o seguinte:

$('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;
    }
});

Clique aqui para demonstração


Mas acho uma pequena diferença aqui. Coloque o cursor na linha em branco (na parte superior de "Digite algumas coisas") e pressione Enter. O cursor está agora imediatamente antes do "Tipo", não na nova linha em branco.
Andrew

3
Isso não funciona no IE11, pois não suporta insertHTML. Veja a resposta abaixo!
Webprogrammer

4
Se você colocar o cursor entre os caracteres, por exemplo. 'Ty [cursor] pe some stuff' e pressione enter, você tem 1 linha a mais.
Chandrew 27/05

13
A resposta não é aceitável. Solução seria ter apenas um <br />
raoulinski

3
esse retorno, tanto como <div>
Nishad Up 10/09/2015

51

Você pode fazer isso apenas com uma alteração de CSS:

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

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

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


1
Ocorreu um problema quando usei o bloco embutido, execute execCommand ("insertHTML", xxx) para inserir qualquer coisa; um "<br>" será adicionado no final do elemento inserido, testado no Chrome33.
Imskull

5
Bom achado. Infelizmente, isso não funciona na posição: elementos absolutos ou elementos que são filhos diretos de um pai com display: flex. Você pode fazer isso funcionar, mantendo isso em mente. Apenas certifique-se de que não é um filho direto de elementos flexíveis. Se você precisar da posição: absoluta, dê a ela um pai ou mãe extra com isso.
Céptico 03/03

@ReinoutvanKempen Começou a usar o flex há 3 meses. Eu acho que este hack não vai funcionar
Kittu

Esta é realmente a melhor solução, é extremamente limpa e clara, nada será inserido, incluindo o br. e especialmente esta solução sem js.
defender orca

2
Uau ... isso resolve o Chrome, mas faz o Firefox começar a adicionar divs no enter, o que não acontece por padrão.
Cbdeveloper 24/04/19

40

Adicione o estilo display:inline-block;a contenteditable, não vai gerar div, pe spanautomaticamente no Chrome.


6
Esta é uma otima soluçao. *[contenteditable="true"]{display: inline-block;}
217156 Erickson escreveu

Love it, simples, mas eficaz
user25794

No IE11, isso fará um extra <p></p> :(
Betty St

1
mas criará outro bug do Chrome muito irritante (que navegador de merda)
vsync 14/16

4
Não funciona mais com o Chrome Versão 63.0.3239.84
Mikaël Mayer

21

Tente o seguinte:

$('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/


Bom, funciona :) Vou aguardar mais atenção antes de decidir, obrigado.
IConnor

não funciona corretamente no firefox. adiciona uma linha extra.
agpt 01/07

Isso faz com que inputnão seja acionado quando você pressiona enter. Uma solução simples: add sth como$(this).trigger('input')
LarsW

A insertHTMLsolução faz algumas coisas estranhas quando existem contenteditableelementos aninhados , sua solução contorna isso, mas há mais alguns problemas, eu a adicionei como uma nova solução possível.
Skerit 31/07/19

Não funciona no Chrome. A primeira vez que você pressiona enter no final da string, ele adiciona um espaço. A segunda vez que funciona embora.

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

Ele substitui o comportamento padrão para ter um parágrafo.

No chrome, o comportamento padrão em enter é:

<div>
    <br>
</div>

Com esse comando, vai ser

<p>
    <br>
</p>

Agora que é mais linear, é fácil ter apenas <br>o necessário.


Quando você pressiona enter, em vez de ter div e br, você terá p e br no navegador. Tente.
Ced

Obrigado! As explicações são sempre úteis
Jpaugh 25/02

@ jpaugh np, editei minha resposta ainda mais para que ela explique melhor.
Ced

isso não funciona no firefox (I testado no Chrome e Firefox apenas)
medBouzid

O FireFox foi corrigido para agora respeitar o defaultParagraphSeparator. IMHO isso faz com que esta resposta seja a melhor, pois torna todos os navegadores consistentes e alinhados com as especificações. Se você não deseja que uma tag P tenha um 'espaçamento' de margem do bloco de texto anterior no conteúdo editável, use o css para modificá-lo.
Blackmamba

9

Use shift+ em entervez de enterapenas inserir uma única <br>tag ou agrupar seu texto em <p>tags.


9
+1 Obrigado, isso é muito útil para saber, mas se você tiver um cliente que está escrevendo um livro, isso será uma
chatice

1
Isso não ajuda se você estiver colando conteúdo
vsync 21/10

5

O modo como contenteditablese comporta quando você pressiona enterdepende dos navegadores, o que <div>acontece no webkit (chrome, safari) e no IE.

Eu lutei com isso há alguns meses e corrigi-o desta maneira:

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

Espero que ajude, e desculpe pelo meu inglês, se não estiver tão claro quanto necessário.

EDIT : Correção da função jQuery removidajQuery.browser


Só para que você saiba, jQuery.browsernão faz mais parte do jQuery.
IConnor 06/12/2018

Você tem razão, eu deveria mencionar isso e usar algo como navigator.userAgent.indexOf("msie") > 0enavigator.userAgent.indexOf("webkit") > 0
Elie

1
if( ( e.keyCode || e.witch ) == 13 ) { ... }precisa serif (e.keyCode === 13 || e.which === 13) { ... }
Sebastian Sandqvist 04/04

5

Eu gosto de usar a ratoeira para manipular teclas de atalho: https://craig.is/killing/mice

Então, apenas intercepto o evento enter, executando um comando insertLineBreak :

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

Todos os comandos: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

Funciona usando o Chrome 75 e o seguinte elemento editável:

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

Também é possível usar o insertHTML :

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

4

adicione um padrão de prevenção à div

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

@connorspiracist desculpe sua document.body.div(você provavelmente terá que colocar em algum outro código para apontar para corrigir divo seu apenas a idéia geral)
Math chiller

4

Eu usaria o estilo (Css) para corrigir o problema.

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

O Firefox realmente adiciona uma quebra de elemento de bloco
, enquanto o Chrome envolve cada seção em uma tag. Você css fornece aos divs um preenchimento de 10px junto com a cor de fundo.

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

Como alternativa, você pode replicar o mesmo efeito desejado no jQuery:

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

Aqui está um garfo do seu violino http://jsfiddle.net/R4Jdz/7/


1
Isto pode ajudar algumas pessoas, mas eu estava mais preocupado com a marcação unessasary, como eu estaria tomando o HTML final do contenteditablee usá-lo em outros lugares
iConnor

4

Você pode ter <p>tags separadas para cada linha, em vez de usar <br>tags e obter maior compatibilidade com o navegador imediatamente.

Para fazer isso, coloque uma <p>tag com algum texto padrão dentro da div contenteditable.

Por exemplo, em vez de:

<div contenteditable></div>

Usar:

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

jsfiddle

Testado no Chrome, Firefox e Edge, e o segundo funciona da mesma maneira em cada um.

O primeiro, no entanto, cria divs no Chrome, cria quebras de linha no Firefox e no Edge cria divs e o cursor é colocado de volta no início da div atual, em vez de passar para a próxima.

Testado no Chrome, Firefox e Edge.


este não é realmente uma má solução
AaronHS

3

Você pode <p>agrupar seus parágrafos com a tag, por exemplo, apareceria na nova linha em vez de div Exemplo:
<div contenteditable="true"><p>Line</p></div>
Após inserir uma nova string:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>


3

A inserHTMLsolução de comando faz algumas coisas estranhas quando você aninha contenteditableelementos.

Peguei algumas idéias de várias respostas aqui, e isso parece atender às minhas necessidades por enquanto:

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

Primeiro, precisamos capturar cada usuário-chave enter para ver se enter é pressionado, então evitamos a <div>criação e criamos nossa própria <br>tag.

Há um problema: quando o criamos, nosso cursor permanece na mesma posição, por isso usamos a API de seleção para colocar nosso cursor no final.

Não se esqueça de adicionar uma <br>tag no final do seu texto, porque se você não inserir o primeiro, não criará uma nova linha.

$('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();
        }
    }
});

Violino


2

Este é o editor HTML5 direcionado ao navegador. Você pode agrupar seu texto e <p>...</p>, sempre que pressionar ENTER, obtém <p></p>. Além disso, o editor funciona dessa maneira que sempre que você pressiona SHIFT + ENTER, ele é inserido <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>

Verifique isso: http://jsfiddle.net/ZQztJ/


2

Isso funciona em todos os principais navegadores (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>

Há um inconveniente. Depois de terminar a edição, os elementos podem conter uma final <br>dentro. Mas você pode adicionar código para reduzi-lo, se necessário.

Verifique esta resposta para remover o https://stackoverflow.com/a/61237737/670839 à direita<br>


Que diabos? Como a única solução que realmente funcionou para mim está tão abaixo na página? Muito obrigado.
user12861 27/07

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

Onde thisestá o contexto atual, o que significa document.getElementById('test');.


0

Outra maneira de fazer isso

$('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/


Não permite que o cursor avance enquanto você digita.
Jack Lu

Isso é estranho, eu apenas tentei no Chrome e IE 11 e funciona bem. Referência Você poderia me dizer qual navegador está usando? Mais detalhes sobre o comportamento seriam úteis para resolver o problema
MrAJ

0

Impedir a criação de novas div no conteúdo editável Div em cada tecla enter: Solução que eu acho muito simples:

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

Esse conteúdo --- innerHTML impede a criação de Nova Div no Div editável de conteúdo em cada tecla Enter.


0

No rascunho do editor do W3C, há algumas informações sobre como adicionar estados ao ContentEditable e para impedir que o navegador adicione novos elementos ao pressionar enter, você pode usar plaintext-only.

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

-1

É possível impedir esse comportamento completamente.

Veja este violino

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.