内容可编辑的单行输入

75

我们公司正在开发的应用程序需要一个支持在基于JavaScript的Web应用程序中插入表情符号的输入框。目前,我们正在使用带有表情符号短代码(例如“:-)”)的输入框,并希望切换为插入实际的图像。

我们最初的计划是使用contenteditable<div>。我们使用侦听器来监听粘贴事件以及不同的键盘/鼠标交互,以确保没有不想要的标记进入contenteditable(我们从其容器标记中剥离文本,并仅保留我们自己插入的图像标记)。

然而,问题在于如果您放入足够的内容,div会调整大小(即其高度增加)。我们不希望发生这种情况,也不能接受文本被隐藏(即纯粹的overflow: hidden)。所以:

是否有办法使可编辑的div行为类似于单行输入框?

如果有一个相对简单的属性/CSS属性可以做到我想要的效果,那将是最好的,但如果必要的话,CSS+JS建议也将不胜感激。


@davin:在(/2)中,文本会自动换行。在(/1)中,会出现滚动条,我无法看到我正在输入的内容。这是在Linux上使用Fx 5.0.1。 - Gijs
我对滚动条的解决方案不太满意,所以一旦有时间(今天有其他问题要处理...),我打算尝试使用JS+CSS来破解一个不需要滚动条的解决方案。 如果失败了,我可能会设置赏金,看看是否有人能够提出一个没有滚动条的可行解决方案。 - Gijs
如果你成功了,你可以在这里发布你的最终结果作为答案。我非常有兴趣看看你会得出什么。 - tw16
当然!现在我有一个在Fx5和Chrome中运行良好的东西,使用getBoundingClientRect并将div定位在容器内。我仍然需要添加一些事件处理程序来拖动鼠标选择,然后它就会更加完美......然后我将不得不检查IE上发生了什么。;-) - Gijs
@tw16:完成了!我已经把源代码放在gist上了,“不幸的是”,我的产品经理看到需要进行单行编辑的工作量后,决定也许我们应该有一个多行编辑器,所以这段代码现在被放弃了... - Gijs
显示剩余5条评论
10个回答

131

[contenteditable="true"].single-line {
    white-space: nowrap;
    width:200px;
    overflow: hidden;
} 
[contenteditable="true"].single-line br {
    display:none;

}
[contenteditable="true"].single-line * {
    display:inline;
    white-space:nowrap;
}
<div contenteditable="true" class="single-line">
    This should work.
</div>


@Gijs 你在用哪个浏览器?编辑:我刚注意到你之前提到了(Firefox 5 / Linux)。 - iDev247
这是一个很好的解决方案......我只想知道 - 所覆盖的div内有哪些标记?如果我知道它们是什么,那么我会具体使用它们而不是使用 - Danield
3
如果您将固定高度设置给[contenteditable="true"].single-line类,则即使用户粘贴已格式化的文本,也会防止换行。 - Danield
4
请注意,div元素仍将包含换行符,特别是如果您在JavaScript中检索innerHTML。 - Bilow
2
请问,Alessio,你能解释一下你的逻辑吗? - Kalpesh Singh
显示剩余8条评论

9
其他答案都是错的,有几个错误(截止至2019年5月7日)。其他解决方案建议使用“white-space: nowrap”(防止文字换行)+ “overflow: hidden”(防止长文本超出字段)+ 隐藏<br> 和其他内容。
这些解决方案中的第一个错误是,“overflow: hidden”还会阻止滚动文本。用户将无法通过以下方式滚动文本:
- 按下鼠标中键 - 选择文本并将鼠标指针向左或向右移动 - 使用水平鼠标滚轮(用户有此功能时)
他唯一可以使用箭头键来滚动。
您可以通过同时使用“overflow: hidden”和“overflow: auto”(或“scroll”)来解决此问题。您应该创建具有“overflow: hidden”的父元素以隐藏用户不应看到的内容。此元素必须具有输入边框和其他设计。您应该创建具有“overflow-x: auto”和“contenteditable”属性的子div。此元素将有滚动条,因此用户可以滚动它而没有任何限制,并且由于在父元素中隐藏了溢出内容,他将看不到此滚动条。
解决方案示例:

