IIJmio(みおふぉん)

クリップボード機能利用 コピー&ペースト [ IE4以上のみ ]

何らかのイベントからクリップボードに自動的にデータをコピーさせる、或いはフォームなどにクリップボードデータを自動的にペーストさせると言う物です。

clipboardDataというオブジェクトをメソッドで操作をする単純な方法
テキストレンジ取得してexecCommand()と言うメソッドを使う方法
のどちらでも可能です。(解説はページ後半)

ユーザーの [ マウスで文字列を選択 ] - [ 右クリックでコピー ] と言う作業や、[ 右クリックでペースト] と言う作業を省かせます。
が、今は [クリップボードへのアクセスを許可しますか?] と言う警告がでます。

当然ですね。 クリップボードにコピーだけではなくクリップボードデータを取り出す(ペースト)もできてしまうのでセキュリティ上の危険行為でもあります。 コピーだけ許可などの選択肢があっても良いくらいですね。

例えばもし警告が出ない場合はユーザーが悪意のあるサイトを開いただけでクリップボードのデータを盗まれてしまいます。 もし自分が『 意図的にコピーする為にクリックなどをしてないのにこの警告が出た場合』は即座に拒否してください。 特に認証サイトなどにログインする時にパスワードをコピーしてクリップボードにデータが残ってる場合は気をつけて。

と言う事で、非常に便利な機能ですが悪用どの可能性でセキュリティ警告が出る事から、 必ずしもビジターを楽にする機能とは言いがたくなっています。 むやみに乱用すると、PCやHP作成などに詳しくない人やセキュリティ面に不安を持ってる人などは、 逆に『 怪しいページじゃなのか?』なんて思われてしまう可能性もあります。 きちんと説明などをどこかにつけるなどしてアナウンスしておきましょう。

簡単なサンプル1

[ フォームを使った 超簡単な方法 ]
■例 [ コピー ] そのまま使えます


inputタグに
onclick="clipboardData.setData('text',this.value)"
を付けただけです。
クリックするだけで、input内の文字列がクリップボードにコピーされます。


inputタグに
onclick="this.select(); clipboardData.setData('text',this.value)"
を付けました。
クリックと同時に内容テキストもselect()されます。
これはコピーできた消極的合図でもあり、NN系でコピーしやすくする為です。
this.select()を先に書かないと、NN系ではエラーの後になり動作しません。


inputタグに
onclick="this.select(); if(clipboardData.setData('text',this.value)){ alert('コピーしました') }
を付けただけです。
これは更に、コピーした事をalert()ではっきり表示します。
ビジターがクリップボードへのアクセスを拒否した場合は出ません。

これらはNN系がエラーを無視してる事を当て込んでの記述方法です。
本当は正しくないが問題ないというものですが簡単なのでJavsScriptがわからない人でも フォーム系エレメンツ(value値を持つ部品)につけるだけですぐ使えます。
エラースルーにしておくのが嫌であれば
if(!self.clipboardData) return false; 理解できない場合ここでストップ
if(self.clipboardData) 理解できる場合だけ通す
のどちらか都合の良い方をclipboardData操作の前に付けて置きます。
例:onclick="if(self.clipboardData) clipboardData.setData('text',this.value)"


■例 [ ペースト ]


inputタグに
onclick="this.value = (clipboardData.getData('text') || '')"
を付けました。
クリックするだけでクリップボードのデータが貼り付けされます。
クリップボードのデータがnullだとnullと言う文字が貼り付くので式にしてあります。 NN系ではやはり無視(エラー)されます。
NN系のエラー出力が嫌であれば
例:onclick="if(self.clipboardData) this.value = (clipboardData.getData('text') || '')"

このサンプル1の簡単な方法は、前述の説明どおりフォーム系タグにイベントハンドラとしてつけるだけで すぐに使える方法で、JavaScript初心者でも迷わず、エラーもなく使えます。
簡単なサンプル2

[ フォーム以外の 超簡単な方法 ]
場合によっては有益な方法

■例 [ コピー ]

この文字列がコピーされます
spanタグに
onclick="if(clipboardData.setData('text',this.innerText)){ alert('コピーしました') }"
を付けました。
アラートが不要なら
onclick="clipboardData.setData('text',this.innerText)"
で良いですし、タグを含むSPAN内の文字列をコピーするなら
onclick="clipboardData.setData('text',this.innerHTML)"
とすれば可能です。

