禁止在ENTER上进行contenteditable添加<div>-Chrome


131

我有一个contenteditable元素,每当我输入一些内容并点击ENTER它时,都会创建一个新元素并将<div>新的行文本放置在其中。我一点都不喜欢。

是否可以防止这种情况发生,或者至少将其替换为<br>

这是演示http://jsfiddle.net/jDvau/

注意:这不是在Firefox中的问题。


1
firefox添加了<br>,chrome-不会,但是在修复样式后,多余的div不会破坏左填充。问题是为什么你不喜欢它?认为它是br ... jsfiddle.net/jDvau/1您还可以使用DOMSubtreeModified事件捕获这些div并将其删除。
ViliusL 2013年

stackoverflow.com/questions/6024594/…这可以帮助您,祝您好运!
2013年

1
对我来说,布雷克·普拉姆(Blake Plumb)的解决方案是最简单的解决方案,而远非最好。
svassr 2013年

1
@svassr不是重点,不是您或我将使用它,而是一个客户甚至可能不知道转变是什么。
iConnor 2013年

2
确实,它改变了一切。也就是说,这是一种常见的行为,很少有帮助信息。“给男人一条鱼,你就给他喂一天。教一个男人鱼,你就给他喂一辈子。”
svassr 2013年

Answers:


161

试试这个:

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

点击此处进行演示


但是我发现这里有些不同。将光标放在空白行(“键入某些内容”顶部)上,然后按Enter。光标现在位于“类型”之前,而不是在新的空白行上。
安德鲁

3
这在IE11中不起作用,因为它不支持insertHTML。请参阅下面的答案!
webprogrammer,2014年

4
如果您将光标放在字符之间,例如 “ Ty [cursor] pe some something”,然后按Enter,您将得到1行太多。
钱德鲁

13
答案不可接受。解决方案是只拥有一个<br />
raoulinski 2014年

3
这将同时返回<br>和<div>
Nishad Up

51

您可以通过更改CSS来做到这一点:

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

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

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


1
当我使用内联块时,执行execCommand(“ insertHTML”,xxx)插入任何内容时出现问题,将在插入的元素的末尾添加“ <br>”,该元素在Chrome33中进行了测试。
Imskull 2014年

5
好发现。遗憾的是,这在位置上不起作用:绝对元素或作为具有display:flex的父级的直接子元素的元素。您可以牢记这一点,以使其正常工作。只要确保它不是flex元素的直接子元素即可。如果您需要它的位置:绝对只需为此提供一个额外的父级。
怀疑论者

@ReinoutvanKempen 3个月前开始使用flex。我猜这种破解是行不通的
kittu

这是一个真正非常好的解决方案,它极其干净清晰,不会插入任何内容,甚至包括br。特别是没有js的解决方案。
捍卫逆戟鲸

2
哇...这解决了Chrome,但使Firefox开始在enter上添加div,默认情况下不启用。
cbdeveloper19年

40

添加样式display:inline-block;contenteditable,也不会产生divpspan自动在Chrome中。


6
这是一个很好的解决方案。*[contenteditable="true"]{display: inline-block;}
ericjbasti 2015年

喜欢它,简单却有效
user25794

在IE11中,这会额外增加<p></p> :(
Betty St

1
它将创建另一个非常烦人的Chrome错误(糟糕的浏览器)
vsync

4
已经不使用Chrome版本63.0.3239.84工作
麦克尔迈耶

21

试试这个:

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


很好,可以用:)在决定之前,我将等待更多关注,谢谢。
iConnor 2013年

在Firefox上无法正常工作。它增加了一行。
2016年

这样可以确保input在您按Enter键时不会触发。一个简单的解决方案:添加类似$(this).trigger('input')
LarsW '16

insertHTML当存在嵌套contenteditable元素时,该解决方案会做一些奇怪的事情,您的解决方案会规避但还有更多问题,我将其添加为新的可能解决方案。
skerit

在Chrome上不起作用。第一次在字符串末尾按Enter时,它会添加一个空格。虽然第二次工作。

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

它覆盖默认行为以改为具有段落。

在chrome上,enter的默认行为是:

<div>
    <br>
</div>

有了这个命令,它将成为

<p>
    <br>
</p>

现在,它在整个过程中更加线性,只<br>需要您就可以轻松拥有它。


当您按Enter键时,浏览器将不再显示div和br,而是显示p和br。试试吧。
Ced 2016年

谢谢!解释总是有帮助的
jpaugh

@jpaugh np,我进一步编辑了答案,以便于更好地解释。
Ced 2016年

这不适用于Firefox(我仅在chrome和Firefox中测试过)
medBouzid

FireFox已修复,现在可以遵守defaultParagraphSeparator。恕我直言,这使此答案最佳,因为它使所有浏览器现在保持一致并符合规范。如果您不希望P标签在可编辑的内容中与上一个文本块之间有一个边距“间距”,则可以使用CSS对其进行修改。
blackmamba

9

