Vue.js カスタムディレクティブでクリップボードコピーを実装してみる
November 26, 2020
目次
カスタムディレクティブとは?
Vue.js 本体で出荷されたディレクティブの標準セットに加えて (v-model と v-show)、カスタムディレクティブ (custom directive) を登録することができます。Vue 2.0 では、コードの再利用と抽象化における基本の形はコンポーネントです。しかしながら、通常の要素で低レベル DOM にアクセスしなければならないケースがあるかもしれません。
まずディレクティブとは、描画されたDOMに特定のリアクティブな振舞いを与えるもの
v-
の接頭辞が付き、Vue.jsの標準セットではv-model
やv-if
・v-for
などが該当する
カスタムディレクティブとは、そのディレクティブを(v-xxx
)を自作して登録出来る仕組みのことである
クリップボードコピーを実装してみる
仕様ととしては
v-clip:[イベント名]="コピーする値"
で利用出来るように実装する- イベントはデフォルト
Click
イベントとする(v-clip="コピーする値"
)
e.g.
<button v-clip="message" /> //Click時にmessageがコピーされる
<input v-clip:focus="message" /> //フォーカス時にコピーされる
<input v-clip:change="message" /> //更新時にコピーされる
//script
message = "Hello!"
クリップボードにコピーするには?
クリップボード APIを使用することでクリップボードにコピーが可能
navigator.clipboard.writeText('コピーする値');
あとは、この処理をaddEventListener
に登録すればOK
directiveを書く
今回はサンプルでVue CLIで雛形生成してsrc/main.ts
に定義している
グローバル登録とする為、Vue.directive
関数を使用する
(※コンポーネント単位で登録も可能)
bind
フック関数を用いて実装
Vue.directive("clip", {
bind: (el, binding) => {
const event = binding.arg || "click";
el.addEventListener(event, () => {
navigator.clipboard.writeText(binding.value);
});
}
});
bind
フック関数について
bind: ディレクティブが初めて対象の要素にひも付いた時に 1 度だけ呼ばれます。ここで 1 回だけ実行するセットアップ処理を行えます 引用: arg: もしあれば、ディレクティブに渡される引数。例えば v-my-directive:foo では、arg は “foo” です。
ディレクティブフック引数(bind
の引数)について
- el: ディレクティブがひも付く要素。DOM を直接操作するために使用できます。
binding: 以下のプロパティを含んでいるオブジェクト。
- value: ディレクティブに渡される値。例えば v-my-directive=“1 + 1” では、value は 2 です。
- arg: もしあれば、ディレクティブに渡される引数。例えば v-my-directive:foo では、arg は “foo” です。
ここでのarg
は、イベントをとる形にしている。
v-clip:focus
であればfocus
がとれる。addEventListener
のイベントとして登録
これで描画してクリップボードにコピーすることが出来る
しかし、これだとコピーする値(data)が更新された時に対応が出来ず、初期値がコピーされる状態になってしまっている
update
フック関数を使い更新に対応する
Vue.directive("clip", {
bind: (el, binding) => {
const event = binding.arg || "click";
el.addEventListener(event, () => {
navigator.clipboard.writeText(binding.value);
});
},
// 以下追加
update: (el, binding) => {
const event = binding.arg || "click";
el.addEventListener(event, () => {
navigator.clipboard.writeText(binding.value);
});
}
});
update
フック関数の部分を追加
update: ひも付いた要素を抱合しているコンポーネントの VNode が更新される度に呼ばれます。しかし、おそらく子コンポーネントが更新される前でしょう。 ディレクティブの値が変化してもしなくても、バインディングされている値と以前の値との比較によって不要な更新を回避することができます。(フック引数に関しては下記を参照してください)
これでコピーする値が更新されてもちゃんと更新した値がクリップボードにコピーされる
これでもいいのだが、bind
とupdate
の内容が同一で冗長なのでいけていない
「関数による省略記法」を用いて省略する
directive
関数の第二引数に関数を渡すことでbind
・update
を省略することが可能
多くの場合、bind と update には同じ振舞いが欲しいでしょうが、その他のフックに関しては気にかけません。 カスタムディレクティブ — Vue.js
最終版
Vue.directive("clip", (el, binding) => {
const event = binding.arg || "click";
el.addEventListener(event, () => {
navigator.clipboard.writeText(binding.value);
});
});
まとめ
フック関数やディレクティブフック引数を把握しないといけないが、
簡単にクリップボードコピーのカスタムディレクティブの実装出来たと思う。
他にも何か作ってみたい。