Vue.jsのカスタムディレクティブを付与した要素にDOMイベントのコールバックを指定する
Vue.jsのカスタムディレクティブのフック関数には
bind
ディレクティブが初めて対象の要素にひも付いた時inserted
ひも付いている要素が親 Node に挿入された時update
ひも付いた要素を抱合しているコンポーネントの VNode が更新される度componentUpdated
抱合しているコンポーネントの VNode と子コンポーネントの VNode が更新された後unbind
ディレクティブがひも付いている要素から取り除かれた時
があるけど、カスタムディレクティブを付与した要素でclick
とかのDOMのイベントが発火したときにコールバック関数を指定したい場合はどうするんだろう?って思ったら、
// `v-foo`というグローバルカスタムディレクティブを登録 Vue.directive('foo', { bind: (el, binding) => { el.addEventListener('click', onClick, false) } }) function onClick() { console.log('clicked') }
みたいに、bind
の中でel.addEventListener
を普通に指定すればよいだけだった。
addEventListenerのコールバック関数に引数を渡す
ちなみに、
<button v-foo="value"></button>
こんな感じにカスタムディレクティブを使うときに引数を渡して、その値をDOMイベントで使いたい場合は、addEventListener
のコールバック関数に引数を渡す必要があるから、
Vue.directive('foo', { bind: (el, binding) => { const {value} = binding el.addEventListener('click', () => onClick(value), false) } }) function onClick(value) { console.log(value) }
みたいに、第二引数を無名関数?にしたらできた。まぁこれは、Vue.jsは関係なくてただのJavaScriptの話だけど。
参考 :
Atomの自作packageのアップデート方法
以前作ったAtomのpackage(プラグイン)に、半年前にissueが立ってて、最近になって他の人からも+1が続いたので修正しようと思ったものの、packageの開発方法とか完全に忘れてて、どうしたらいいのか分からなくて困ったので未来の自分のために残す。
過去に自作のpackageをリリースしてる前提です。
開発環境の準備
まず、環境を準備するために、apm develop
コマンドを実行する。
$ apm develop <package-name>
次のようなログが流れる。
Cloning https://github.com/<user-name>/<package-name> ✓ Installing modules ✓ /Users/<user-name>/.atom/dev/packages/<package-name> -> /Users/<user-name>/github/<package-name>
apm develop
コマンドを実行すると、GitHubからソースコード一式をCloneしてくる~/.atom
にdev
ディレクトリが作られ、packages
内に該当のpackageのショートカットができる- Cloneしてきたコード一式は、
~/github
以下に保存される
(クローン先を変更したい場合はATOM_REPOS_HOME
で変更できるらしい)
リンクの確認
apm links
を実行して確認すると、次のようにpackageがローカルの開発環境にリンクされているを確認できる。
$ apm links
/Users/<user-name>/.atom/dev/packages (1) └── <package-name> -> /Users/<user-name>/github/<package-name> /Users/<user-name>/.atom/packages (0) └── (no links)
開発環境に移動しておく。
$ cd /Users/<user-name>/github/<package-name>
devモードでAtomを起動
Atomのメニューから、[View] - [Developer] - [Open In Dev Mode...] でdevモードでAtomを起動する。
devモードにするとAtomが~/.atom/dev/packages
を見てくれるようになるので、つまりそこからリンクされているローカルの開発環境を見てくれるようになる。
packageの中身を修正する
ソースコードをいじったら、Atomのメニューから、[View] - [Developer] - [Reload Window] でエディタ上に修正内容を反映できる。
GitHubにpushする
master
にpushすればよいはず。
publishする
$ apm publish <version-type>
version-type
の部分は修正内容に合わせて、major
かminor
かpatch
を指定する。それに合わせてpackage.jsonのバージョンが自動で書き替わるので。
もし、次のようなメッセージが表示されたら、https://atom.io/accountでログインして、API tokenをコピーしてターミナルに貼り付けてEnterすればOK。
Welcome to Atom! Before you can publish packages, you'll need an API token. Visit your account page on Atom.io https://atom.io/account, copy the token and paste it below when prompted. Press [Enter] to open your account page on Atom.io.
これで、新しいバージョンのpackageがユーザーに自動で届きます。めでたし🎉
Vue.js Tokyo v-meetup="#3" に参加してきました
申し込んだ時点で213/80人と絶望的だったのですが、たまたまブログ書く枠が空いたので勢いでポチってしまいました。ただ、私はVue.js初心者(※)なのでブログを書けるほど内容が理解できるのかかなり不安でしたが、結果的にどのトークも楽しめました(理解したとは言ってない)。なので、同じような初心者の方でも、興味があれば参加してみるとよいのではと思います。
(※)人がつくったアプリ(Vue 1.x)の改修をしたり、開発合宿でミニマムな評価アプリ(Vue 2.x)をギリギリつくった程度のレベルです。
以下、それぞれのトークの内容のメモです。
Vue.js の中身 - 算出プロパティはどうやって動いているか @kitak
https://kitak.github.io/slides/170316-vue-meetup/
Vue.jsのようなライブラリは生産性を高めてくれるけど、内部実装を理解しないで誤った使い方をすると、バグの原因やパフォーマンスの低下に繋がるからちゃんと理解しようねという話でした。私のことか。
算出プロパティ(computed
)は普通のメソッドと違って、依存プロパティの値が変わらない間はキャッシュしてくれるそう(知らなかった)。依存関係の追跡や状態変更の通知と再計算を実現するために、内部ではリアクティブプロパティやWatcherインスタンスが使われていること、またそれらはJavaScriptでどのように実装されているかを、温かみのある絵とともに解説してくれました。
Vuexを使ってみなかった話 @atsushiss15
Vuexを使わずに自前で簡易Fluxをつくる方法とかの話でした。
自前簡易Fluxをつくることになった経緯は、当初、状態管理やロジックを各コンポーネント内で書いていたけど、だんだんコンポーネント間で状態を共有する必要が出てきて、props
などでがんばったけど、密結合や複雑化していってしまい、何によって状態が変更したか分からない状況になってしまった。そこから、storeパターンを取り入れようということになったそう。
Vuexには「State」「Mutation」「Actions」があって、このうちの「State」「Actions」を自前実装して、Fluxアーキテクチャの「複数コンポーネントで状態共有」「Viewとデータロジックを分離」を実現。新しくつくるならVuexをつかう方がいいけど、学習コストを割かずにミニマムに実装するならこんな感じで自前実装もできる。ただし、自前の場合はVue.js devtoolsが使えないのがつらみ。
E2D3 の Vue.js 活用 @chimerast
E2D3はExcelのアドインで、Excel上でインタラクティブなチャートを生成したり、SVGに保存したりWebにシェアしたりできるそう。MacOffice 2016でもブラウザ上のOffice 365でも使えるらしい。
当初は、D3.jsとjQueryでがんばっていたのでしんどみがあったけど、Vue.jsで実装するようになってHTML上に構造ができるようになったので、拡張性が担保された。
Vue.jsはカジュアルにもガチにもつかえて便利なのでもっと使っていこうという話でした。
型付きテンプレートがほしい @ktsn
テンプレート内の変数名やコンポーネント名が間違っていたら、コンパイル時にターミナルにエラーが出るツールをつくったよという話でした。
実装は、VDOMにコンパイルしたテンプレートをTypeScriptにしてコンパイルして実現しているけれど、細々した調整が必要でその解説が主な内容でした。
まだ完成形ではなくて、現状の問題点としては、ソースコードが書き換わるのでエラーの箇所と行数がズレてしまうということと、vue-class-componentしか対応できないので、TypeScript 2.3を待ってるとのことでした。
VueでComponentをはじめました @kawakami_kazuyoshi
メトロノームのデモの解説と、使用したライブラリなどの紹介でした。
コンポーネントの単位は細かく分ける派だそう。たとえばボタンコンポーネントをひとつつくれば、色とアイコンを渡せばどこでも使いまわしができるから。
Vue.js with Go @k2wanko
ToDoのJavaScript部分をGoで書くデモとそのためのライブラリなどの話でした。Goへの愛を感じました。
- GopherJS
- GoをJSに変換するトランスパイラ
- GUIアプリケーションをブラウザにもってこれる
- go-vue
- GopherJSでVue.jsを書くためのバインディング
- go-loader
- WebpackのGoファイルローダー
結論として、VueをGoで書くのはつらい。
Vue.jsとFirebaseでSPA @buddy7
会社で超短期間で機能てんこ盛りのサービスをリリースすることになったけど、人員も足りないのでサーバーサイドはFirebaseにしてVue.jsで実装したという話でした。
でもサーバーからのメールが英語になってしまったり、Vuexを使わなかったのでデータフローがぐちゃぐちゃになってしまったなどの問題もまだ残っているそう。
その話と平行して、vue-cliでのプロジェクト作成から、Firebaseのデータを画面上に表示するところまでを、その場で5分くらいで実演していました。私も合宿で同じ構成でやったのですが、簡単で便利ですよね。
Nuxt.js @inouetakuya
SSRが必要なときに、Nuxt.jsのレールに乗るだけで、簡単にユニバーサルなVue.jsアプリを構築できるらしい。具体的には、Nuxt.jsには以下の機能が備わっているそう。
- サーバーサイドレンダリング
- ルーティング(vue-router)
- Vuex store
- 非同期データの取り扱い
- head要素の管理(vue-meta)
- Webpackと組み合わせてやることアレコレ
使い方も、vue init nuxt/starter
するだけ。あとは、pages
ディレクトリに*.vue
を置くだけでそれがそのままルーティングされる。すごい。
nuxt generate
というのは*.vue
を使った静的ファイルジェネレータで、静的ファイルができるのでGitHub Pagesなども利用できるようになる。
Nuxt.jsすごそう!
まとめ
全体を通しての感想は、「vue-cli便利」「Vuex使おう」でした。
ちなみに、参加者はほぼ男性で、女性は5人くらいだった気がしました。 それにヒヨって懇親会には参加できなかったのだけが心残りですが、Vue.jsへの愛も深まったし参加してよかったです。
スピーカーや運営のみなさまありがとうございました。
Python 3ではSimpleHTTPServerではなくhttp.serverを使う
以前、Pythonを使ってMacでローカルサーバーを簡単に立てる方法を書いたけど、
新しいMacBookではanyenvにして、(無駄に)Pythonもバージョン管理するようにしたら、SimpleHTTPServer
が使えなくてちょっとハマった。
原因は、Python 2にはあったSimpleHTTPServer
という標準ライブラリのモジュールが、Python 3ではhttp.server
というモジュールに統合されたからだった。
要するに、Python 2では
$ python -m SimpleHTTPServer [ポート番号]
としていたのを、Python 3では
$ python -m http.server [ポート番号]
にすればいいだけでした。
ありがとうStack Overflow。
タブを折り返して多段表示するAtomのプラグインをつくった
花金なので、multiline-tabっていうAtomのプラグインをつくりました🍻
Atomって開いてるタブが多くなると、タブ幅が小さくなりすぎてファイル名が読めない上に、エディタの幅に収まらないタブは横スクロールで画面外に消えてしまって使いづらすぎるので、タブ幅の最小値を大きくして、エディタの幅を超える場合はタブを折り返して表示するためのプラグインです。
もともと、開いているタブを縦に並べるプラグイン(👇)を使わせてもらっていたんだけど、
GitHub - 1000ch/atom-vtab: Verticalize tabs on Atom.
横並びのままで折り返したいなって思って、上記のコードをパク参考にさせてもらいました。ありがとうございます :bow:
やってることはCSSしか触ってないくらい簡単なんだけど、いろんなテーマで崩れないように調整するのが結構つらかったです。結局、あまりいじらないのがベストだってことになりました。
タブの幅はとりあえず固定になってるけど、本当は設定で自由に変更できるようにしたかったので、時間とれたら実装するかも。でもプルリクも待ってます。
最初はwrap-tabっていう名前だったんだけど、apm publish
が最初うまくできなくて、あれこれしてるうちにAPI tokenのキーをうっかり作り直してしまって、権限がなくなって削除もできなくなってしまって残骸になってしまったので、multiline-tabという別の名前に変えました。どうやって消そうかな。
jQuery.ajax()の代替としてFetch APIをざっくり使ってみる
jQueryを使わずにAjaxをしたくて、とはいえ生のXHR(XMLHttpRequest )を扱うのはめんどくさいっていうときに、Fetch APIを使ってみました。そのとき調べたことの覚え書きです。
Fetch APIって?
ここに、Jxck先生のすばらしい記事があります。
正直ぜんぜん理解できてないのですが(🙇)、ものすごくざっくりいうと、
みたいな感じなのかなと思いました。
ちなみに、先の記事では単なるXHRの代わりじゃないと記載されてるので、FetchとかFetch APIの理解にはそちらを読んでもらった方がいいかと思います。。
ブラウザサポート状況
Can I use... Support tables for HTML5, CSS3, etcを見る限り、IEとSafari、iOS Safari以外は対応してるみたいです。
私の場合はそれでもよかったので使ってないのですが、pollyfilもあるみたいです。
GET
次のような感じでGETができます。簡単!
fetch(url) .then(response => { return response.text(); }) .then(body => { document.body.innerHTML = body; });
先述したとおり、Fetch APIではPromiseが返ってくるため、then()
で繋げて書いていくことができます。
レスポンスは、以下のいずれかの形式で取得できます。
- プレーンテキスト :
response.text()
- JSON :
response.json()
- ArrayBuffer :
response.arrayBuffer()
- Blob :
response.blob()
POST
POSTする場合は、fetch()
の第二引数にオプションでmethod: 'POST'
を指定するだけです。$.ajax()
っぽい!
fetch(url, { method: 'POST', body: new FormData(document.getElementById('form')) }) .then(response => { return response.json(); }) .then(json => { ... });
サーバーに値を渡すには、body
オプションに指定できます。
クロスオリジン通信
オリジンが異なる(別ドメインの)サーバーと通信したい場合は、次のようにCORSを使います。
1. クライアント側で、fetch()
のmode
オプションに'cors'
を指定する
fetch(url, { mode: 'cors' }) .then(response => { ... });
2. サーバー側でリクエストヘッダのOrigin
をチェックする
GET /api HTTP/1.1 Origin: http://xxx.com
3. サーバー側でレスポンスヘッダにAccess-Control-Allow-Origin
を追加する
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://xxx.com
これで、クロスオリジン通信が可能になります。
Access-Control-Allow-Origin: *
のAPIの場合は1.の指定だけでできると思います。
Cookieを許可
Cookieを許可するには、次のように指定します。
1. クライアント側でfetch()
のcredentials
オプションに'include'
を指定する
fetch(url, { mode: 'cors', credentials: 'include' }) .then(response => { ... });
2. サーバー側でレスポンスヘッダにAccess-Control-Allow-Credentials: true
を追加する
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://xxx.com Access-Control-Allow-Credentials: true
独自のリクエストヘッダを追加
とあるAPIを利用するときに、独自のリクエストヘッダを追加して通信する必要がありました。その場合、次のように指定できます。
1. クライアント側でfetch()
のheaders
オプションに、オブジェクトの形式で独自ヘッダーを指定する
fetch(url, { method: 'GET', mode: 'cors', headers: { 'X-MyRequest': 'hoge' } }) .then(response => { ... });
2. サーバー側でプリフライトリクエストのリクエストヘッダを確認する
OPTIONS /api HTTP/1.1 Origin: http://xxx.com Access-Control-Request-Method: GET,POST,HEAD,OPTIONS Access-Control-Request-Headers: X-MyRequest
3. 許可する場合は、サーバー側からレスポンスヘッダを返す
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://xxx.com Access-Control-Allow-Methods: GET Access-Control-Allow-Headers: X-MyRequest
4. 実際のリクエストがクライアントからサーバーに送られる
サーバー側からAccess-Control-Allow-Methods
とAccess-Control-Allow-Headers
で許可されたものしか送れないという仕組みのようです。
独自のレスポンスヘッダを読み出す
まず最初に、ダメだった方法を。
1. サーバー側から独自のレスポンスヘッダを追加したレスポンスを返す
HTTP/1.1 200 OK X-MyResponse: hoge
2. クライアント側でresponse.headers.get()
にて取得しようとするもできない
fetch(url, { method: 'GET', mode: 'cors' }) .then(response => { console.log(response.headers.get('X-MyResponse')); });
この場合、セキュアではないヘッダにアクセスしようとしたと見なされてアクセスが許可されなかったようです。
なお、以下のヘッダには、問題なくアクセス可能です。
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
そのため、次のようにする必要があるようです。
1. サーバー側でアクセスを許可する独自ヘッダをAccess-Control-Expose-Headers
で指定する
HTTP/1.1 200 OK Access-Control-Allow-Origin: http://xxx.com Access-Control-Allow-Methods: GET,POST,HEAD,OPTIONS Access-Control-Allow-Headers: X-MyRequest Access-Control-Expose-Headers: X-MyResponse
2. クライアント側でresponse.headers.get()
にて取得する
fetch(url, { method: 'GET', mode: 'cors' }) .then(response => { console.log(response.headers.get('X-MyResponse')); });
サーバー側のエラーの処理
fetch()
では、サーバー側でエラーが起こってもレスポンスはreject()
されません。つまりcatch()
できないわけです。
では、どういう場合にreject()
されるのかというと、ネットワークエラーの場合のみのようです。そのため、サーバーエラーの処理は、then()
の中でresponse.ok
をチェックする必要があります。
fetch(url) .then(response => { if (!response.ok) { throw Error(response.statusText); } return response; }) .then(response => { ... }) .catch(err => { ... });
まとめ
jQuery.ajax()
が使えるときはそっちのが安心感あるけど、個人プロジェクトで少し触ってみる程度ならよいのかも?
※実際に使ってみたのは1年以上前だし、内容が古いかもしれないです。
package.jsonのnpmのバージョンを一括で書き変えてくれるncuが便利だった
npm-check-updatesというNode.jsのモジュールを使ってみたら便利でしたという話です。
2013年のブックマークとかもあったので、別に新しいものではないと思うけど、私は知らなくて感動したのでした。
なにこれ?
package.json
に書かれているnpmのバージョンを、一括で最新に書き変えてくれるNode.jsのモジュール。ncu
コマンドひとつで一度に書き変えできて便利。- 実際に書き変える前に確認だけすることもできる。
- 「メジャーバージョンは固定で、それ以下を最新にしたい」などの細かい設定もオプションで可能。
どんなときに便利なの?
- 既存の
package.json
を流用して、同じnpmをそのまま使いたいけど、バージョンだけは新しくしたいとき。 - 昔つくったサイトのメンテナンスで、npmのバージョンだけを新しくしたいとき。
使い方
初回のみ、npm-check-updatesをグローバルにインストールする必要があります。
$ npm install -g npm-check-updates
👆によって、ncu
コマンドが使えるようになるので、その後は、対象のpackage.json
のあるディレクトリに移動して、ncu
コマンドを実行するだけ。
確認と実行
どう書き変わるのかを確認する
ncu
コマンドだけだと、変更前と変更後のリストが表示されるだけで、package.json
はまだ書き替わらないので安心。
$ ncu express 4.12.x → 4.13.x multer ^0.1.8 → ^1.0.1 react-bootstrap ^0.22.6 → ^0.24.0 react-a11y ^0.1.1 → ^0.2.6 webpack ~1.9.10 → ~1.10.5
実際に書き変える
-u
オプションをつけることで、実際にpackage.json
が書き変えられる。
$ ncu -u
npmを個別に指定
特定のnpmのみをバージョンアップしたい場合は、対象のnpmの名前を指定するだけ。
$ ncu express, webpack
npmの名前の指定には、正規表現も使えて便利。
$ ncu '/^(?!gulp-).*$/'
バージョンを細かく指定
メジャーバージョンも含めて最新にする
デフォルトではメジャーバージョンも含めて最新になります。
$ ncu gulp-eslint 2.0.0 → 3.0.1
メジャーバージョンは固定、それ以下を最新に
--semverLevel major
オプションをつけることで、メジャーバージョンは固定で、それ以下を最新にできます。
メジャーバージョンアップをして、既存のコードが動かなくなるのを避けたい場合などに。
$ ncu --semverLevel major gulp-eslint 2.0.0 → 2.1.0
マイナーバージョンまで固定、それ以下を最新に
--semverLevel minor
オプションをつけることで、マイナーバージョンまでを固定して、それ以下を最新にできます。
$ ncu --semverLevel minor gulp-eslint 2.0.0 → 2.0.1
気の利くところ
既存のpackage.json
の記法を尊重して、アップデート後も同じように書き変えてくれて気が効くなと思いました。やさしさ。
$ ncu 1.2 → 1.3 0.1.0 → 0.2.1 ^1.2.0 → ^2.0.0 1.x → 2.x