Gij*_*ijs 56 html javascript css jquery contenteditable
对于我在我工作的公司开发的应用程序,我们需要一个支持在基于JS的Web应用程序中插入表情符号的输入.我们目前正在使用带有表情符号短代码(即':-)')的输入,并希望切换到插入实际的图形图像.
我们最初的计划是使用contenteditable <div>.我们正在使用监听器来执行粘贴事件以及不同的键/鼠标交互,以确保没有不需要的标记进入contenteditable(我们从其容器标签中删除文本并仅留下我们自己插入的图像标签).
但是,现在的问题是如果你输入足够的内容(即它的高度增加),div会调整大小.我们不希望这种情况发生,文本只是被隐藏(即普通overflow: hidden)也是不可接受的.所以:
有没有办法让contenteditable div表现得像单行输入?
我最喜欢,如果有一个相对简单的属性/ css属性,我错过了将做我想要的,但如果有必要CSS + JS建议也将不胜感激.
小智 106
[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;
}Run Code Online (Sandbox Code Playgroud)
<div contenteditable="true" class="single-line">
This should work.
</div>?Run Code Online (Sandbox Code Playgroud)
其他答案是错误的,几乎没有错误(2019-05-07)。其他解决方案建议使用“空白:nowrap”(防止携带到另一行)+“溢出:隐藏”(防止长文本超出字段)+隐藏 <br> 等。
该解决方案中的第一个错误是“溢出:隐藏”也会阻止滚动文本。用户将无法通过以下方式滚动文本:
他可以滚动的唯一方法是使用键盘箭头。
您可以通过同时使用“溢出:隐藏”和“溢出:自动”(或“滚动”)来解决此问题。您应该使用“溢出:隐藏”创建父 div 以隐藏用户不应看到的内容。这个元素必须有输入边框和其他设计。并且您应该使用“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();
});
});Run Code Online (Sandbox Code Playgroud)
.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*/
}Run Code Online (Sandbox Code Playgroud)
<div class="CETextInputBorder">
<div class="CETextInputCont">
<div class="CETextInput" contenteditable></div>
</div>
</div>Run Code Online (Sandbox Code Playgroud)
还有一个问题是用户或扩展程序可以粘贴
但是建议隐藏所有<br> 也是错误的。那是因为 Mozilla Firefox 将 <br> 元素添加到空字段(我想这可能是删除最后一个字符后文本光标消失的解决方法;在 2019-03-19 发布的 Firefox 66 中检查)。如果您隐藏此元素,则当用户将焦点移动到字段时,将在此隐藏的 <br> 元素中设置插入符号,并且文本光标也将(始终)隐藏。
如果您在知道字段为空时将成为 <br>,则可以解决此问题。你在这里需要一些 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);
}
});Run Code Online (Sandbox Code Playgroud)
/*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;
}Run Code Online (Sandbox Code Playgroud)
<!--OLD CODE:-->
<div class="CETextInputBorder">
<div class="CETextInputCont">
<div class="CETextInput" contenteditable></div>
</div>
</div>Run Code Online (Sandbox Code Playgroud)
我们隐藏了 <br> 元素,因此“innerText”值将不包含它们。但:
因此,当您获得价值时,您应该进行替换以避免意外换行:
s = s.replace(/[\r\n]+/g, '');
Run Code Online (Sandbox Code Playgroud)
您也可以通过 javascript 删除它们来解决 <br> 的问题,但这是非常糟糕的解决方案,因为在每个删除用户之后,无法再使用“撤消”操作来取消在删除之前所做的更改。
您也可以使用 document.execCommand('delete') 删除 <br> ,但很难实现 + 用户可以撤消您的删除并恢复 <br> 元素。
它没有被问到,但我想很多使用单行 contenteditable 元素的人会需要它。以下是如何使用 css 和我们上面讨论的“空”类制作占位符的示例:
//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'));
}
});Run Code Online (Sandbox Code Playgroud)
/*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;
}Run Code Online (Sandbox Code Playgroud)
<!--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.-->Run Code Online (Sandbox Code Playgroud)
你也可以通过设置“overflow-x: auto”、“overflow-y: hidden”和“scrollbar-width: none”来只使用一个div。但“滚动条宽度”是新属性,仅适用于 Firefox 64+,尚不适用于其他浏览器。
您还可以添加:
我不建议使用此解决方案,但以下是示例:
//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);
}
});Run Code Online (Sandbox Code Playgroud)
/*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;
}Run Code Online (Sandbox Code Playgroud)
<!--NEW CODE:-->
<div class="CETextInput" contenteditable></div>Run Code Online (Sandbox Code Playgroud)
这个解决方案有3 个关于 padding 的问题:
要解决这些问题,您需要使用我们之前使用的 3 个元素,但在这种情况下,您不需要使用滚动条宽度。我们的 3 个元素的解决方案没有这些问题。
我认为你正在寻找一个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;
}Run Code Online (Sandbox Code Playgroud)
<div contenteditable>
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
</div>Run Code Online (Sandbox Code Playgroud)
的min-height: 40px结合了用于显示的水平滚动条时的高度.min-height:20px当水平滚动条出现时,A 会自动展开,但这在IE7中不起作用(尽管如果需要,可以使用条件注释来应用单独的样式).
我改编了 @tw16 接受的解决方案(2019 年 12 月 5 日)以添加滚动功能。技巧是使用添加滚动overflow-x: auto,然后隐藏滚动条(/sf/answers/3449486981/)
/* Existing Solution */\r\n[contenteditable="true"].single-line {\r\n white-space: nowrap;\r\n width: 200px;\r\n overflow: hidden;\r\n} \r\n[contenteditable="true"].single-line br {\r\n display:none;\r\n\r\n}\r\n[contenteditable="true"].single-line * {\r\n display:inline;\r\n white-space:nowrap;\r\n}\r\n\r\n/* Make Scrollable */\r\n[contenteditable="true"].single-line {\r\n overflow-x: auto;\r\n overflow-y: hidden;\r\n scrollbar-width: none; /* Firefox */\r\n -ms-overflow-style: none; /* Internet Explorer 10+ */\r\n}\r\n[contenteditable="true"].single-line::-webkit-scrollbar { /* WebKit */\r\n width: 0;\r\n height: 0;\r\n} Run Code Online (Sandbox Code Playgroud)\r\n<div contenteditable="true" class="single-line">\r\n This should scroll when you have really long text!\r\n</div>\xe2\x80\x8bRun Code Online (Sandbox Code Playgroud)\r\n