document.querySelectorAll('.CETextInput').forEach(el => {
 //Focusing on child element after clicking parent. We need it because parent element has bigger width than child.
 el.parentNode.addEventListener('mousedown', function(e) {
  if (e.target === this) {
   setTimeout(() => this.children[0].focus(), 0);
  }
 });
 
 //Prevent Enter. See purpose in "Step 2" in answer.
 el.parentNode.addEventListener('keydown', function(e) {
  if (e.keyCode === 13)
   e.preventDefault();
 });
});
.CETextInputBorder { /*This element is needed to prevent cursor: text on border*/
 display: inline-block;
 border: 1px solid #aaa;
}

.CETextInputCont {
 overflow: hidden;
 cursor: text; /*You must set it because parent elements is bigger then child contenteditable element. Also you must add javascript to focus child element on click parent*/
 
 /*Style:*/
 width: 10em;
 height: 1em;
 line-height: 1em;
 padding: 5px;
 font-size: 20px;
 font-family: sans-serif;
}

.CETextInput {
 white-space: pre; /*"pre" is like "nowrap" but displays all spaces correctly (with "nowrap" last space is not displayed in Firefox, tested on Firefox 66, 2019-05-15)*/
 overflow-x: auto;
 min-height: 100%; /*to prevent zero-height with no text*/
 
 /*We will duplicate vertical padding to let user click contenteditable element on top and bottom. We would do same thing for horizontal padding but it is not working properly (in all browsers when scroll is in middle position and in Firefox when scroll is at the end). You can also replace vertical padding with just bigger line height.*/
 padding: 5px 0;
 margin-top: -5px;
 
 outline: none; /*Prevent border on focus in some browsers*/
}
<div class="CETextInputBorder">
 <div class="CETextInputCont">
  <div class="CETextInput" contenteditable></div>
 </div>
</div>

步骤二:解决<br>和其他问题:

此外,用户或扩展程序可能会粘贴以下内容,导致问题:

  • <br> (可由用户粘贴)
  • <img> (可能具有大尺寸)(可由用户粘贴)
  • 带有另一种“white-space”值的元素
  • <div> 和其他将文本带到另一行的元素
  • 具有不适合的“display”值的元素

但是,建议隐藏所有 <br>也是错误的。因为Mozilla Firefox会向空字段添加<br>元素(我猜这可能是在删除最后一个字符后文本光标消失的错误的解决方法;在2019-03-19发布的Firefox 66中检查)。如果隐藏此元素,则当用户将焦点移动到字段时,光标将设置在此隐藏的<br>元素中,并且文本光标也将始终隐藏。

如果您知道字段为空,则可以通过JavaScript修复此问题。您需要在此处使用一些javascript(您不能使用:empty选择器,因为该字段包含<br>元素而不是空白)。以下是解决方案示例:

document.querySelectorAll('.CETextInput').forEach(el => {
 //OLD CODE:
 
 //Focusing on child element after clicking parent. We need it because parent element has bigger width than child.
 el.parentNode.addEventListener('mousedown', function(e) {
  if (e.target === this) {
      setTimeout(() => this.children[0].focus(), 0);
    }
 });
 
 //Prevent Enter to prevent blur on Enter
 el.parentNode.addEventListener('keydown', function(e) {
  if (e.keyCode === 13)
   e.preventDefault();
 });
 
 //NEW CODE:
 
 //Update "empty" class on all "CETextInput" elements:
 updateEmpty.call(el); //init
 el.addEventListener('input', updateEmpty);

 function updateEmpty(e) {
  const s = this.innerText.replace(/[\r\n]+/g, ''); //You must use this replace, see explanation below in "Step 3"
  this.classList.toggle('empty', !s);
 }
});
/*OLD CODE:*/

.CETextInputBorder { /*This element is needed to prevent cursor: text on border*/
 display: inline-block;
 border: 1px solid #aaa;
}

.CETextInputCont {
 overflow: hidden;
 cursor: text; /*You must set it because parent elements is bigger then child contenteditable element. Also you must add javascript to focus child element on click parent*/
 
 /*Style:*/
 width: 10em;
 height: 1em;
 line-height: 1em;
 padding: 5px;
 font-size: 20px;
 font-family: sans-serif;
}

