Contenteditable <div>
領域があり、この領域内にテキストを含む<span contenteditable="false"></span>
がある場合があります。これらのスパン要素は、編集できないスタイル付きテキストを表しますが、バックスペースキーを押すことで<div contenteditable="true"></div>
領域から削除できます。
カーソルの配置がここでの大きな問題です。これらの<span>
要素のいずれかを削除すると、カーソルは<div>
の末尾にジャンプします。さらに興味深いことに、カーソルが「最後」にあるときにテキストを入力すると、テキストの配置は問題ありません...次に、新しく入力したテキストを削除すると、カーソルが元に戻ります。
これを実証するフィドルを用意しました。 これはChromeでのみ機能する必要があり、他のブラウザは今のところ問題がないか、回避策があります。 (また、準備されたFiddleは、これをChromeでのみ示すように作成されていることに注意してください)
フィドル
フィドル命令:Chromeバージョン39.0.2171.95m(64ビット)32ビットで再現同じように
<div>
エリアをクリックしますこれを広範囲に調査して、似たようなさまざまなSOの質問に出くわしましたが、関連するソリューションを借りることが、私が求めている特効薬であるとは証明されていません。また、Chromeプロジェクトで、上記の問題をターゲットにしているように見える問題を見つけました(おそらく正確な方法ではありません)。以下で確認できます。
私が見つけた最も近いSOソリューションは ここ である可能性があります。このソリューションのアイデアは、‌
要素の後に<span>
文字を配置することですが、<span>
を削除したい場合は、代わりに‌
...を削除します。カーソルを最後にジャンプして、「最初のDeleteキーストローク」で<span>
を削除しないことで、奇妙なUIエクスペリエンスを提供します。
誰かがこの問題を経験し、回避策を見つけましたか? JSがハッキーになったとしても、考えられる解決策を歓迎します。 contenteditable
を活用することには、苦労のリストが付属していることを知りましたが、これが私が現在抱えている最後の難しさのようです。
なぜそうなるのかわかりませんが、<div>
のサイズと関係があると感じたので、display
プロパティで遊んでみました。 inline-block
に設定し、テキストを少し試してみたところ、編集、具体的には改行を追加すると、問題が解消されたことがわかりました。
何らかの理由で、新しい行を削除した後、<br/>
タグがdiv.main
に保持されているのを見ましたが、<div>
の外観と、矢印キーへの応答方法は新しい行がない場合と同じです。
そこで、CSSを変更し、<br/>
とビオラにdiv.main
タグを付けて、フィドルを再起動しました。
結論として:
display: inline-block
をdiv.main
に追加します<br/>
の最後にdiv.main
を追加します問題は、contenteditable
要素がdiv
であり、デフォルトではdisplay: block
であるということです。これがキャレット位置の問題の原因です。これは、最も外側のdiv
を編集不可にし、inline-block
として扱われる新しい編集可能なdiv
を追加することで修正できます。
新しい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
も追加しましたが、これを防ぐために必要ではありません。質問で報告されたキャレットジャンプの問題。
これが フィドル です。
発見し始めたように、contenteditable
はブラウザ間で一貫性のない方法で処理されます。数年前、私はcontenteditable
ですべてが簡単になると思ったプロジェクト(ブラウザー内XMLエディター)の作業を開始しました。その後、アプリケーションを開発すると、contenteditable
が無料で提供すると思っていた機能を引き継ぐことにすぐに気付きました。今日、contenteditable
が私に与える唯一のことは、編集したい要素のキーボードイベントをオンにすることです。キャレットの動きやキャレットの表示など、その他すべてはカスタムコードによって管理されます。
したがって、input
フィールドが更新されたときにトリガーされる contenteditable
イベントに依存する、少しクリーンなアプローチの実装があります。このイベントは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;
}
<div>
の最後でカーソルが誤動作するinitial問題をJQueryで解決するためのハックな方法を見つけました。私は基本的に、カーソルが<i>
の内容の最後に「ラッチ」するための空の<div>
を挿入しています。このタグは、font-style: normal
(フィドルを参照)をオーバーライドするために通常のテキストからバックスペースするときにエンドユーザーにUIの違いがなく、挿入するために<span>
とは異なるものが必要だったために機能します
私はこの回避策に特にわくわくしていません。特に<i>
を選択したからですが、より良い代替案に出くわすことはありません。うまくいけば矢印キーも理解するためにこれに取り組み続けるつもりですが、幸いなことに、私はFiddleのこのグリッチに悩まされており、コードには悩まされていません。
Fiddle(Chromeのみ)
<div id="main" contenteditable="true">
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
<span contenteditable="false">item</span>
</div>
function hackCursor() {
return $('#main :last-child').get(0).tagName === 'SPAN' ?
$('#main span:last-child').after('<i style="font-style: normal"></i>') :
false;
}
$(function(){
hackCursor();
$('#main').bind({
'keyup': function(e) {
hackCursor();
}
})
});
改行文字を追加するだけです(\n
)contenteditable
タグを閉じる前。たとえばJavaScriptの場合:var html = '<div id="main" contenteditable="true">' + content + "\n" + '</div>'