Ngăn chặn thêm nội dung <div> trên ENTER - Chrome


131

Tôi có một contenteditableyếu tố, và bất cứ khi nào tôi gõ một số nội dung và nhấn ENTERnó sẽ tạo ra một dòng mới <div>và đặt văn bản dòng mới vào đó. Tôi không thích điều này một chút.

Có thể ngăn chặn điều này xảy ra hoặc ít nhất là chỉ thay thế nó bằng một <br>?

Đây là bản demo http://jsfiddle.net/jDvau/

Lưu ý: Đây không phải là một vấn đề trong firefox.


1
firefox thêm <br>, chrome - không, nhưng sau khi sửa kiểu của bạn, các div bổ sung không phá vỡ phần đệm bên trái. Câu hỏi là tại sao bạn không thích nó? Hãy nghĩ rằng đó là ... jsfiddle.net/jDvau/1 Ngoài ra, bạn có thể sử dụng sự kiện DOMSubtreeModified để bắt những div này và xóa chúng.
ViliusL

stackoverflow.com/questions/6024594/ trên này có thể giúp bạn, chúc may mắn!
Sirikon

1
Đối với tôi giải pháp của Blake Plumb là đơn giản nhất và từ xa là tốt nhất ở đây.
svassr

1
@svassr đó không phải là vấn đề, không phải bạn hoặc tôi sẽ sử dụng nó, Đó là một khách hàng thậm chí có thể không biết sự thay đổi là gì.
iConnor

2
Quả thực nó thay đổi mọi thứ. Điều đó nói rằng đó là một hành vi phổ biến và thông điệp trợ giúp nhỏ sẽ không có tác dụng. "Hãy cho một người đàn ông một con cá và bạn nuôi sống anh ta một ngày. Dạy một người đàn ông câu cá và bạn nuôi sống anh ta cả đời."
svassr

Câu trả lời:


161

Thử cái này:

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

Bấm vào đây để demo


Nhưng tôi tìm thấy một chút khác biệt ở đây. Đặt con trỏ của bạn chỉ trên dòng trống (trên đầu "Nhập một số nội dung") và nhấn enter. Con trỏ bây giờ ngay trước "Loại", không phải trên dòng trống mới.
Andrew

3
Điều này không hoạt động trong IE11 vì nó không hỗ trợ insertHTML. Xem câu trả lời dưới đây!
lập trình web

4
Nếu bạn đặt con trỏ giữa các ký tự, vd. 'Ty [con trỏ] pe một số thứ' và nhấn enter, bạn nhận được 1 dòng quá nhiều.
Chandrew

13
Trả lời không được chấp nhận. Giải pháp sẽ chỉ có một <br />
raoulinski

3
điều này trả lại cả <br> và <div>
Nishad Up

51

Bạn có thể làm điều này chỉ với một thay đổi CSS:

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

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

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


1
Có một vấn đề khi tôi sử dụng khối nội tuyến, thực thi execCommand ("insertHTML", xxx) để chèn bất cứ thứ gì, một "<br>" sẽ được thêm vào cuối phần tử được chèn, được thử nghiệm trong Chrome33.
Imskull

5
Đẹp tìm thấy. Đáng buồn thay, điều này sẽ không hoạt động trên vị trí: các yếu tố tuyệt đối hoặc các yếu tố là con cái trực tiếp của cha mẹ với màn hình: flex. Bạn có thể hack nó để làm việc mặc dù ghi nhớ điều đó. Chỉ cần chắc chắn rằng nó không phải là con trực tiếp của các yếu tố flex. Nếu bạn cần vị trí của nó: tuyệt đối chỉ cần cung cấp cho nó thêm cha mẹ với điều đó.
Skeptic ngày

@ReinoutvanKempen Bắt đầu sử dụng flex 3 tháng trước. Tôi đoán hack này sẽ không hoạt động
kittu

Đây là một giải pháp thực sự tuyệt vời nhất, nó cực kỳ sạch sẽ và rõ ràng, sẽ không có gì được chèn, thậm chí bao gồm cả br. và đặc biệt là giải pháp này mà không cần js.
bảo vệ orca

2
Wow ... điều này giải quyết được Chrome, nhưng làm cho Firefox bắt đầu thêm div khi vào, điều này không có mặc định.
cbdeveloper

40

Thêm phong cách display:inline-block;đến contenteditable, nó sẽ không tạo ra div, pspantự động trong Chrome.


6
Đây là một giải pháp tuyệt vời. *[contenteditable="true"]{display: inline-block;}
ericjbasti

Yêu nó, đơn giản nhưng hiệu quả
user25794

Trong IE11, điều này sẽ kiếm thêm <p></p> :(
Betty St

1
nhưng nó sẽ tạo ra một lỗi Chrome rất khó chịu khác (thật là một trình duyệt tồi tệ)
vsync

4
Không hoạt động nữa với Chrome Phiên bản 63.0.3239.84
Mikaël Mayer

21

Thử cái này:

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


Tốt, hoạt động :) Tôi sẽ chờ đợi sự chú ý nhiều hơn trước khi tôi quyết định, cảm ơn.
iConnor