.CETextInput {
 white-space: pre; /*"pre" is like "nowrap" but displays all spaces correctly (with "nowrap" last space is not displayed in Firefox, tested on Firefox 66, 2019-05-15)*/
 overflow-x: auto;
 min-height: 100%; /*to prevent zero-height with no text*/
 
 /*We will duplicate vertical padding to let user click contenteditable element on top and bottom. We would do same thing for horizontal padding but it is not working properly (in all browsers when scroll is in middle position and in Firefox when scroll is at the end). You can also replace vertical padding with just bigger line height.*/
 padding: 5px 0;
 margin-top: -5px;
 
 outline: none; /*Prevent border on focus in some browsers*/
}

/*NEW CODE:*/

.CETextInput:not(.empty) br,
.CETextInput img { /*We hide <img> here. If you need images do not hide them but set maximum height. User can paste image by pressing Ctrl+V or Ctrl+Insert.*/
 display: none;
}

.CETextInput * {
 display: inline;
 white-space: pre;
}
<!--OLD CODE:-->

<div class="CETextInputBorder">
 <div class="CETextInputCont">
  <div class="CETextInput" contenteditable></div>
 </div>
</div>

步骤三:解决获取值问题:

我们隐藏了<br>元素,因此“innerText”值将不包含它们。但是:

  1. 当设置“empty”类时,结果可能包含<br>元素。
  2. 您的其他样式或扩展可能通过“!important”标记或具有更高优先级的规则覆盖“display: none”。

因此,在获取值时,应进行替换以避免意外获取换行符:

s = s.replace(/[\r\n]+/g, '');

不要使用 JavaScript 隐藏 <br>

你可以通过 JavaScript 删除 <br> 以解决问题,但这是一个很糟糕的解决方案,因为在每次删除后,用户都无法再使用“撤消”操作来取消之前所做的更改。

你也可以使用 document.execCommand('delete') 来删除 <br>,但这很难实现 + 用户可以撤消您的删除并恢复 <br> 元素。


添加占位符

虽然这个问题并没有被提出,但我想许多使用单行 contenteditable 元素的人都需要它。以下是使用 CSS 和上述的“empty”类的示例:

//OLD CODE:

document.querySelectorAll('.CETextInput').forEach(el => {
 //Focusing on child element after clicking parent. We need it because parent element has bigger width than child.
 el.parentNode.addEventListener('mousedown', function(e) {
  if (e.target === this) {
      setTimeout(() => this.children[0].focus(), 0);
    }
 });
 
 //Prevent Enter to prevent blur on Enter
 el.parentNode.addEventListener('keydown', function(e) {
  if (e.keyCode === 13)
   e.preventDefault();
 });
 
 //Update "empty" class on all "CETextInput" elements:
 updateEmpty.call(el); //init
 el.addEventListener('input', updateEmpty);

 function updateEmpty(e) {
  const s = this.innerText.replace(/[\r\n]+/g, ''); //You must use this replace, see explanation below in "Step 3"
  this.classList.toggle('empty', !s);
  
  //NEW CODE:
  
  //Make element always have <br>. See description in html. I guess it is not needed because only Firefox has bug with bad cursor position but Firefox always adds this element by itself except on init. But on init we are adding it by ourselves (see html).
  if (!s && !Array.prototype.filter.call(this.children, el => el.nodeName === 'BR').length)
   this.appendChild(document.createElement('br'));
 }
});
/*OLD CODE:*/

.CETextInputBorder { /*This element is needed to prevent cursor: text on border*/
 display: inline-block;
 border: 1px solid #aaa;
}

.CETextInputCont {
 overflow: hidden;
 cursor: text; /*You must set it because parent elements is bigger then child contenteditable element. Also you must add javascript to focus child element on click parent*/
 
 /*Style:*/
 width: 10em;
 height: 1em;
 line-height: 1em;
 padding: 5px;
 font-size: 20px;
 font-family: sans-serif;
}

