クリップボードを操作するライブラリに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
を叩いているだけなので、これで十分動く。