không hoạt động đúng trên firefox. nó thêm một dòng phụ.
agpt

Điều này làm cho nó inputkhông được kích hoạt khi bạn nhấn enter. Một giải pháp đơn giản: thêm sth like$(this).trigger('input')
LarsW

Các insertHTMLgiải pháp thực hiện một số điều kỳ lạ khi có lồng contenteditableyếu tố, circumvents giải pháp của bạn đó nhưng có một số vấn đề hơn, tôi đã thêm nó như là một giải pháp mới có thể.
skerit

Không hoạt động trên Chrome. Lần đầu tiên khi bạn nhấn enter ở cuối chuỗi, nó sẽ thêm một khoảng trắng. Lần thứ hai nó hoạt động mặc dù.

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

Nó ghi đè hành vi mặc định để có đoạn thay thế.

Trên chrome, hành vi mặc định khi nhập là:

<div>
    <br>
</div>

Với lệnh đó, nó sẽ là

<p>
    <br>
</p>

Bây giờ nó trở nên tuyến tính hơn, thật dễ dàng chỉ <br>có bạn sẽ cần.


Khi bạn nhấn enter, thay vì có div và br, bạn sẽ có p và br trên trình duyệt. Thử nó.
Ced

Cảm ơn! Giải thích luôn hữu ích
jpaugh

@jpaugh np, tôi đã chỉnh sửa câu trả lời của mình hơn nữa để nó giải thích rõ hơn.
Ced

điều này không hoạt động trên firefox (tôi chỉ thử nghiệm bằng chrome và firefox)
medBouzid

FireFox đã được sửa chữa để tôn trọng defaultPar ĐoạnSeparator. IMHO điều này làm cho câu trả lời này là tốt nhất vì nó làm cho tất cả các trình duyệt hiện nhất quán và phù hợp với thông số kỹ thuật. Nếu sau đó bạn không muốn thẻ P có lề 'khoảng cách' từ khối văn bản trước đó trong nội dung có thể chỉnh sửa thì bạn có thể sử dụng css để sửa đổi điều đó.
blackmamba

9

Sử dụng shift+ enterthay vì enterchỉ đặt một <br>thẻ vào hoặc bọc văn bản của bạn trong <p>các thẻ.


9
+1 Cảm ơn, điều này rất hữu ích để biết, nhưng nếu bạn có một khách hàng đang viết một cuốn sách, đó sẽ là một nỗi đau trong ***
iConnor

1
Điều này không hữu ích nếu bạn dán nội dung
vsync

5

Cách contenteditablehành xử khi bạn nhấn enterphụ thuộc vào trình duyệt,<div> xảy ra trên webkit (chrome, safari) và IE.

Tôi đã vật lộn với điều này vài tháng trước và tôi đã sửa nó theo cách này:

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

Tôi hy vọng nó sẽ giúp ích, và xin lỗi cho tiếng Anh của tôi nếu nó không rõ ràng như cần thiết.

EDIT : Sửa lỗi hàm jQuery bị loại bỏjQuery.browser


Chỉ để cho bạn biết, jQuery.browserkhông còn là một phần của jQuery.
iConnor

Bạn đã đúng, tôi nên đề cập đến điều này và sử dụng một cái gì đó như navigator.userAgent.indexOf("msie") > 0navigator.userAgent.indexOf("webkit") > 0
Elie

1
if( ( e.keyCode || e.witch ) == 13 ) { ... }cần phải cóif (e.keyCode === 13 || e.which === 13) { ... }
Sebastian Sandqvist

5

Tôi thích sử dụng Mousetrap cho các phím nóng cầm tay: https://craig.is/killing/mice

Sau đó, tôi chỉ chặn sự kiện enter, thực thi lệnh insertLineBreak :

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

Tất cả các lệnh: https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand

Nó hoạt động bằng Chrome 75 và yếu tố có thể chỉnh sửa sau:

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

Cũng có thể sử dụng insertHTML :

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

4

thêm một ngăn chặn mặc định cho div

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

@connorspiracist xin lỗi document.body.div(có lẽ bạn sẽ cần phải nhập một số mã khác để chỉ để sửa divnó chỉ là ý tưởng chung)
làm lạnh toán học

4

Tôi sẽ sử dụng kiểu dáng (Css) để khắc phục sự cố.

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

Firefox thực sự bổ sung phần ngắt khối
, trong khi Chrome kết thúc từng phần trong thẻ. Bạn css cung cấp cho div một phần đệm 10px cùng với màu nền.

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

Ngoài ra, bạn có thể sao chép hiệu ứng mong muốn tương tự trong jQuery:

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