.CETextInput {
 white-space: pre; /*"pre" is like "nowrap" but displays all spaces correctly (with "nowrap" last space is not displayed in Firefox, tested on Firefox 66, 2019-05-15)*/
 overflow-x: auto;
 min-height: 100%; /*to prevent zero-height with no text*/
 
 /*We will duplicate vertical padding to let user click contenteditable element on top and bottom. We would do same thing for horizontal padding but it is not working properly (in all browsers when scroll is in middle position and in Firefox when scroll is at the end). You can also replace vertical padding with just bigger line height.*/
 padding: 5px 0;
 margin-top: -5px;
 
 outline: none; /*Prevent border on focus in some browsers*/
}

.CETextInput:not(.empty) br,
.CETextInput img { /*We hide <img> here. If you need images do not hide them but set maximum height. User can paste image by pressing Ctrl+V or Ctrl+Insert.*/
 display: none;
}

.CETextInput * {
 display: inline;
 white-space: pre;
}

/*NEW CODE:*/

.CETextInput[placeholder].empty::before { /*Use ::before not ::after or you will have problems width first <br>*/
 content: attr(placeholder);
 display: inline-block;
 width: 0;
 white-space: nowrap;
 pointer-events: none;
 cursor: text;
 color: #b7b7b7;
 
 padding-top: 8px;
 margin-top: -8px;
}
<!--OLD CODE:-->

<div class="CETextInputBorder">
 <div class="CETextInputCont">
  <div class="CETextInput" placeholder="Type something here" contenteditable><br></div>
 </div>
</div>

<!--We manually added <br> element for Firefox browser because Firefox (tested on 2019-05-11, Firefox 66) has bug with bad text cursor position in empty contenteditable elements that have ::before or ::after pseudo-elements.-->

只使用一个 div 和 "scrollbar-width" 的解决方案

您还可以通过设置 "overflow-x: auto"、"overflow-y: hidden" 和 "scrollbar-width: none" 来仅使用一个 div。但是,"scrollbar-width" 是一种新属性,目前仅在 Firefox 64+ 中起作用,其他浏览器尚未支持。

您还可以添加以下内容:

  • webkit 前缀版本:" -webkit-scrollbar-width: none"
  • 非标准化的 ".CETextInput::-webkit-scrollbar { display: none; }"(适用于基于 Webkit 的浏览器)
  • "-ms-overflow-style: none"

我不建议使用这种解决方案,但这里有一个示例:

//OLD CODE:

document.querySelectorAll('.CETextInput').forEach(el => {
 //Focusing on child is not needed anymore
 
 //Prevent Enter to prevent blur on Enter
 el.addEventListener('keydown', function(e) {
  if (e.keyCode === 13)
   e.preventDefault();
 });
 
 //Update "empty" class on all "CETextInput" elements:
 updateEmpty.call(el); //init
 el.addEventListener('input', updateEmpty);

 function updateEmpty(e) {
  const s = this.innerText.replace(/[\r\n]+/g, ''); //You must use this replace, see explanation below in "Step 3"
  this.classList.toggle('empty', !s);
 }
});
/*NEW CODE:*/

.CETextInput {
 white-space: pre; /*"pre" is like "nowrap" but displays all spaces correctly (with "nowrap" last space is not displayed in Firefox, tested on Firefox 66, 2019-05-15)*/
 overflow-x: auto; /*or "scroll"*/
 overflow-y: hidden;
 -webkit-scrollbar-width: none; /*Chrome 4+ (probably), webkit based*/
 scrollbar-width: none; /*FF 64+, Chrome ??+, webkit based, Edge ??+*/
 -ms-overflow-style: none; /*IE ??*/
 
 /*Style:*/
 width: 10em;
 height: 1em;
 line-height: 1em;
 padding: 5px;
 border: 1px solid #aaa;
 font-size: 20px;
 font-family: sans-serif;
}

.CETextInput::-webkit-scrollbar {
 display: none; /*Chrome ??, webkit based*/
}

/*OLD CODE:*/

.CETextInput:not(.empty) br,
.CETextInput img { /*We hide <img> here. If you need images do not hide them but set maximum height. User can paste image by pressing Ctrl+V or Ctrl+Insert.*/
 display: none;
}

