Impedisci contenteditable aggiungendo <div> su ENTER - Chrome


131

Ho un contenteditableelemento e ogni volta che scrivo qualcosa e ENTERlo premo crea un nuovo <div>e inserisce il testo della nuova riga. Non mi piace per niente.

È possibile impedire che ciò accada o almeno sostituirlo con un <br>?

Ecco la demo http://jsfiddle.net/jDvau/

Nota: questo non è un problema in Firefox.


1
firefox aggiunge <br>, chrome - no, ma dopo aver corretto gli stili, i div extra non interrompono l'imbottitura sinistra. La domanda è: perché non ti piace? Pensa che sia ... jsfiddle.net/jDvau/1 Inoltre puoi usare l'evento DOMSubtreeModified per catturare questi div e rimuoverli.
ViliusL

stackoverflow.com/questions/6024594/… questo potrebbe aiutarti, buona fortuna!
Sirikon,

1
Per me la soluzione di Blake Plumb è la più semplice e di gran lunga la migliore quaggiù.
svassr,

1
@svassr non è questo il punto, non sei tu o io che lo useremo, è un client che potrebbe anche non sapere quale sia il turno.
iConnor l'

2
Anzi cambia tutto. Detto questo è un comportamento comune e un piccolo messaggio di aiuto non si armerebbe. "Dai un pesce a un uomo e gli dai da mangiare per un giorno. Insegna a un uomo a pescare e gli dai da mangiare per tutta la vita."
svassr,

Risposte:


161

Prova questo:

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

Clicca qui per la demo


Ma trovo una piccola differenza qui. Posiziona il cursore sulla riga vuota (nella parte superiore di "Scrivi alcune cose") e premi Invio. Il cursore si trova ora appena prima del "Tipo", non sulla nuova riga vuota.
Andrew,

3
Questo non funziona in IE11 in quanto non supporta insertHTML. Vedi la risposta qui sotto!
webprogrammer

4
Se si posiziona il cursore tra i caratteri, ad es. 'Ty [cursore] pe alcune cose' e premi invio, ottieni 1 riga di troppo.
Chandrew,

13
La risposta non è accettabile La soluzione sarebbe quella di avere un solo <br />
raoulinski il

3
questo ritorno sia <br> che <div>
Nishad Up

51

Puoi farlo con solo una modifica CSS:

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

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

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


1
Si è verificato un problema quando ho usato inline-block, eseguo execCommand ("insertHTML", xxx) per inserire qualcosa, verrà aggiunto un "<br>" alla fine dell'elemento inserito, testato in Chrome33.
Imskull,

5
Bella scoperta. Purtroppo questo non funzionerà sulla posizione: elementi assoluti o elementi che sono figli diretti di un genitore con display: flex. Puoi hackerarlo per funzionare tenendo presente questo. Assicurati solo che non sia un figlio diretto di elementi flex. Se ti serve la posizione: assoluto basta dargli un genitore extra con quello.
Scettico

@ReinoutvanKempen Iniziato a utilizzare Flex 3 mesi fa già. Immagino che questo trucco non funzionerà
kittu il

questa è davvero una soluzione davvero eccezionale, è estremamente pulita e chiara, non verrà inserito nulla, incluso br. e soprattutto questa soluzione senza js.
difendi orca l'

2
Wow ... questo risolve Chrome, ma fa in modo che Firefox inizi ad aggiungere div su enter, cosa che di default non lo fa.
cbdeveloper,

40

Aggiungere stile display:inline-block;a contenteditable, non genera div, pe spanautomaticamente in Chrome.


6
Questa è un'ottima soluzione *[contenteditable="true"]{display: inline-block;}
ericjbasti,

Lo
adoro