( この画像をクリック )
imgタグに
onclick="clipboardData.setData('text',this.src)"
を付けました。
この画像のSRCの値(URI文字列)がクリップボードにコピーされます。


このフォームをクリックしてから、画像をクリック。
上の画像をクリックしてから、下の画像をクリック。

この様にフォーム部品以外でもDOMで操作可能な場所を取り出してクリップボードに格納させたり、 クリップボードから取り出して貼り付け操作で交換する事も可能です。

が、同じページ内でデータをコピーさせて、どこかに貼り付けるのであれば これはIEだけで通用するクリップボードデータを使うよりも、JavaScriptで値を変数に格納しておいてから、 その値を変数参照で交換すれば良いだけですのでクリップボードを使うのは無駄な行為です。

ビジターにとってクリップボードに格納させる事が本当に一手間省けると言う場面でこそ使うべきで、 飾りとして使うような方法ではありません。
逆に『クリップボードへのアクセス許可』の問い合わせがでるので不信感を抱かせるだけです。

簡単なサンプル3

使いやすい clipboardData 方式
NN系のエラースルーをあてにせずにもう少し正しく。

■表示例 ボタンを表示させる方法
下記のソースをコピーしてください
IE系の場合のみボタンを表示させて、コピーしやすくさせます。


■この表示例のソース (そのまま使えます)

■使い方
同じページ内に複数このスクリプトを貼り付ける時はIDがかぶります。
ソース内に2箇所の「copy1」という文字列がありますので、 このソースを1つ増やすごとに copy2、copy3の様にIDを変えてください。

こんな感じでNNへの配慮などをしていけば良いでしょう。
下位ブラウザを考慮しない場合やBODY内にスクリプトを書きたくない場合は、 inputをdisplay:noneにしておくか、createElementなどで追加すれば良いでしょう。


簡単なサンプル4


IE以外の場合にもボタンを表示させままにしますが、
コピーができないブラウザでは内容をselect()状態にさせます。

コピー可能な場所をフォームエレメントのinputとtextareaとします。

■表示例

■ この表示例のソース <head>〜</head>に記述しておく関数

■ この表示例のソース コピー指示の場所 内用

■使い方
まずHEAD内用のスクリプトをそのままHEAD内に貼り付けてください。
これはフォーム部品専用の関数です。

次に コピーさせたい文字とボタンの部分を必要な場所に貼り付けます。
名前の部分が2箇所ありますので、 1箇所貼るごとにこの2箇所の名前を同じ名前にしてください。
TEXTAREA/INPUTタグどちらでも構いません。属性やスタイル、ボタンのValue部分などは自由に変更可能です。

onclick="DoCopy('名前',this.form,0)
この数字部分は アラートを使うか使わないかです。
0にしておけば『コピーしました』のアラートが出ません。
1にすると出ます。
ボタンがいらない場合はTEXTAREAやINPUTにイベントハンドラをつければOKです。

この方法だとクリップボードへのアクセスを拒否された場合や、でIE以外でも内容がselect()されるのでコピーしやすくなります。




■ ここからは、自分でもっとあれこれ工夫したい人への説明です。

clipboardData を使う方法


[ サンプル ]
clipboardData オブジェクトを利用して簡単なコーディングで実現可能
■このテキストエリアをクリックすると、コピーされます


■このテキストエリアをクリックすると、ペーストされます
ページの適当な文字列をコピーしてここをクリックしても可能。


■このボタンをクリックすると、クリップボードがクリアされます

[ 解 説 ]
clipboardDataと言うクリップボードを指すオブジェクトがあります。
これに対して setData()、getData()、clearData() と言うメソッドが使えます。

clipboardData クリップボードそのものを指すオブジェクト名
setData('text','文字列') クリップボードに文字列をコピーするメソッド
getData('text') クリップボードから文字データを取り出すメソッド
clearData() クリップボードを空(null)にするメソッド

'text'の部分はデータの型を指す固定だと思ってください。(変更不要)

■setData('text','文字列')

