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.

iConnor
fuente
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

Ram G Athreya
fuente
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/

airi
fuente
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.

Le Tung Anh
fuente
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/

Andrés
fuente
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.

Sección de la economía
fuente
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.

Blake Plumb
fuente
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

Elie
fuente
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.

Josh Powlison
fuente
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");
Gauss
fuente
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>";
    }
}
Enfriador de matemáticas
fuente
@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/

cbayram
fuente
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>

nes
fuente
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;
}
skerit
fuente
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

L105
fuente
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/

Mehdi
fuente
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>


fuente
¿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');?

programador web
fuente
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/

MrAJ
fuente
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.

DrShyam Babu Gupta
fuente
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>
StefansArya
fuente
-1

Es posible prevenir este comportamiento por completo.

Ver este violín

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
Omnicon
fuente