Zapobiegaj dodawaniu edytowalnej zawartości <div> w ENTER - Chrome


140

Mam contenteditableelement i za każdym razem, gdy piszę coś i naciskam ENTER, tworzy nowy <div>i umieszcza tam nowy tekst. Ani trochę mi się to nie podoba.

Czy można temu zapobiec lub przynajmniej po prostu zastąpić to znakiem <br>?

Oto demo http://jsfiddle.net/jDvau/

Uwaga: to nie jest problem w przeglądarce Firefox.


1
firefox dodaje <br>, chrome - nie, ale po poprawieniu stylów dodatkowe elementy div nie przerywają lewego dopełnienia. Pytanie brzmi, dlaczego ci się to nie podoba? Pomyśl, że to br ... jsfiddle.net/jDvau/1 Możesz również użyć zdarzenia DOMSubtreeModified do złapania tych elementów div i ich usunięcia.
ViliusL,

stackoverflow.com/questions/6024594/ ... to może ci pomóc, powodzenia!
Sirikon,

1
Dla mnie rozwiązanie Blake Plumb jest tutaj najprostsze i zdecydowanie najlepsze.
svassr

1
@svassr nie o to chodzi, to nie ty czy ja będziemy go używać. To klient, który może nawet nie wiedzieć, co to jest zmiana.
iConnor,

2
Rzeczywiście, zmienia wszystko. To powiedziawszy, jest to typowe zachowanie, a mała wiadomość z pomocą nie byłaby uzbrojona. „Daj człowiekowi rybę, a nakarmisz go na jeden dzień. Naucz człowieka łowić ryby, a nakarmisz go na całe życie”.
svassr

Odpowiedzi:


164

Spróbuj tego:

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

Kliknij tutaj, aby zobaczyć demo


Ale tutaj widzę małą różnicę. Umieść kursor w pustym wierszu (na górze „Wpisz coś”) i naciśnij Enter. Kursor znajduje się teraz tuż przed „Typem”, a nie w nowej pustej linii.
Andrew,

3
To nie działa w IE11, ponieważ nie obsługuje insertHTML. Zobacz odpowiedź poniżej!
webprogrammer

4
Jeśli umieścisz kursor między znakami np. „Ty [kursor] pe some stuff” i naciśnij Enter, a otrzymasz o 1 linię za dużo.
Chandrew

13
Odpowiedź jest nie do przyjęcia. Rozwiązaniem byłoby posiadanie tylko jednego <br />
raoulińskiego

3
ten powrót zarówno <br>, jak i <div>
Nishad Up

51

Możesz to zrobić za pomocą samej zmiany CSS:

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

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

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


1
Wystąpił problem, gdy użyłem inline-block, wykonałem execCommand („insertHTML”, xxx), aby coś wstawić, na końcu wstawianego elementu zostanie dodany znak „<br>”, przetestowany w Chrome33.
Imskull

5
Niezłe znalezisko. Niestety nie zadziała to na pozycjach: absolutnych elementach lub elementach, które są bezpośrednimi dziećmi rodzica z display: flex. Możesz go zhakować do pracy, pamiętając o tym. Tylko upewnij się, że nie jest to bezpośrednie dziecko elementów elastycznych. Jeśli potrzebujesz pozycji: absolutna, po prostu daj jej dodatkowego rodzica z tym.
Sceptic

@ReinoutvanKempen Zaczął używać flex już 3 miesiące temu. Myślę, że ten hack nie zadziała
kittu

to naprawdę najlepsze rozwiązanie, jest ekstremalnie czyste i przejrzyste, nic nie zostanie wstawione, nawet zawiera br. a zwłaszcza to rozwiązanie bez js.
bronić orki

2
Wow ... to rozwiązuje Chrome, ale sprawia, że ​​Firefox zaczyna dodawać elementy div przy wejściu, czego domyślnie nie robi.
cbdeveloper

42

Dodaj styl display:inline-block;do contenteditable, nie wygeneruje div, pa spanautomatycznie w Chrome.


7
To świetne rozwiązanie. *[contenteditable="true"]{display: inline-block;}
ericjbasti

Uwielbiam to, proste, ale skuteczne
user25794

W IE11 będzie to dodatkowy <p></p> :(
Betty St

1
ale stworzy kolejny bardzo irytujący błąd Chrome (co za gówniana przeglądarka)
vsync

5
Nie działa już z Chrome w wersji 63.0.3239.84
Mikaël Mayer

22

Spróbuj tego:

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


Dobrze, działa :) Czekam na więcej uwagi zanim zdecyduję, dzięki.
iConnor

