解決策#1(プレーンテキストのみ、Firefox 22以降が必要)
IE6 +、FF 22 +、Chrome、Safari、Edgeで動作します(IE9 +でのみテストされていますが、下位バージョンでも動作するはずです)
HTMLまたはFirefox <= 22の貼り付けのサポートが必要な場合は、ソリューション#2を参照してください。
HTML
<div id='editableDiv' contenteditable='true'>Paste</div>
JavaScript
function handlePaste (e) {
var clipboardData, pastedData;
// Stop data actually being pasted into div
e.stopPropagation();
e.preventDefault();
// Get pasted data via clipboard API
clipboardData = e.clipboardData || window.clipboardData;
pastedData = clipboardData.getData('Text');
// Do whatever with pasteddata
alert(pastedData);
}
document.getElementById('editableDiv').addEventListener('paste', handlePaste);
JSFiddle:https ://jsfiddle.net/swL8ftLs/12/
このソリューションでは、関数にパラメーター 'Text'を使用していますがgetData
、これは非標準です。ただし、執筆時点ではすべてのブラウザで動作します。
ソリューション#2(HTMLおよびFirefox <= 22で動作)
IE6以降、FF 3.5以降、Chrome、Safari、Edgeでテスト済み
HTML
<div id='div' contenteditable='true'>Paste</div>
JavaScript
var editableDiv = document.getElementById('editableDiv');
function handlepaste (e) {
var types, pastedData, savedContent;
// Browsers that support the 'text/html' type in the Clipboard API (Chrome, Firefox 22+)
if (e && e.clipboardData && e.clipboardData.types && e.clipboardData.getData) {
// Check for 'text/html' in types list. See abligh's answer below for deatils on
// why the DOMStringList bit is needed. We cannot fall back to 'text/plain' as
// Safari/Edge don't advertise HTML data even if it is available
types = e.clipboardData.types;
if (((types instanceof DOMStringList) && types.contains("text/html")) || (types.indexOf && types.indexOf('text/html') !== -1)) {
// Extract data and pass it to callback
pastedData = e.clipboardData.getData('text/html');
processPaste(editableDiv, pastedData);
// Stop the data from actually being pasted
e.stopPropagation();
e.preventDefault();
return false;
}
}
// Everything else: Move existing element contents to a DocumentFragment for safekeeping
savedContent = document.createDocumentFragment();
while(editableDiv.childNodes.length > 0) {
savedContent.appendChild(editableDiv.childNodes[0]);
}
// Then wait for browser to paste content into it and cleanup
waitForPastedData(editableDiv, savedContent);
return true;
}
function waitForPastedData (elem, savedContent) {
// If data has been processes by browser, process it
if (elem.childNodes && elem.childNodes.length > 0) {
// Retrieve pasted content via innerHTML
// (Alternatively loop through elem.childNodes or elem.getElementsByTagName here)
var pastedData = elem.innerHTML;
// Restore saved content
elem.innerHTML = "";
elem.appendChild(savedContent);
// Call callback
processPaste(elem, pastedData);
}
// Else wait 20ms and try again
else {
setTimeout(function () {
waitForPastedData(elem, savedContent)
}, 20);
}
}
function processPaste (elem, pastedData) {
// Do whatever with gathered data;
alert(pastedData);
elem.focus();
}
// Modern browsers. Note: 3rd argument is required for Firefox <= 6
if (editableDiv.addEventListener) {
editableDiv.addEventListener('paste', handlepaste, false);
}
// IE <= 8
else {
editableDiv.attachEvent('onpaste', handlepaste);
}
JSFiddle:https ://jsfiddle.net/nicoburns/wrqmuabo/23/
説明
onpaste
イベントがdiv
ありhandlePaste
:それに取り付けられており、単一の引数を渡された関数event
ペーストイベントのオブジェクトを。私たちにとって特に興味深いのは、clipboardData
IE以外のブラウザでクリップボードにアクセスできるようにするこのイベントのプロパティです。IEでは同等ですがwindow.clipboardData
、APIは少し異なります。
以下のリソースセクションを参照してください。
handlepaste
機能:
この関数には2つのブランチがあります。
1つ目は、その存在を確認し、そのプロパティに 'text / html'が含まれているevent.clipboardData
かどうかを確認しますtypes
(メソッドを使用して確認される、またはメソッドを使用して確認される文字列のtypes
いずれか)。これらの条件がすべて満たされた場合は、ソリューション#1と同様に処理します。ただし、「text / plain」ではなく「text / html」を使用します。これは現在、ChromeおよびFirefox 22以降で動作します。DOMStringList
contains
indexOf
このメソッドがサポートされていない場合(他のすべてのブラウザ)、次に
- 要素のコンテンツを
DocumentFragment
- 要素を空にする
waitForPastedData
関数を呼び出す
waitforpastedata
機能:
この関数はまず、ペーストされたデータをポーリングします(20ミリ秒に1回)。これは、すぐには表示されないために必要です。データが表示されたら:
- 編集可能なdiv(現在は貼り付けられたデータ)のinnerHTMLを変数に保存します
- DocumentFragmentに保存されたコンテンツを復元します
- 取得したデータを使用して「processPaste」関数を呼び出します
processpaste
機能:
貼り付けたデータで任意のことを行います。この場合、データに警告するだけで、好きなことができます。おそらく、貼り付けたデータを何らかのデータ消毒プロセスで実行する必要があります。
カーソル位置の保存と復元
実際の状況では、前に選択を保存し、後で復元したいと思うでしょう(contentEditable <div>にカーソル位置を設定します)。次に、ユーザーが貼り付け操作を開始したときにカーソルがあった位置に貼り付けたデータを挿入できます。
リソース:
DocumentFragmentの使用を提案するTim Downに感謝し、clipboardData.typesの文字列の代わりにDOMStringListを使用することによりFirefoxでエラーをキャッチする