contenteditable属性について
通常、Webページで入力をする場合は、inputタグかtextareaタグで閲覧者の文字入力を行います。 ログインページのIDやパスワード、お問い合わせページの内容入力などは、おそらくすべてinputタグかtextareaタグでformタグ内に構成されていると思います。 これを、他のどんなタグでも、中(innerHTML)に書かれている文字列を自由に編集(書き換え)できるようにするのが、contenteditable属性です。 以下のデモで、それぞれの挙動を確認してみてください。デモ
DIVタグ
デモのソースコード
<input type="text" value="inputタグ" style="border:1px solid black;padding:10px;width:100%;">
<textarea style="border:1px solid black;padding:10px;width:100%;min-height:80px;">textareaタグ</textarea>
<div contenteditable="true" style="border:1px solid black;padding:10px;">DIVタグ</div>
contenteditableのメリット
inputとtextaareaは、contenteditableと同じと思う人も多いかもしれませんが、最も違う点で、利点でもある、ネストタグを内包できるという点です。 何なら、画像や、別ページのDOM構造もそのまま貼り付けることができるのが、contenteditable属性です。 もちろん、inputとtextareaは、いわゆる文字列だけしか扱えないので、装飾も含めたDOM構造が手軽に扱えるのが、contenteditable属性のメリットですね。contenteditableのデメリット
いろいろなサイトでcontenteditableについて書かれている記事などを見ていると、ブラウザによって、文字入力時などのキー操作や挙動が若干違うという事が書かれています。 一番問題になっていた、コピペができないブラウザがあるとの事だったので、GoogleChrome、Safari、FirefonをMacですが確認したところ、この3つに関しては同じ挙動をしているようでした。 おそらく、スマホアプリなどで使われるアプリ内ブラウザや、ossを利用した独自ブラウザなどにおいて、それぞれの挙動が存在するのだと思った。エンジニア視点からのアプローチ
何だか新しく覚えた機能は、早速でも使ってみたくなるのが、エンジニアの特性。 個人的に、次のような場合はどうするか(どうなるか)というのをいくつか紹介してfocus対応
focus()は普通に対応できますが、キャレット(カーソル位置)が、要素内の文字列の先頭になります。 それを末尾に移動させるには、次のコードでできます。const elm = document.querySelector(".contenteditable")
elm.focus()
const selection = window.getSelection()
const range = document.createRange()
const offset = elm.innerText.length
range.setStart(elm.firstChild, offset)
range.setEnd(elm.firstChild, offset)
selection.removeAllRanges()
selection.addRange(range)
1行目のセレクタを該当のcontenteditable要素に書き換えるだけで、行末のキャッレトフォーカスが実現できます。
内部の文字列やDOM構造の取得
これは非常に簡単で、文字列だけをしゅとくしたければ、document.querySelector(".contenteditable").textContent
DOM構造を取得したければ、
document.querySelector(".contenteditable").innerHTML
こちらで内容取得が柔軟に行えます。
さらに、内部DOMを分解調査などもしやすいので、悪くないですね。
※DOM構造をコピペした場合は、style属性などが、必要以上にくっついてくるので、これらの精査をする必要がある場合もあるかも。
入力イベントなどの可否
inputやtextareaと同様に、次のイベント達が正常に動作するか調べてみました。focus : OK blur : OK change : NG input : OK keypress : OK残念ながら、onchangeイベントが動作しませんでした。 inputイベントをうまくフラグ的に処理して、blurイベント発火で独自にonchange発火を取得するしかないですかね?
inputのように改行をさせないようするには
inputとtextareaのそれぞれのタグを使い分けるには、改行を含むかどうかというポイントがあります。 contenteditableをtrueにすると、自由に改行ができてしまう、いわゆるtextarea状態になってしまうので、 inputタグのように1行しか入力させたくない場合はどうすればいいかというと、 まず簡易に考えた、cssでのwhite-space:nowrapをセットするだけだと、改行されてしまう。 これは、contenteditableが改行でdivタグを追加する仕様だからである。 他のサイトで色々と研究されていて、keypressイベントなどで、enterを発火させるといいのだが、document.querySelector(".contenteditable").addEventListener("keypress" , ((e)=>{
console.log("keypress", e.keyCode)
if(e.keyCode === 13){
e.preventDefault()
}
}))
コピペ時にenterを取り除く対応もしなければ十分とは言えない。
ペーストを禁止させるのは、以下のイベントで簡単にセットできる。
document.querySelector(".contenteditable").addEventListener("paste" , ((e)=>{
console.log("paste")
e.preventDefault()
}))
formとして送信したい場合
formタグを使って、action属性で、サーバーの受取用APIなどに、入力データを送りたい場合は、いくつかの方法があります。 1. 普通にformタグを作って、サーバーに操作するtextarea(隠し要素)に内包するDOMをinputイベントで自動挿入して、formのsubmitで送信する。 2. new FormData()を使って、JS側でサーバー送信を行う。// Sample
const formData = new FormData();
formData.append("name", document.querySelector(".name").textContent);
3. JSのAjaxを使って柔軟にサーバーへのデータ送信をする。
0 件のコメント:
コメントを投稿