.CETextInput * {
 display: inline;
 white-space: pre;
}
<!--NEW CODE:-->

<div class="CETextInput" contenteditable></div>

这个解决方案的3个问题与填充有关:

  1. 在Firefox中(在2019-05-11上测试了Firefox 66),当输入长文本时,没有右填充。这是因为Firefox不显示底部或右侧填充,当在具有滚动条并且内容滚动到末尾的同一元素中使用填充时。
  2. 在所有浏览器中,在滚动长文本到中间位置时没有填充。看起来更糟糕。 <input type="text">没有这个问题。
  3. 当用户按home或end键时,浏览器会滚动到填充不可见的位置。

要解决这些问题,您需要使用3个元素,就像我们以前使用的那样,但在这种情况下,您不需要使用scrollbar-width。我们使用3个元素的解决方案没有这些问题。


其他问题(在每个解决方案中):

  • 粘贴文本并带有换行符时,模糊结束。我会想办法解决它。
  • 在使用填充时,“this.children[0].focus()”在基于Webkit的浏览器中不够用(光标位置不在用户点击的位置)。我会想办法解决它。
  • Firefox(在2019-05-11上测试了Firefox 66):当输入短文本时,用户无法通过在其右侧双击来选择最后一个单词。我会考虑一下。
  • 当用户在页面中开始选择文本时,他可以结束在我们的字段中。通常的<input type="text">没有这种行为。但我认为这不是关键问题。

所以你让我将其标记为已接受,但这个解决方案仍然在 Firefox 67 beta(macOS)中有一个水平滚动条。 - Gijs
@Gijs,我安装了Firefox 67 beta版本,但我的解决方案中没有滚动条。请发送您使用的usercss(或者如果您使用Stylish,则是css)。也许您只使用了一个<div>的解决方案?它在Firefox 64+中没有滚动条(但Firefox 67比Firefox 64更大,但也许您使用的是Firefix 63或更低版本)。 - vitaliydev
写作时,我在Mozilla工作,已经工作了几年。我知道我正在使用哪个Firefox版本,谢谢。我不使用任何用户CSS或时尚样式。我使用了你回答中的第一个代码片段。我在Mac上,滚动条设置为自动隐藏(默认设置)。截图:https://imgur.com/a/AkupcSh。 - Gijs
感谢您提供的全面答案;但还有一个未解决的问题:粘贴格式化文本。http://s.webcore.io/a1033aac7057/its-so-green.png - amcgregor
太棒了!真是太棒了!!你解决了我过去两周一直遇到的问题,即鼠标滚轮选择文本。无法感谢你。 <3 - Gogol

6

我认为你正在寻找一个具有contenteditable属性的div,且只有一行文本,在文本超出div范围时可以水平滚动。这个方法应该可以解决问题:http://jsfiddle.net/F6C9T/1

div {
    font-family: Arial;
    font-size: 18px;
    min-height: 40px;
    width: 300px;
    border: 1px solid red;
    overflow: hidden;
    white-space: nowrap;
}
<div contenteditable>
    Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
</div>

min-height: 40px 包括水平滚动条出现时的高度。当水平滚动条出现时,min-height:20px 会自动扩展,但在IE7中无效(尽管您可以使用条件注释应用单独的样式)。


这很不错,但出于美观的考虑,我敢打赌产品管理人员会讨厌滚动条。有没有什么聪明的主意可以在没有滚动条的情况下完成它?(“没有”是完全有效的,但我还是很好奇的;-))。 - Gijs
@gijs:所以你想用光标滚动而不是实际的滚动条?你不能使用<input type="text" />吗? - tw16
是的,没错:想要在文本输入框中插入图片。 :-) - Gijs
1
@gijs:要复制您想要的效果并不容易。但从可用性的角度来看,滚动条要好得多。这个解决方案仍然实现了单行非换行contenteditable``div的最终目标,允许内容滚动。 - tw16
1
为了以后的参考,可以在不使用滚动条的情况下使其工作。只需设置 overflow-x:hidden;,然后它将随着光标滚动文本,而不显示滚动条。 - BurningLights
2
该解决方案无法正常工作,因为用户无法通过选择文本或鼠标中键滚动行(但可以使用键盘箭头)。 - vitaliydev