In IE11 questo farà un extra <p></p> :(
Betty St,

1
ma creerà un altro fastidioso bug di Chrome (che browser
schifoso

4
Non funziona più con la versione 63.0.3239.84 di Chrome
Mikaël Mayer,

21

Prova questo:

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


Bene, funziona :) Aspetterò più attenzione prima di decidere, grazie.
iConnor

non funziona correttamente su Firefox. aggiunge una riga aggiuntiva.
agpt

Questo fa sì che inputnon venga attivato quando si preme invio. Una soluzione semplice: aggiungi sth like$(this).trigger('input')
LarsW

La insertHTMLsoluzione fa alcune cose strane quando ci sono contenteditableelementi nidificati , la tua soluzione elude che, ma ci sono alcuni altri problemi, l'ho aggiunta come nuova possibile soluzione.
skerit

Non funziona su Chrome. La prima volta che si preme invio alla fine della stringa, viene aggiunto uno spazio. La seconda volta però funziona.

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

Sostituisce invece il comportamento predefinito con paragrafo.

Su Chrome il comportamento predefinito su Invio è:

<div>
    <br>
</div>

Con quel comando lo sarà

<p>
    <br>
</p>

Ora che è più lineare in tutto, è facile avere solo <br>ciò di cui avresti bisogno.


Quando premi Invio, invece di div e br avrai p e br nel browser. Provalo.
Ced

Grazie! Le spiegazioni sono sempre utili
jpaugh

@jpaugh np, ho modificato ulteriormente la mia risposta in modo che spieghi meglio.
Ced

questo non funziona su Firefox (ho testato solo su Chrome e Firefox)
medBouzid

FireFox è stato corretto per rispettare il defaultParagraphSeparator. IMHO rende questa risposta la migliore in quanto rende tutti i browser ora coerenti e in linea con le specifiche. Se poi non vuoi che un tag P abbia un margine 'spaziatura' dal precedente blocco di testo nel contenuto modificabile, puoi usare CSS per modificarlo.
Blackmamba,

9

Usa shift+ enterinvece di enterinserire un singolo <br>tag o avvolgere il testo in <p>tag.


9
+1 Grazie, questo è molto utile da sapere, ma se hai un cliente che sta scrivendo un libro, sarà un dolore nel ***
iConnor

1
Questo non aiuta se stai incollando contenuti
vsync il

5

Il modo in cui contenteditablesi comporta quando si preme enterdipende dai browser, ciò <div>accade su webkit (chrome, safari) e IE.

Ho lottato con questo alcuni mesi fa e l'ho corretto in questo modo:

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

Spero che possa essere d'aiuto, e scusami per il mio inglese se non è così chiaro come necessario.

EDIT : correzione della funzione jQuery rimossajQuery.browser


Solo per farti sapere, jQuery.browsernon fa più parte di jQuery.
iConnor,

Hai ragione, dovrei menzionarlo e usare qualcosa del genere navigator.userAgent.indexOf("msie") > 0enavigator.userAgent.indexOf("webkit") > 0
Elie

1
if( ( e.keyCode || e.witch ) == 13 ) { ... }deve essereif (e.keyCode === 13 || e.which === 13) { ... }
Sebastian Sandqvist il

5

Puoi avere <p>tag separati per ogni riga anziché utilizzare i <br>tag e ottenere una maggiore compatibilità del browser pronta all'uso .

Per fare ciò, inserisci un <p>tag con del testo predefinito all'interno del div contenteditable.

Ad esempio, anziché:

<div contenteditable></div>

Uso:

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

jsfiddle

Testato su Chrome, Firefox e Edge, e il secondo funziona allo stesso modo in ciascuno di essi.

Il primo, tuttavia, crea div in Chrome, crea interruzioni di linea in Firefox e in Edge crea div e il cursore viene riportato all'inizio del div corrente invece di passare a quello successivo.

Testato su Chrome, Firefox e Edge.


questa non è in realtà una cattiva soluzione
AaronHS

5

Mi piace usare la trappola per topi per consegnare i tasti di scelta rapida: https://craig.is/killing/mice

Quindi, intercetto semplicemente l'evento enter, eseguendo un comando insertLineBreak :

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

Tutti i comandi: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

Funziona con Chrome 75 e il seguente elemento modificabile:

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

È anche possibile utilizzare insertHTML :

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

4

aggiungere un valore predefinito di prevenzione 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 mi dispiace document.body.div(probabilmente dovrai inserire qualche altro codice per indicare che è giusto divl'idea generale)
Math chiller

4

Userei lo styling (Css) per risolvere il problema.

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

Firefox infatti aggiunge un'interruzione dell'elemento blocco
, mentre Chrome avvolge ogni sezione in un tag. Css dà ai div un'imbottitura di 10px insieme al colore di sfondo.

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

In alternativa, puoi replicare lo stesso effetto desiderato in jQuery:

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

Ecco un fork del tuo violino http://jsfiddle.net/R4Jdz/7/


1
Questo può aiutare alcune persone, ma ero più preoccupato per il markup nonessasary, dato che avrei preso l'HTML finale del contenteditablee usandolo altrove
iConnor

3

Puoi avvolgere i tuoi paragrafi con <p>tag, ad esempio, verrebbe apper su una nuova riga anziché div Esempio:
<div contenteditable="true"><p>Line</p></div>
Dopo aver inserito una nuova stringa:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>


3

La inserHTMLsoluzione di comando fa alcune cose strane quando hai contenteditableelementi nidificati .

Ho preso alcune idee da più risposte qui, e questo sembra soddisfare le mie esigenze per ora:

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

Per prima cosa dobbiamo acquisire tutti gli utenti chiave immessi per vedere se viene premuto invio, quindi impediamo la <div>creazione e creiamo il nostro <br>tag.

C'è un problema, quando lo creiamo il nostro cursore rimane nella stessa posizione, quindi utilizziamo l' API di selezione per posizionare il cursore alla fine.

Non dimenticare di aggiungere un <br>tag alla fine del testo perché se non lo fai, la prima immissione non farà una nuova riga.

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

Questo è un editor HTML5 per browser. Puoi avvolgere il tuo testo con <p>...</p>, quindi ogni volta che premi INVIO otterrai <p></p>. Inoltre, l'editor funziona in questo modo che ogni volta che si preme MAIUSC + INVIO si inserisce <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>

Controlla questo: http://jsfiddle.net/ZQztJ/


2

Funziona con tutti i principali browser (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>

C'è un inconveniente. Al termine della modifica, gli elementi potrebbero contenere un finale <br>all'interno. Ma potresti aggiungere del codice per eliminarlo se necessario.

Controlla questa risposta per rimuovere la coda <br> https://stackoverflow.com/a/61237737/670839


Che diamine? Come può l'unica soluzione che ha funzionato per me essere così in fondo alla pagina? Grazie mille.
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>')

Dov'è thisil contesto reale che significa document.getElementById('test');.


0

Un altro modo per farlo

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


Non consente al cursore di spostarsi in avanti durante la digitazione.
Jack Lu

È strano, ho appena provato in Chrome e IE 11 e funziona benissimo. Riferimento Potresti dirmi quale browser stai utilizzando? Ulteriori dettagli sul comportamento sarebbero utili per risolvere il problema
MrJAJ

0

Impedisci la creazione di una nuova Div in Div modificabile nel contenuto su ogni tasto Invio: Soluzione che ho trovato è molto semplice:

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

Questo contenuto --- innerHTML impedisce la creazione di nuovi Div in contenuti modificabili Div su ogni tasto Invio.


0

Nella bozza dell'editor del W3C ci sono alcune informazioni sull'aggiunta di stati in ContentEditable e per impedire al browser di aggiungere nuovi elementi quando si preme invio è possibile utilizzare plaintext-only.

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

-1

È possibile prevenire completamente questo comportamento.

Vedi questo violino

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.