上段の左・右フォームには、それぞれ
onclick="clipboardData.setData('text',this.value)"
というイベントハンドラ(onclick)でJavascript起動にしてあります。

受け渡す文字列は this.value (テキストエリア内の文字列) の文字列です。 このthis.valueの部分は"文字列" の様に実際に文字を入れて、状況にあわせたクォーテーションで囲む事ももちろんできます。 長くなる場合などは関数内にコーディングとして書いておく、または隠しフォーム(CSSでdisplay:none状態)などに入れておくのが楽でしょう。

アンカーやinputボタン等にこのイベントを付けて、フォーム(または隠しフォーム)からデータを取り出すのであれば、 当然 this.value ではなく、javascript(この機能の場合Jscript等でもOK)のオブジェクト指定方法に従ってID等で明確にターゲットを指定をしっかりやってください。

■getData('text')

中段の貼り付け用フォームには
onclick="this.value = (clipboardData.getData('text') || '')"
というイベントハンドラ(onclick)でJavascript起動にしてあります。

これは clipboardDataがあればそれを、nullかundefinedなら ''と言う空文字と言う意味です。 クリップボードデータがあれば貼り付け、無ければフォームを空にすると言う事です。 this.value = clipboardData.getData('text') だけでも良いのですが、clipboardDataがnull値の場合Javascriptが nullと言うデータ評価文字を入れ込んでしまうので、それを防ぐ為です。
或いはクリップボードデータがが無いのなら貼り付けは行えないのは当然ですから空にするのではなく
if(clipboardData.getData('text')){ this.value= clipboardData.getData('text') }
でも良いと言えます。

■clearData()

下段のボタンには
onclick="clipboardData.clearData()
というイベントハンドラ(onclick)でJavascript起動にしてあります。

名前どおりclearしていて、null(何も無い状態)にしています。
データを完全に消す必要があればclearData()が便利ですが、Javascript評価でnullを入れたくない場合 onclick="clipboardData.setData('text','')
つまり何も無い空をコピーする事で、擬似的『空』状態にできます。
擬似的といっても 文字列状態で ''の物はJavascript内での評価でもnullとほぼ同等の動きをするので問題はありません。

この例の様に内容を可変的にできるフォーム内の文字列を取り出してコピーさせる事で、色々な使い道ができます。 フォーム自体は隠しフォームにしても良いですし、NN等の為に表示させても良いです。 CSSでボーダーを外して、overflowコントロールや、背景透過設定をすればフォームだと気づきにくくさせる事もできます。
逆に考えるとこのclipboardDataを「簡単に利用」する場合は、コピーさせる為の文字列はスクリプト内に書き込む文字列か、 フォームの様にプロパティで値を参照できるタグ内に書き込まれた文字列に限られてしまいます。 (innerHTMLやテキストレンジを使う事も可能です。最後に書きます)

もっとコーディングをしっかりやるには、
イベントから関数を呼び出す形にして、IE以外のブラウザやクリップボードコピーを拒否された場合を考えて、 Javascriptを起動させない、或いはfalseさせる、或いはコピーしやすいようにフォーム内の文字をワンクリックやマウスオーバーでselect()させてしまうなどの処理へ導くと良いでしょう。

execCommand() を使う方法


■このテキストエリアをクリックすると、コピーされます


■このテキストエリアをクリックすると、ペーストされます
ページの適当な文字列をコピーしてここをクリックしても可能。


■このボタンをクリックすると、クリップボードがクリアされます
削除された後は右クリックで「貼り付け」が無理になってるのがわかると思います。

[ 解 説 ]
IEの場合テキストレンジと言うページ内のテキストドキュメントをオブジェクト化する方法があります。 普通HTMLページは一度表示されると書換え不能ですが、IEの場合はテキストレンジを使う事で後からいくらでも書換えが可能です。 (このコピーとは関係なければIEでもNN6以降、FireFoxなどでも書換えは可能です)

このテキストレンジからターゲットの文字列(タグで囲まれたinnerHtmlやvalueプロパティを元々持っているフォームエレメント)を限定させて、execCommand()と言うメソッドの copy(cutも可能) や paste と言うコマンドで、クリップボードへコピーしたり取り出してペーストしたりできます。 直接innerHTMLを取り出す方法でも構いませんが、方法としてあると言う事です。