4

我改编了@tw16于2019年12月5日接受的解决方案,以添加滚动功能。关键是使用overflow-x: auto添加滚动条,然后隐藏滚动条 (https://dev59.com/j2Qn5IYBdhLWcg3wpYj0#49278385)

/* Existing Solution */
[contenteditable="true"].single-line {
    white-space: nowrap;
    width: 200px;
    overflow: hidden;
} 
[contenteditable="true"].single-line br {
    display:none;

}
[contenteditable="true"].single-line * {
    display:inline;
    white-space:nowrap;
}

/* Make Scrollable */
[contenteditable="true"].single-line {
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none; /* Firefox */
    -ms-overflow-style: none;  /* Internet Explorer 10+ */
}
[contenteditable="true"].single-line::-webkit-scrollbar { /* WebKit */
    width: 0;
    height: 0;
}    
<div contenteditable="true" class="single-line">
    This should scroll when you have really long text!
</div>


3

以下是一个相对简单的解决方案,它使用contenteditable的input事件来扫描dom并过滤出各种换行符号(因此它应该可以抵御复制/粘贴、拖放、键盘输入等操作)。 它将多个TextNodes压缩到单个TextNodes中,从TextNodes中删除换行符,消除BR元素,并在其触及的任何其他元素上放置“display:inline”。 在Chrome上测试,其他地方没有保证。

var editable = $('#editable')

editable.on('input', function() {
  return filter_newlines(editable);
});


function filter_newlines(div) {
    var node, prev, _i, _len, _ref, _results;
    prev = null;
    _ref = div.contents();
    _results = [];
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        node = _ref[_i];
        if (node.nodeType === 3) {
            node.nodeValue = node.nodeValue.replace('\n', '');
            if (prev) {
                node.nodeValue = prev.nodeValue + node.nodeValue;
                $(prev).remove();
            }
            _results.push(prev = node);
        } else if (node.tagName.toLowerCase() === 'br') {
            _results.push($(node).remove());
        } else {
            $(node).css('display', 'inline');
            filter_newlines($(node));
            _results.push(prev = null);
        }
    }
    return _results;
}
#editable {
    width: 200px;
    height: 20px;
    border: 1px solid black;
}
<div id="editable" contenteditable="true"></div>

这里有一个 jsfiddle 的链接可以查看:http://jsfiddle.net/tG9Qa/


1
很遗憾,input事件在contenteditable上并不被所有浏览器普遍支持。IE和Opera根本不支持它,而Firefox自14版本才开始支持它。 - Tim Down
蒂姆说的没错。但理想情况下,这种事情应该比处理当前的各种事件、DOM怪癖等更明智(当然,你目前的代码也没有做到后者,但对于那些可以对使用的浏览器提出相当严格要求的人来说,这可能是一个不错的开始)。 - Gijs

2
如果你想用不同的方法来解决它而不是更改需求,那么只需要加上一点 display:table 就可以完全实现 =)

.container1 {
    height:20px;
    width:273px; 
    overflow:hidden;
    border:1px solid green;
}
.container2 {
    display:table;
}
.textarea {
    width:273px;
    font-size: 18px;
    font-weight: normal;
    line-height: 18px;
    outline: none;
    display: table-cell;
    position: relative;
    -webkit-user-select: text;
    -moz-user-select: text;
    -ms-user-select: text;
    user-select: text;
    word-wrap: break-word;    
    overflow:hidden;
}
<div class="container1">
    <div class="container2">
        <div contenteditable="true" class="textarea"></div>
    </div>
</div>


糟糕的解决方案。使用overflow: hidden;时滚动不起作用。 - vitaliydev

1

因此,为了后代:最简单的解决方案是让您的产品经理更改要求,以便您可以进行多行编辑。这就是我们的情况最终发生的事情。