nie działa poprawnie w przeglądarce Firefox. dodaje jedną dodatkową linię.
agpt

To sprawia, że inputnie jest uruchamiany po naciśnięciu klawisza Enter. Proste rozwiązanie: dodaj coś takiego jak$(this).trigger('input')
LarsW

insertHTMLRozwiązanie robi dziwne rzeczy, kiedy nie są zagnieżdżone contenteditableelementy, twoje omija rozwiązanie, ale istnieje kilka problemów, dodałem go jako nowego możliwego rozwiązania.
skerit

Nie działa w Chrome. Pierwsze naciśnięcie klawisza Enter na końcu ciągu dodaje spację. Jednak za drugim razem to działa.

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

Zastępuje domyślne zachowanie, aby zamiast tego mieć akapit.

W Chrome domyślne zachowanie przy wejściu to:

<div>
    <br>
</div>

Z tym poleceniem tak będzie

<p>
    <br>
</p>

Teraz, gdy jest bardziej liniowy w poprzek, łatwo jest go mieć tylko <br>wtedy, gdy potrzebujesz.


Kiedy naciśniesz Enter, zamiast div i br będziesz mieć p i br w przeglądarce. Spróbuj.
Ced

Dzięki! Wyjaśnienia są zawsze pomocne
jpaugh

@jpaugh np, zredagowałem swoją odpowiedź dalej, aby lepiej wyjaśniała.
Ced

to nie działa na Firefoksie (testowałem tylko w Chrome i Firefox)
medBouzid

FireFox został naprawiony tak, aby teraz respektował defaultParagraphSeparator. IMHO to sprawia, że ​​ta odpowiedź jest najlepsza, ponieważ sprawia, że ​​wszystkie przeglądarki są teraz spójne i zgodne ze specyfikacją. Jeśli następnie nie chcesz, aby znacznik P miał marginesy „odstępów” od poprzedniego bloku tekstu w edytowalnej treści, możesz użyć CSS, aby to zmienić.
blackmamba

9

Użyj shift+ enterzamiast enterpo prostu wstawić pojedynczy <br>tag lub zawinąć tekst w <p>tagi.


9
+1 Dzięki, jest to bardzo przydatne, ale jeśli masz klienta, który pisze książkę, będzie to uciążliwe ***
iConnor

1
To nie pomaga, jeśli
wklejasz

8