■ 呼び出している定義関数
この関数はそのままコピーして使いまわしできます。 コピーさせたいブロックタグのIDを引数として渡せばOKです。

<script language="javascript">

function DoCopy(arg){
    var doc = document.body.createTextRange();
    doc.moveToElementText(document.all(arg));
    doc.execCommand("copy");

}

function DoPaste(arg){
    var clip = document.body.createTextRange();
    clip.moveToElementText(document.all(arg));
    clip.execCommand("paste");
}

</script>


■上段のコピーする為のエリアは両方とも

DoCopy('sample10') DoCopy('sample11')の様に自分のIDを引数としてDoCopy()関数を呼び出しています。

DoCopy()関数の中で
var doc = document.body.createTextRange(); で、ボディ全体のテキストをオブジェクトとして取り出します。
この時の変数docは、あとで問題になりにくいように関数内だけのローカル変数にする為に わざわざ var をつけてローカル宣言しています。グローバル変数にしたい場合は varを取ってください。

doc.moveToElementText(document.all(arg)); そのオブジェクトの中で、IDの部分(そのIDのタグで囲まれているinnerHtml領域)だけ取り出しています。

doc.execCommand("copy"); execCommand()メソッドの copyコマンドでクリップボードに格納しています。
後でも書きますが、このコピーの部分は前の方法を使って
clipboradData.setData('text',doc.text);と言う、テキストレンジdocのtextプロパティをコピーさせる方法でも可能です。

この手順で、必要なテキストを取り出してテキストレンジにしてやるのが応用性が高い方法です。 valueプロパティを持つフォーム内のエレメントであれば
var text = document.all( id );
var doc = text.createTextRange();
これでも対象がフォームエレメンツならテキストレンジオブジェクトにできます。が、この方法だとプロパティで文字列を参照できるようなエレメントしか適用できません。 テキストレンジオブジェクトはフォーム部品以外の所からも文字列を取れるのが最大の魅力ですから、汎用性を高くしておく為にはベースをボディ全体から引き出した方が良いですし、 どんなケースにも同じコーディングを使いまわし可能なので便利です。
var doc = document.body.createTextRange();
doc.moveToElementText(document.all(id));
が良いです。

■中段のペースト為のエリアは

DoPaste1('sample12')の様に自分のIDを引数としてDoPaset()関数を呼び出しています。

var doc = document.body.createTextRange();
doc.moveToElementText(document.all(arg));
これでDoCopy()と同じように場所とテキストオブジェクトを特定しています。

clip.execCommand("paste"); execCommand()メソッドの pasetコマンドでクリップボードから取り出したもので、既にある文字列を上書きして貼り付けています。 この貼り付け方法は対象のテキストレンジを確定して、その文字を上書きすると言う方法であって、フォームエレメンツのvalueを入れ替える方法とは微妙に違います。 何が違うかと言うと、フォームエレメンツのような通常可変可能なHTML部品以外の場所も書き換えられると言う事になります。

何か文字をコピーしてからこのSPANエリアをクリック

■下段のクリアボタンは

DoCopy('sample13')として、コピーの形を取って存在しない文字をコピーする事で、ある意味エラーによりクリップボードのデータを消しています。 実際には存在時無い文字はテキストレンジ化する事は出来ないはずなので、軽いエラーを誘ってる形になるのかもしれません。


■その他:

execCommand()でのcopyやpasteは、テキストレンジに対して操作を行うメソッドであり、クリップボードに対して操作する物ではありません。 従って『クリア』と言うコマンドは実際は無いです。

execCommand()には cut というコマンドもあります。
これは、右クリックの動作と同じくコピーする際に元のテキストを消してしまう「切り抜き」と同じ物です。 cutの方が都合が良いのであれば、copyの代わりに cut を使う事でクリップボードに対しては同じ仕事をします。






それぞれの利点


2008.01 一部修正しています。innerHTML、innerTextを忘れていました。

既に一部書きましたが、clipboardDataオブジェクトを使う場合は、非常に簡単なメソッド(setData,getData)で行いやすい事で非常に使いやすい事が利点と言えます。 フォームなどの様にvalueプロパティを使って文字列を参照できる物にテキストを格納する場合などは、この方法が良いです。 それ以外の文字列を扱うのであれば、innerHTML、innerTextで取り出すか結局テキストレンジ化する必要があります。

