クリップボードを操作するライブラリに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に渡したテキストがクリップボードにコピーされる。

解説

ZeroClipboardreadyaftercopyなど独自のイベントを持っているが、これは純粋なobjectになっている。acceptStatement: trueとして一つ一つ割り当てるのは不毛なので、自分でHTMLEventsを定義したイベントをextendして、v-onから使えるようにしている。v-onは単純に内部でエレメントのaddEventListenerを叩いているだけなので、これで十分動く。