Działa to we wszystkich głównych przeglądarkach (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>

Jest jedna niedogodność. Po zakończeniu edycji elementy mogą zawierać zakończenie w <br>środku. Ale możesz dodać kod, aby go zmniejszyć, jeśli zajdzie taka potrzeba.

Zaznacz tę odpowiedź, aby usunąć końcowe <br> https://stackoverflow.com/a/61237737/670839


1
Co za cholera? W jaki sposób jedyne rozwiązanie, które faktycznie zadziałało dla mnie, może znajdować się tak daleko na stronie? Dzięki wielkie.
user12861

Właśnie sprawiłeś, że mój dzień zajęło mi wiele godzin - dzięki!
Alexander Kludt

5

Sposób, w jaki contenteditablezachowuje się po naciśnięciu, enterzależy od przeglądarek, rozszerzenie<div> dzieje się tak w przypadku Webkita (Chrome, Safari) i IE.

Zmagałem się z tym kilka miesięcy temu i poprawiłem to w ten sposób:

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

Mam nadzieję, że to pomoże i przepraszam za mój angielski, jeśli nie jest tak jasny, jak potrzeba.

EDYCJA : Korekta usuniętej funkcji jQueryjQuery.browser


Chcemy tylko poinformować, że jQuery.browsernie jest już częścią jQuery.
iConnor

Masz rację, powinienem o tym wspomnieć i użyć czegoś takiego jak navigator.userAgent.indexOf("msie") > 0inavigator.userAgent.indexOf("webkit") > 0
Elie,

1
if( ( e.keyCode || e.witch ) == 13 ) { ... }musi byćif (e.keyCode === 13 || e.which === 13) { ... }
Sebastian Sandqvist

5

Możesz mieć osobne <p>tagi dla każdego wiersza, zamiast używać <br>tagów i uzyskać większą zgodność przeglądarki po wyjęciu z pudełka.

Aby to zrobić, umieść <p>tag z domyślnym tekstem wewnątrz edytowalnego elementu div.

Na przykład zamiast:

<div contenteditable></div>

Posługiwać się:

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

jsfiddle

Testowany w Chrome, Firefox i Edge, a drugi działa tak samo w każdym.

Jednak pierwszy tworzy elementy div w Chrome, tworzy podziały wierszy w Firefoksie, aw Edge tworzy elementy div, a kursor jest umieszczany z powrotem na początku bieżącego elementu div, zamiast przesuwać się do następnego.

Przetestowano w Chrome, Firefox i Edge.


to właściwie nie jest złe rozwiązanie
AaronHS

5

Lubię używać pułapki na myszy do obsługi skrótów klawiszowych: https://craig.is/killing/mice

Następnie po prostu przechwytuję zdarzenie enter, wykonując polecenie insertLineBreak :

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

Wszystkie polecenia: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

Działa przy użyciu przeglądarki Chrome 75 i następującego edytowalnego elementu:

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

Możliwe jest również użycie insertHTML :

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

Nic nie robi po mojej stronie…
Matt

4

dodaj opcję zapobiegania domyślnego do elementu div

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

@connorspiracist sorry to document.body.div(prawdopodobnie będziesz musiał wstawić inny kod, aby wskazać, aby poprawić divjego ogólny pomysł)
Math chiller

4

Użyłbym stylizacji (CSS), aby rozwiązać problem.

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

Firefox rzeczywiście dodaje przerwanie elementu blokowego
, podczas gdy Chrome otacza każdą sekcję tagiem. Twój css daje elementom div wypełnienie 10 pikseli wraz z kolorem tła.

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

Alternatywnie możesz powtórzyć ten sam pożądany efekt w jQuery:

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

Oto widelec twoich skrzypiec http://jsfiddle.net/R4Jdz/7/


1
Może to pomóc niektórym osobom, ale bardziej martwiłem się niepotrzebnymi znacznikami, ponieważ brałbym ostateczny kod HTML contenteditablei używał go w innym miejscu
iConnor

3

Możesz otoczyć akapity <p>tagiem, na przykład pojawi się w nowej linii zamiast div Przykład:
<div contenteditable="true"><p>Line</p></div>
Po wstawieniu nowego ciągu:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>


3

Rozwiązanie inserHTMLpoleceń robi dziwne rzeczy po zagnieżdżeniucontenteditable elementy.

Wziąłem kilka pomysłów z wielu odpowiedzi tutaj i wydaje się, że na razie odpowiada to moim potrzebom:

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

Najpierw musimy przechwycić każdy klawisz wprowadzany przez użytkownika, aby sprawdzić, czy naciśnięto klawisz Enter, a następnie zapobiegamy <div>tworzeniu i tworzymy własny <br>tag.

Jest jeden problem, kiedy tworzymy go, nasz kursor pozostaje w tej samej pozycji, więc używamy Selection API, aby umieścić kursor na końcu.

Nie zapomnij dodać <br>tagu na końcu tekstu, ponieważ jeśli tego nie zrobisz, pierwsza enter nie utworzy nowej linii.

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

Skrzypce


2

To jest edytor HTML5 obsługiwany przez przeglądarkę. Możesz zawijać swój tekst <p>...</p>, a następnie za każdym razem, gdy naciśniesz ENTER, otrzymasz <p></p>. Edytor działa również w ten sposób, że każde naciśnięcie SHIFT + ENTER wstawia <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>

Sprawdź to: http://jsfiddle.net/ZQztJ/


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

Gdzie thisjest rzeczywisty kontekst, który oznacza document.getElementById('test');.


0

Inny sposób na zrobienie tego

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


Nie pozwala na przesuwanie kursora do przodu podczas pisania.
Jack Lu

To dziwne, właśnie próbowałem w Chrome i IE 11 i działa dobrze. Odniesienie Czy mógłbyś mi powiedzieć, której przeglądarki używasz? Dalsze szczegóły dotyczące zachowania byłyby pomocne w rozwiązaniu problemu
MrAJ

0

Zapobiegaj tworzeniu nowych elementów Div w edytowalnych treściach Div przy każdym klawiszu Enter: Rozwiązanie, które znalazłem, jest bardzo proste:

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

Ta zawartość --- innerHTML zapobiega tworzeniu nowych elementów Div w edytowalnych treściach Div przy każdym klawiszu Enter.


0

W wersji roboczej edytora W3C jest kilka informacji o dodawaniu stanów do ContentEditable i zapobieganiu dodawaniu przez przeglądarkę nowego elementu po naciśnięciu klawisza Enter plaintext-only.

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

-1

Można całkowicie zapobiec temu zachowaniu.

Zobacz to skrzypce

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.