クリップボードを操作するライブラリにZeroClipboardというものがあり、ちょうどいい感じにVueのディレクティブでラップできたのでその知見。
swfファイルを読み込む
Vueを使うときはブラウザ上でもCommonJSに則って扱うことが多いが、幸いZeroClipboardもnpmにパッケージが公開されているのでrequire('zeroclipboard')で読み込むことができる。しかし何も設定せずに読み込もうとすると埋め込み用のswfファイルが見つからないと怒られてしまう。
なのでまずこのようにする。
(require 'zeroclipboard').config
swfPath: require 'file!zeroclipboard/dist/ZeroClipboard.swf'
WebPackを普通に使っている人なら入れているであろうが、file-loaderが必要になる。WebPackは静的ファイルもアセットとしてコンパイルの対象になり、コンパイル後は、ファイル名はハッシュ化されてWebPackの管理下に置かれる。なので、file-loaderでハッシュ化されたファイルへのURLをWebPackから引っ張ってきて、ZeroClipboardに渡してやると、適切なswfファイルを読み込んでくれるようになる。
ディレクティブでラップする
ZC = require 'zeroclipboard'
Vue.directive 'copy',
bind: ->
@client = new ZC @el
@emitWrappedEvent = (_ev)=>
ev = document.createEvent 'HTMLEvents'
ev.initEvent _ev.type
Vue.util.extend ev, _ev
@el.dispatchEvent ev
@client.on 'ready', @emitWrappedEvent
@client.on 'aftercopy', @emitWrappedEvent
update: (value)->
@el.setAttribute 'data-clipboard-text', value
<button v-copy="'コピーされるテキスト'" v-on="aftercopy: onCopied($event)">テキスト</button>
これでボタンをクリックするとv-copyに渡したテキストがクリップボードにコピーされる。
解説
ZeroClipboardはreadyやaftercopyなど独自のイベントを持っているが、これは純粋なobjectになっている。acceptStatement: trueとして一つ一つ割り当てるのは不毛なので、自分でHTMLEventsを定義したイベントをextendして、v-onから使えるようにしている。v-onは単純に内部でエレメントのaddEventListenerを叩いているだけなので、これで十分動く。