然而,在这之前,我最终创建了一个手动移动单行富文本编辑器。最后我将其封装在jQuery插件中。我没有时间完成它(在IE中可能会有错误,Firefox效果最佳,Chrome效果相当不错-注释很少且有时不太清楚)。 它使用 Rangy library的部分(提取出来是因为我不想依赖于完整的库)来获取所选内容的屏幕位置,以便测试鼠标位置与所选内容的区别(这样您就可以拖动选择并移动框)。

大致上,它通过使用3个元素来工作。外部div(您在插件上调用的东西),该元素获得overflow: hidden,然后内部有两个嵌套级别。第一级是绝对定位,第二级是实际的contenteditable。这种分离是必要的,否则某些浏览器将给contenteditable绝对定位元素 grippies,以让用户将其移动...

无论如何,然后有一堆代码来移动绝对定位的元素在顶部元素内部,从而移动实际的contenteditable。 contenteditable本身具有white-space nowrap等等,以强制它保持单行。
插件中还有代码,可以从拖入框中的任何文本中剥离出除图像之外的任何内容(例如br、表格等等)。您需要其中的某些部分(例如brs、剥离/规范化段落等),但是也许通常希望保留链接、em、strong和/或其他一些格式。
来源:https://gist.github.com/1161922

1

看看我刚刚发布的答案。这应该会帮助你:

如何创建一个HTML5单行contentEditable选项卡,它监听Enter和Esc键

这是HTML标记:

<span contenteditable="false"></span>

这是jQuery/javascript代码:

$(document).ready(function() {
    $('[contenteditable]').dblclick(function() {
        $(this).attr('contenteditable', 'true');
        clearSelection();
        $(this).trigger('focus');
    });

    $('[contenteditable]').live('focus', function() {
        before = $(this).text();
        if($(this).attr('contenteditable') == "true") { $(this).css('border', '1px solid #ffd646'); }
    //}).live('paste', function() {
    }).live('blur', function() {
        $(this).attr('contenteditable', 'false');
        $(this).css('border', '1px solid #fafafa');
        $(this).text($(this).text().replace(/(\r\n|\n|\r)/gm,""));

        if (before != $(this).text()) { $(this).trigger('change'); }
    }).live('keyup', function(event) {
        // ESC=27, Enter=13
        if (event.which == 27) {
            $(this).text(before);
            $(this).trigger('blur');
        } else if (event.which == 13) {
            $(this).trigger('blur');
        }
    });

    $('[contenteditable]').live('change', function() {
        var $thisText = $(this).text();
        //Do something with the new value.
    });
});

function clearSelection() {
    if ( document.selection ) {
        document.selection.empty();
    } else if ( window.getSelection ) {
        window.getSelection().removeAllRanges();
    }
}

希望这能帮助到某人!!!

这还不够,因为我仍然可以复制并粘贴到这个文本框中,这会完全混淆您的代码并显示换行符。此外,您的代码会剥离所有HTML(仅使用“text”)- 所以我实际上不太确定为什么您不只是使用一个文本框。 - Gijs
你也可以使用 .html() 方法。这适用于选项卡或其他文本,因此您不希望它作为文本框。只有双击后,才能进行编辑。至于“粘贴”,也有相应的注释行。您可以根据需要进行处理。 - Anthony Graglia

0

你可以在调用onclick事件后,将此div替换为文本输入框。
我之前使用了类似这个插件的东西,它工作得很好。


这样做将不允许用户在图片之后继续输入/移动/选择,因此这对我们的应用程序不可行。它应该像完整的单行输入框一样运作。 - Gijs

-3
使用jQuery,我设置了一个.keypress事件,然后测试e.keyCode == 13(回车键),如果是则从事件返回false,并且编辑无法进行多行编辑。
$('*[contenteditable=yes]').keypress(function(e) {
  if(e.keyCode == 13 && !$(this).data('multiline')) {
    return false;
  }
})

3
这种方法行不通。人们插入换行符的方式有很多种,不仅仅是通过按键(考虑拖放、复制粘贴等)。此外,根据规范,contenteditable 属性的值只能是 truefalseinherit 或空字符串,而不是 yes。我还怀疑(但没有检查过)抑制回车键事件不能保证在各种浏览器中都有效,可能需要改用 keydown 和/或 keyup - Gijs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接