我有一个满意的<div>
区域,在这个区域内我可能会有一些<span contenteditable="false"></span>
包含一些文字。这个想法是,这些span元素将代表无法编辑的样式文本,但可以通过按退格键从<div contenteditable="true"></div>
区域删除。
光标位置是最重要的问题。如果删除其中一个<span>
元素,则光标会跳转到<div>
的末尾。更有趣的是,如果你键入一些文字,而光标是#34;最后,&#34;文本放置很好......然后,如果删除新键入的文本,光标会跳回来!
我准备了一个小提琴来证明这一点。 我需要此功能才能在Chrome 中使用,而其他浏览器现在不需要关注或者有适当的解决方法。 (另请注意,准备好的小提琴只是为了在Chrome中展示这一点)。
Fiddle
小提琴说明:Chrome版本39.0.2171.95 m(64位)以32位再现
<div>
区域对此进行了广泛的研究,我遇到了类似的各种SO问题,但借用相关解决方案并未证明是我追求的银弹。我还发现了Chrome项目的问题,这些问题似乎针对上述问题(可能不是以精确的方式),可以在下面查看。
我找到的最接近的SO解决方案可能是here。此解决方案中的想法是在‌
元素之后放置<span>
个字符,但如果我现在要删除<span>
,我会删除‌
...强制我的光标跳到最后,通过不删除我的&#34;初始删除键击中的<span>
来提供奇怪的UI体验。&#34;
是否有人遇到此问题并找到了解决方法?我欢迎任何可能的解决方案,即使JS他们来的时候也很讨厌。我已经开始了解利用contenteditable
带来了一份挣扎的清单,但这似乎是我目前的最后一个难点。
答案 0 :(得分:16)
我不知道为什么会这样,但我觉得它与<div>
的大小有关,所以我尝试使用display
属性。在将其设置为inline-block
并使用文本稍微播放之后,我发现在我对其进行一些编辑后,问题就消失了,特别是添加了新行。
我看到,出于某种原因,<br/>
标记在我删除新行后保留在div.main
中,但<div>
的外观及其对箭头的响应方式键与其中没有新行相同。
所以我重新启动了CSS更改以及<br/>
和中提琴中的div.main
标记!
总结如下:
display: inline-block
添加到div.main
<br/>
div.main
醇>
<强> JSFiddle Link 强>
答案 1 :(得分:4)
问题是您的contenteditable
元素是div
,默认情况下为display: block
。这是导致您的插入位置问题的原因。这可以通过使最外面的div
不可编辑并添加将被视为div
的新的可编辑inline-block
来解决。
新HTML将在外部HTML中有一个新的div
(以及最后的相应结束标记):
<div id="main" class="main"><div id="editable" contenteditable="true">...
并将其添加到您的CSS:
div#editable {
display: inline-block;
}
为了在span
元素之间更好地查看插入符号,我还在CSS中为margin: 2px
的规则添加了div.main span
但这不是必须防止问题中报告的插入符号跳跃问题。
这是fiddle。
当您开始发现时,contenteditable
在浏览器中的处理方式不一致。几年前,我开始研究一个项目(浏览器内的XML编辑器),我认为contenteditable
会让一切变得更容易。然后当我开发应用程序时,我很快发现自己接管了我认为contenteditable
将免费提供给我的功能。今天,contenteditable
给我的唯一一件事就是它会打开我想编辑的元素上的键盘事件。其他所有内容,包括插入符号移动和插入符号显示,都由自定义代码管理。
答案 2 :(得分:1)
因此,我的方法稍微更清晰一些,它依赖于contenteditable
字段更新时触发的input
事件。 IE不支持此事件,但看起来contenteditable
在IE中非常不稳定。
它基本上会在标记为contenteditable="false"
的每个元素周围注入元素。它可能是在初始加载时而不是在input
事件上完成的,但我认为您可能有办法向该区域注入更多span
,因此input
应该考虑到此
限制包括箭头键周围的一些奇怪的行为,就像你自己看到的那样。我所看到的主要是当你向后移动跨度时光标保持其正确的位置,但是当你向前移动时则不是。
<强>的Javascript 强>
$('#main').on('input', function() {
var first = true;
$(this).contents().each(function(){
if ($(this).is('[contenteditable=false]')) {
$("<i class='wrapper'/>").insertAfter(this);
if (first) {
$("<i class='wrapper'/>").insertBefore(this);
first = false
}
}
});
}).trigger('input');
<强> CSS 强>
div.main {
width: 400px;
height: 250px;
border: solid 1px black;
}
div.main span {
width:40px;
background-color: red;
border-radius: 5px;
color: white;
cursor: pointer;
}
i.wrapper {
font-style: normal;
}
答案 3 :(得分:0)
我找到了一种解决<{1>}末尾带有一些JQuery的游标行为错误的初始问题的hacky方法。我基本上是为光标插入一个空<div>
到&#34; latch&#34;在<i>
内容的末尾。这个标签对我有用,因为由于覆盖<div>
(请参阅小提琴)而从正常文本退回这些内容时,最终用户没有UI差异,而且我还需要一些不同于font-style: normal
的内容来插入
我对这种解决方法并不特别激动,特别是选择<span>
只是因为,但我没有遇到更好的选择,我仍然欢迎更好的解决方案 - 如果存在的话!我打算继续努力,希望能够弄清楚箭头键,但幸运的是,我只是被小提琴中的这个小故障所困扰,而不是我的代码。
Fiddle (仅限Chrome)
<i>
<div id="main" contenteditable="true">
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
</div>
答案 4 :(得分:0)
在关闭\n
标记之前,只需添加新的行字符{contenteditable
)。
例如在JavaScript中:
var html = '<div id="main" contenteditable="true">' + content + "\n" + '</div>'
答案 5 :(得分:0)
该问题在以下示例中显而易见,可以通过将contentetiable
包装器更改为display:block
来解决,但是会导致非常令人讨厌的Chrome错误-{{1 }}将在按下ENTER键后添加
<div><br></div>
[contenteditable="true"]{
border: 1px dotted red;
box-sizing: border-box;
width: 100%;
padding: 5px;
outline: none;
display: inline-block; /* prevents Chrome from adding <div><br></div> when pressing ENTER key. highly undesirable. */
}
[contenteditable="false"]{
background: lightgreen;
padding: 3px;
border-radius: 3px;
}
让我们尝试对其进行修复:
我可以看到<div contenteditable="true">
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
</div>
的组合比内容宽,而且width
的组合也有问题。
如果有 CSS 修复的可能性,我也不想使用 javascript 。
我非常想保留display: inline-block
来防止上述Chrome错误发生,因此将display: inline-block
问题设置为{{1 }}当 contenteditable 成为焦点时,并使用允许假冒相同宽度的元素包装所有内容
和之前在 contenteditable 中使用伪元素一样(仅在聚焦时使用)
width
auto
上面的解决方案在某些情况下是好的,但是当行换行并且在最后一个像上时,最后一个元素是节点:
.wrapper{
width: 100%;
position: relative;
}
[contenteditable="true"]{
border: 1px solid red;
box-sizing: border-box;
width: 100%;
padding: 5px;
outline: none;
display: inline-block;
}
[contenteditable="true"]:focus{
border-color: transparent;
width: auto;
}
[contenteditable="true"]:focus::before{
content: '';
border: 1px solid red; /* same as "real" border */
position: absolute;
top:0; right:0; bottom:0; left:0;
}
[contenteditable="false"]{
background: lightgreen;
padding: 3px;
border-radius: 3px;
}
<div class='wrapper'>
<div contenteditable="true">
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
</div>
<div>
让我们只使用javascript并在末尾放置一个.wrapper{
width: 100%;
position: relative;
}
[contenteditable="true"]{
border: 1px solid red;
box-sizing: border-box;
width: 100%;
padding: 5px;
outline: none;
display: inline-block;
}
[contenteditable="true"]:focus{
border-color: transparent;
width: auto;
}
[contenteditable="true"]:focus::before{
content: '';
border: 1px solid red; /* same as "real" border */
position: absolute;
top:0; right:0; bottom:0; left:0;
}
[contenteditable="false"]{
background: lightgreen;
padding: 3px;
border-radius: 3px;
}
元素(如果一个元素不存在的话)(不能通过全选并删除内容将其删除):
<div class='wrapper'>
<div contenteditable="true">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
</div>
<div>
br
var elem = document.body.firstElementChild;
if( !elem.lastChild || elem.lastChild.tagName != 'BR' )
elem.insertAdjacentHTML('beforeend', '<br>')