Đây là một nhánh của fiddle của bạn http://jsfiddle.net/R4Jdz/7/


1
Điều này có thể giúp một số người nhưng tôi quan tâm nhiều hơn đến việc đánh dấu không cần thiết, vì tôi sẽ lấy HTML cuối cùng contenteditablevà sử dụng nó ở nơi khác
iConnor 12/12/13

4

Bạn có thể có các <p>thẻ riêng cho từng dòng thay vì sử dụng<br> các thẻ và có được khả năng tương thích trình duyệt lớn hơn.

Để làm điều này, hãy đặt một <p>thẻ với một số văn bản mặc định bên trong div có thể nội dung.

Ví dụ: thay vì:

<div contenteditable></div>

Sử dụng:

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

jsfiddle

Đã thử nghiệm trong Chrome, Firefox và Edge và thứ hai hoạt động giống nhau ở mỗi cái.

Tuy nhiên, lần đầu tiên, tạo các div trong Chrome, tạo các ngắt dòng trong Firefox và trong Edge tạo các div con trỏ được đặt lại ở đầu div hiện tại thay vì chuyển sang div tiếp theo.

Đã thử nghiệm trong Chrome, Firefox và Edge.


đây thực sự không phải là một giải pháp tồi
AaronHS

3

Bạn có thể bọc các đoạn văn bản của mình bằng <p>thẻ, ví dụ như nó sẽ xuất hiện trên dòng mới thay vì div Ví dụ:
<div contenteditable="true"><p>Line</p></div>
Sau khi chèn chuỗi mới:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>


3

Các inserHTMLgiải pháp lệnh thực hiện một số điều kỳ lạ khi bạn có lồng contenteditableyếu tố.

Tôi đã lấy một số ý tưởng từ nhiều câu trả lời ở đây, và điều này dường như phù hợp với nhu cầu của tôi bây giờ:

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

Trước tiên, chúng tôi cần nắm bắt mọi người dùng khóa nhập để xem nếu nhấn phím enter, chúng tôi sẽ ngăn chặn việc <div>tạo và chúng tôi tạo riêng của mình<br> thẻ .

Có một vấn đề, khi chúng tôi tạo nó, con trỏ của chúng tôi giữ nguyên vị trí, vì vậy chúng tôi sử dụng API lựa chọn để đặt con trỏ ở cuối.

Đừng quên thêm một <br>thẻ ở cuối văn bản của bạn bởi vì nếu bạn không nhập lần đầu tiên sẽ không làm một dòng mới.

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

Vĩ cầm


2

Đây là trình soạn thảo HTML5 hướng trình duyệt. Bạn có thể bọc văn bản của mình <p>...</p>, sau đó bất cứ khi nào bạn nhấn ENTER bạn nhận được <p></p>. Ngoài ra, trình chỉnh sửa hoạt động theo cách này mà bất cứ khi nào bạn nhấn SHIFT + ENTER, nó sẽ chèn <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>

Kiểm tra điều này: http://jsfiddle.net/ZQztJ/


2

Điều này hoạt động trong tất cả các trình duyệt chính (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ó một điều bất tiện. Sau khi bạn chỉnh sửa xong, các yếu tố có thể chứa một kết thúc <br>bên trong. Nhưng bạn có thể thêm mã để cắt giảm nếu bạn cần.

Kiểm tra câu trả lời này để xóa dấu vết <br> https://stackoverflow.com/a/61237737/670839


Cái quái gì thế Làm thế nào giải pháp duy nhất thực sự có hiệu quả với tôi đến tận trang này? Cám ơn rất nhiều.
dùng12861

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

Đâu thislà bối cảnh thực tế có nghĩa là document.getElementById('test');.


0

Một cách khác để làm điều đó

$('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ó không cho phép con trỏ di chuyển về phía trước khi bạn gõ.
Jack Lu

Điều đó thật lạ, tôi mới thử trong Chrome và IE 11 và nó hoạt động tốt. Tài liệu tham khảo bạn có thể xin vui lòng cho tôi biết trình duyệt mà bạn đang sử dụng? Mọi chi tiết khác về hành vi sẽ hữu ích cho việc giải quyết vấn đề
MrAJ

0

Ngăn chặn việc tạo Div mới trong nội dung Div có thể chỉnh sửa trên mỗi phím enter: Giải pháp mà tôi đã tìm thấy rất đơn giản:

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

Điều này --- nội dungHTML ngăn chặn việc tạo Div mới trong nội dung Div có thể chỉnh sửa trên mỗi phím enter.


0

Trên Bản nháp của W3C Editor, có một số thông tin về việc thêm trạng thái vào ContentEditable và để ngăn trình duyệt thêm phần tử mới khi nhấn enter, bạn có thể sử dụng plaintext-only.

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

-1

Có thể ngăn chặn hành vi này hoàn toàn.

Xem câu đố này

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.