■innerTextを使う
function DoCopy(arg){

    var txt = document.all(arg).innerText;
    var result = clipboardData.setData("text",txt);
    if(result){ alert('コピーしました'); }

}
innerTextで取り出せる文字列は、テキストレンジと同じくIDを指定すれば取り出すことが可能です。 この方法が単なるコピーを目的とするだけであれば、一番楽な方法で最も使いやすい方法だと思います。

テキストレンジで取り出せる文字はフォームエレメントに限らずドキュメント全体です。 例えば<span id="id">〜</span>や<div id="id">〜</div>の様に、 ページ内のブロックにIDを付けておく事でそのブロック内(innerHTML、innerTextと同等)に文字列を取り出す事が自在にできます。 innerHTMLで取り出す時は単なる文字列になりますが、テキストレンジにするとexecCommandなども使えて便利な面もあります。

また、これらのどちらかに拘る事無く、最も汎用性があるのがコレ
function DoCopy(arg){

    var doc = document.body.createTextRange();
    doc.moveToElementText(document.all(arg));
    var result = clipboardData.setData("text",doc.text);
    if(result){ alert('コピーしました'); }

}

この様に対象文字列をテキストレンジにしておき、テキストレンジdocのプロパティtextをオブジェクトから文字列化して setData()を使ってクリップボードに貼り付ける事もできます。 docはテキストレンジオブジェクトなのでdocを直接貼り付ける事はできませんので、doc.text という textプロパティを呼び出す必要があります。

『汎用性がある』と書いたのは
doc.execCommand("copy");の場合
result = doc.execCommand("copy");
としても、ユーザーがクリップボードへのアクセスを拒否してコピーができなくてもresult自体はtrue になってしまいます。 これはこの「式の評価」がtrueだからだと思います。
一方
clipboardData.setData("text",doc.text);の場合
result = clipboardData.setData("text",doc.text);
とすると、ユーザーがクリップボードへのアクセスを拒否した場合は resultにfalseが入ります。 従って、コピーができたかできなかったか?を判断できるので、 alert('コピーしました')で嘘無く結果を表示する事ができます。

alert()や結果をアナウンスしない場合はどうでも良いのですが、スクリプトのコーディング上で、 このクリップボードコピーをより活用するには、きちんとした戻り値を取れる方が使い出があります。

もっと省略して、さらにIEだけに有効になるようにすると
function DoCopy(arg){
  if(self.clipboardData && document.all){
    var doc = document.body.createTextRange();
    doc.moveToElementText(document.all(arg));
    if(clipboardData.setData("text",doc.text)){ alert('コピーしました'); }
  }
}


■テキストレンジを使った場合の汎用性 select()
innerHTMLやinnerTextでもSPANタグで囲まれたテキストなどは取れます。
テキストレンジで取った場合は、テキストレンジに用意されているメソッドなどを使う事ができます。

このテキストをクリックすると

ワンクリックで反転して選択された状態になります。
これは先ほどのソースに doc.select();を言う分を挿入しただけです。
テキストレンジにはselect()と言うメソッドが用意されていて、ドキュメント中のテキストを選択状態にできます。 だから?といわれると困りますが(^^ゞ、この様に汎用性があるのがテキストレンジです。

とりあえずコピーやペーストにはこのようにclipboardDataオブジェクトを使う方法と、 テキストレンジ化してexecCommand()を使う方法が存在しています。



専用ページから申し込むと
So-netより高い3万円CB

案ずるより産むが易し
使ってみれば疑問も解決

XREA+ (plus) 206円/月
( お試し7日間 )

CORE SERVER 428円/月
( お試し15日間 )

ロリポップ 270円/月
( お試し期間10日間 )

ヘテムル 1620円/月
( お試し期間15日間 )

さくら 129円/月
( お試し期間2週間 )

無駄な高額ドメイン管理料金払ってませんか?

バリュードメイン
ムームードメイン

お客さんに振込手数料を払わせていませんか?イーバンク銀行同士なら振込手数料無料。 オフィスで簡単振込み イーバンク銀行 ビジネス口座