Evite agregar contenido <div> en ENTER - Chrome


131

Tengo un contenteditableelemento, y cada vez que escribo algo y ENTERlo presiono crea uno nuevo <div>y coloca el nuevo texto de línea allí. No me gusta este poquito.

¿Es posible evitar que esto suceda o al menos simplemente reemplazarlo con un <br>?

Aquí está la demostración http://jsfiddle.net/jDvau/

Nota: Esto no es un problema en Firefox.


1
firefox agrega <br>, chrome - not, pero después de arreglar sus estilos, los divs adicionales no rompen el relleno izquierdo. La pregunta es ¿por qué no te gusta? Piensa que es br ... jsfiddle.net/jDvau/1 También puedes usar el evento DOMSubtreeModified para capturar estos divs y eliminarlos.
ViliusL

stackoverflow.com/questions/6024594/… esto podría ayudarte, ¡buena suerte!
Sirikon

1
Para mí, la solución de Blake Plumb es la más simple y, de lejos, la mejor aquí.
svassr

1
@svassr ese no es el punto, no somos tú o yo quienes lo usaremos, es un cliente que puede que ni siquiera sepa qué es el cambio.
iConnor

2
De hecho, lo cambia todo. Dicho esto, es un comportamiento común y no se armaría un pequeño mensaje de ayuda. "Dale un pescado a un hombre y lo alimentarás por un día. Enseña a un hombre a pescar y lo alimentarás toda la vida".
svassr

Respuestas:


161

Prueba esto:

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

Haga clic aquí para ver una demostración


Pero encuentro una pequeña diferencia aquí. Coloque el cursor en la línea en blanco (en la parte superior de "Escriba algunas cosas") y presione Entrar. El cursor ahora está justo antes del "Tipo", no en la nueva línea en blanco.
Andrew

3
Esto no funciona en IE11 ya que no admite insertHTML. Ver respuesta a continuación!
webprogrammer

44
Si coloca el cursor entre los caracteres, por ejemplo. 'Ty [cursor] pe algunas cosas' y presiona enter, obtienes 1 línea demasiado.
Chandrew

13
La respuesta no es aceptable. La solución sería tener solo uno <br />
raoulinski

3
este regreso tanto en <br> como en <div>
Nishad Up

51

Puede hacer esto con solo un cambio de CSS:

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

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

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


1
Hubo un problema cuando utilicé el bloque en línea, ejecute execCommand ("insertHTML", xxx) para insertar cualquier cosa, se agregará un "<br>" al final del elemento insertado, probado en Chrome33.
Imskull

55
Buen hallazgo Lamentablemente, esto no funcionará en la posición: elementos absolutos o elementos que son hijos directos de un padre con pantalla: flex. Puedes hackearlo para que funcione, aunque tenlo en cuenta. Solo asegúrese de que no sea un hijo directo de elementos flexibles. Si lo necesitas posición: absoluto solo dale un padre extra con eso.
Escéptico

@ReinoutvanKempen Comenzó a usar flex hace 3 meses. Supongo que este truco no funcionará
kittu

esta es una solución realmente excelente, es extremadamente limpia y clara, no se insertará nada, incluso se incluirá br. y especialmente esta solución sin js.
defender orca

2
Wow ... esto resuelve Chrome, pero hace que Firefox comience a agregar divs al ingresar, lo que no hace de manera predeterminada.
cbdeveloper

40

Agregue estilo display:inline-block;a contenteditable, no se generará div, py spanautomáticamente en Chrome.


66
Esta es una gran solución. *[contenteditable="true"]{display: inline-block;}
ericjbasti

Me encanta, simple pero efectivo
user25794

En IE11 esto hará un extra <p></p> :(
Betty St

1
pero creará otro error de Chrome muy molesto (qué navegador de mierda)
vsync

44
Ya no funciona con Chrome versión 63.0.3239.84
Mikaël Mayer

21

Prueba esto:

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


Bien, funciona :) Esperaré más atención antes de decidir, gracias.
iConnor

no funciona correctamente en firefox. agrega una línea extra.
agpt

Esto hace que inputno se active cuando presionas enter. Una solución simple: agregue algo como$(this).trigger('input')
LarsW

La insertHTMLsolución hace algunas cosas raras cuando hay contenteditableelementos anidados , su solución evita eso pero hay algunos problemas más, lo agregué como una nueva solución posible.
skerit

No funciona en Chrome. La primera vez que presiona Intro al final de la cadena, agrega un espacio. Sin embargo, la segunda vez funciona.

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

Se anula el comportamiento predeterminado para tener párrafo en su lugar.

En Chrome, el comportamiento predeterminado al ingresar es:

<div>
    <br>
</div>

Con ese comando va a ser

<p>
    <br>
</p>

Ahora que es más lineal, es fácil tenerlo solo <br>si lo necesita.


Cuando presionas Intro, en lugar de tener div y br, tendrás p y br en todo el navegador. Intentalo.
Ced

¡Gracias! Las explicaciones siempre son útiles
jpaugh

@jpaugh np, edité mi respuesta más para que se explique mejor.
Ced