使用shift+ enter而不是enter仅将单个<br>标签放入或将文本包装在<p>标签中。


9
+1谢谢,这很容易知道,但是如果您有一位客户正在写书,那将是***的痛苦
iConnor 2013年

1
如果您粘贴内容,这无济于事
vsync

5

contenteditable按下时的行为方式enter取决于浏览器,<div>在webkit(chrome,safari)和IE上会发生。

我在几个月前对此进行了努力,并通过以下方式进行了纠正:

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

希望对您有所帮助,如果英语不够清晰,请对我的英语感到抱歉。

编辑:删除的jQuery函数的更正jQuery.browser


只是让您知道,jQuery.browser它不再是jQuery的一部分。
iConnor 2013年

你已经正确的,我应该提到这一点,并使用类似navigator.userAgent.indexOf("msie") > 0navigator.userAgent.indexOf("webkit") > 0
埃利

1
if( ( e.keyCode || e.witch ) == 13 ) { ... }需要成为if (e.keyCode === 13 || e.which === 13) { ... }
塞巴斯蒂安·桑德克维斯特

5

我喜欢使用捕鼠器来处理热键:https://craig.is/killing/mice

然后,我只是截取enter事件,执行命令insertLineBreak

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

所有命令:https : //developer.mozilla.org/zh-CN/docs/Web/API/Document/execCommand

它可以使用Chrome 75和以下可编辑元素工作:

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

也可以使用insertHTML

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

4

向div添加一个阻止默认值

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

@connorspiracist对不起document.body.div(您可能需要输入一些其他代码来纠正div它的一般想法)
Math chiller 2013年

4

我会使用样式(Css)来解决此问题。

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

Firefox确实添加了一个block元素break
,而Chrome将每个部分包装在一个标签中。您的CSS给divs填充了10px的填充以及背景色。

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

或者,您可以在jQuery中复制相同的所需效果:

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

这是您的小提琴的叉子http://jsfiddle.net/R4Jdz/7/


1
这可能会对某些人有所帮助,但我更关心unessaary标记,因为我将使用的最终HTML contenteditable并将其在其他地方使用
iConnor 2013年

4

您可以<p>为每行使用单独的标签,而不是使用<br>标签,从而可以提高浏览器的兼容性。

为此,请将<p>带有一些默认文本的标签放在contenteditable div内。

例如,代替:

<div contenteditable></div>

用:

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

jsfiddle

在Chrome,Firefox和Edge上进行了测试,第二个在每个版本中均相同。

但是,第一个在Chrome中创建div,在Firefox中创建换行符,在Edge中创建div 将光标放回到当前div的开头,而不是移至下一个div。

在Chrome,Firefox和Edge中进行了测试。


这实际上不是一个不好的解决方案
AaronHS

3

您可以使用<p>标记将段落包装起来,例如,它将用换行符而不是div换行。示例:
<div contenteditable="true"><p>Line</p></div>
插入新字符串后:
<div contenteditable="true"><p>Line</p><p>New Line</p></div>


3

inserHTML当您具有嵌套contenteditable元素时,命令解决方案会做一些奇怪的事情。

我从这里的多个答案中提取了一些想法,目前看来这很适合我的需求:

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

首先,我们需要捕获每个关键用户的回车键,以查看是否按下了回车键,然后阻止<div>创建,并创建自己的<br>标签。

有一个问题,当我们创建它时,光标停留在相同的位置,因此我们使用Selection API将光标放在最后。

不要忘记<br>在文本的末尾添加标签,因为如果您不这样做,则第一个输入将不会换行。

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

小提琴


2

这是由浏览器控制的HTML5编辑器。您可以使用来换行<p>...</p>,然后每按ENTER键一次<p></p>。此外,编辑器的工作方式是,每当您按SHIFT + ENTER时都会插入<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>

检查此:http : //jsfiddle.net/ZQztJ/


2

这适用于所有主要浏览器(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>

有一个不便之处。完成编辑后,元素可能<br>在内部包含结尾。但是,如果需要,您可以添加代码以将其缩减。

检查此答案以删除结尾的<br> https://stackoverflow.com/a/61237737/670839


有没有搞错?对于我来说,实际上唯一有效的解决方案是如何做到这一点呢?非常感谢。
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>')

this实际情况在哪里呢document.getElementById('test');


0

另一种方式

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


键入时,光标不会向前移动。
杰克·卢

真奇怪,我只是在Chrome和IE 11中尝试过,但效果很好。 参考 请您告诉我您使用的是哪种浏览器?有关行为的更多详细信息将有助于解决问题
MrAJ

0

防止在每个Enter键的内容可编辑Div中创建新Div:解决方案我发现非常简单:

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

该--- innerHTML内容可防止在每个Enter键上的内容可编辑Div中创建新Div。



-1

有可能完全防止这种行为。

看到这个小提琴

$('<div class="temp-contenteditable-el" contenteditable="true"></div>').appendTo('body').focus().remove();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.