Esto no funciona en Firefox (solo probé en Chrome y
Firefox

FireFox se ha corregido para que ahora respete el DefaultParagraphSeparator. En mi humilde opinión, esto hace que esta respuesta sea la mejor, ya que ahora todos los navegadores son consistentes y están en línea con las especificaciones. Si no desea que una etiqueta P tenga un margen 'espaciado' del bloque de texto anterior en el contenido editable, puede usar css para modificarlo.
blackmamba

9

Use shift+ en enterlugar de entersimplemente colocar una sola <br>etiqueta o envolver su texto en <p>etiquetas.


9
+1 Gracias, es muy útil saberlo, pero si tienes un cliente que está escribiendo un libro, será un fastidio en el ***
iConnor

1
Esto no ayuda si está pegando contenido
vsync

5

La forma en que se contenteditablecomporta cuando presiona enterdepende de los navegadores, lo que <div>sucede en webkit (Chrome, Safari) e IE.

Luché con esto hace unos meses y lo corregí de esta manera:

//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 ayude, y lo siento por mi inglés si no es tan claro como sea necesario

EDITAR : corrección de la función jQuery eliminadajQuery.browser


Solo para hacerle saber, jQuery.browserya no es parte de jQuery.
iConnor

Tienes razón, debo mencionar esto y usar algo como navigator.userAgent.indexOf("msie") > 0ynavigator.userAgent.indexOf("webkit") > 0
Elie

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

5

Puede tener <p>etiquetas separadas para cada línea en lugar de usar<br> etiquetas y obtener una mayor compatibilidad del navegador fuera de la caja.

Para hacer esto, pon un <p> etiqueta con texto predeterminado dentro del div contenteditable.

Por ejemplo, en lugar de:

<div contenteditable></div>

Utilizar:

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

jsfiddle

Probado en Chrome, Firefox y Edge, y el segundo funciona igual en cada uno.

Sin embargo, el primero crea divs en Chrome, crea saltos de línea en Firefox, y en Edge crea divs y el cursor se vuelve a colocar al comienzo del div actual en lugar de pasar al siguiente.

Probado en Chrome, Firefox y Edge.


esto en realidad no es una mala solución
AaronHS

5

Me gusta usar Mousetrap para manejar teclas de acceso rápido: https://craig.is/killing/mice

Luego, solo intercepto el evento enter, ejecutando un comando insertLineBreak :

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

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

Funciona usando Chrome 75 y el siguiente elemento editable:

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

También es posible usar insertHTML :

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

4

agregar un valor predeterminado de prevención al div

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

@connorspiracist lo siento document.body.div(es probable que deba poner algún otro código para corregir divla idea general)
Math chiller

4

Usaría el estilo (Css) para solucionar el problema.

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

Firefox agrega un salto de elemento de bloque
, mientras que Chrome envuelve cada sección en una etiqueta. Tu css le da a los divs un relleno de 10px junto con el color de fondo.

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

Alternativamente, puede replicar el mismo efecto deseado en jQuery:

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

Aquí hay un tenedor de su violín http://jsfiddle.net/R4Jdz/7/


1
Esto puede ayudar a algunas personas, pero estaba más preocupado por el marcado poco práctico, ya que tomaría el HTML final del contenteditabley lo
usaría

3

Puede ajustar sus párrafos con una <p>etiqueta, por ejemplo, aparecería en una nueva línea en lugar de div Ejemplo:
<div contenteditable="true"><p>Line</p></div>
después de insertar una nueva cadena:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>


3

La inserHTMLsolución de comando hace algunas cosas raras cuando has anidadocontenteditable elementos .

Tomé algunas ideas de varias respuestas aquí, y esto parece satisfacer mis necesidades por ahora:

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

Primero, necesitamos capturar cada clave que ingrese el usuario para ver si se presiona enter, luego evitamos la <div>creación y creamos la nuestra.<br> etiqueta.

Hay un problema, cuando lo creamos, nuestro cursor permanece en la misma posición, por lo que usamos la API de selección para colocar nuestro cursor al final.

No olvide agregar una <br>etiqueta al final de su texto porque si no lo hace, la primera entrada no hará una nueva línea.

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

Violín


2

Este es el editor HTML5 dirigido por el navegador. Puede ajustar su texto <p>...</p>, luego cada vez que presiona ENTRAR obtiene <p></p>. Además, el editor funciona de esta manera que cada vez que presiona MAYÚS + ENTRAR se inserta <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 esto: http://jsfiddle.net/ZQztJ/


2

Esto funciona en todos los principales 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>

Hay un inconveniente. Después de que termine de editar, los elementos pueden contener un final <br>dentro. Pero podría agregar código para recortarlo si es necesario.

Verifique esta respuesta para eliminar el https://stackoverflow.com/a/61237737/670839 final<br>


¿Que demonios? ¿Cómo puede la única solución que realmente funcionó para mí estar tan abajo en la página? Muchas gracias.
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>')

¿Dónde thisestá el contexto real que significa document.getElementById('test');?


0

Otra forma de hacerlo

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


No permite que el cursor avance mientras escribe.
Jack Lu

Eso es extraño, acabo de probar en Chrome e IE 11 y funciona bien. Referencia ¿Podría decirme qué navegador está utilizando? Cualquier otro detalle sobre el comportamiento sería útil para resolver el problema
MrAJ

0

Evite la creación de nuevas Div en contenido Div editable en cada tecla enter: La solución que he encontrado es muy simple:

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

Este contenido --- innerHTML impide la creación de Nueva Div en contenido Div editable en cada tecla enter.


0

En el Borrador del Editor del W3C hay información sobre cómo agregar estados en ContentEditable , y para evitar que el navegador agregue un nuevo elemento al presionar enter que puede usar plaintext-only.

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

-1

Es posible prevenir este comportamiento por completo.

Ver este violín

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.