Vue.js は JavaScript のフレームワークでコンポーネント単位での開発を容易にし、巨大な機能を持つページも比較的容易に開発できます。
新規機能の開発を楽にしたいので Vue.js を使いたい、という時がままありますが既存のプロジェクトには jQuery が組み込まれている時が少なくなく、既存の jQuery 込みのデザインを崩すことは好まれません。そこで Vue.js と jQuery を組み合わせコードの需要があります。
Vue.js と既存の jQuery の組み合わせで面倒なのは Vue.js が Vue.js の都合で自由に DOM を追加、削除することによって jQuery によるイベント指定がしょっちゅう外れ、初期化もうまくいかないことです。input 要素の拡張やアニメーションのライブラリは特にこれが顕著です。これを Vue.js のコンポーネント内に jQuery のライフサイクルを組み込むことで対策します。
例えば、次の様にできます。
クリックでソースコードを展開
<template> <input type="text" class="form-control calendar" /> </template> <script> /** * ↓を元にした jquery 1.8.3 + bootstrap-datepicker 1.5 を扱うためのコンポーネントです * @see https://github.com/ankurk91/vue-bootstrap-datetimepicker */ export default { name: "DatePicker", props: { value: { default: null, validator(value) { return ( value === null || value instanceof Date || typeof value === "string" || value instanceof String ); }, }, config: { type: Object, default: () => ({// datepicker のデフォルト設定 format: "yyyy/mm/dd", language: "ja", autoclose: true, clearBtn: true, orientation: "top auto", }), }, }, data() { return { dp: null, // DatePicker jqEl: null, // jQuery DOM Element }; }, watch: { /** * 外からの値の変化を監視して datepicker まで渡す * @param {mixed} newValue */ value(newValue) { this.dp && this.dp.setValue(newValue || null); }, /** * 外からの設定の変化を監視して datepicker まで渡す * @param {Object} newConfig */ config: { deep: true, handler(newConfig) { this.dp && this.dp.options(newConfig); }, }, }, mounted() { // 定義済みならば処理なし if (this.dp) { return; } this.jqEl = $(this.$el); // Vue内のルート要素をjQuery化して取得 this.jqEl.datepicker(this.config); // datepicker を初期化 this.dp = this.jqEl.data().datepicker; // datepicker を bind this.dp.setValue(this.value); // datepicker に初期値を代入 // 親コンポーネントの :input とこのコンポーネントの DatePicker の変化を紐づけ。主に v-model 用 this.jqEl.on("change", (event) => this.$emit("input", event.currentTarget.value) ); // 上に伝播させるイベントをまとめて登録 ["hide", "show", "change", "error", "update"].forEach((name) => { this.$el.addEventListener(name, (...args) => { this.$emit(name, ...args); }); }); }, /** * DatePicker, jQuery を掃除。 * Vueの管理外なので都度DatePickerを破壊する必要がある */ beforeDestroy() { if (this.dp) { this.dp.destroy(); this.dp = null; this.jqEl = null; } }, }; </script>
この様にすると次の様に簡単に jQuery 付きのコンポーネントを呼び出せます。
<DatePicker v-model="hoge_date" />
プログラムの内容を端的に言うと mounted 時に jQuery ライブラリによる初期化を行い、 beforeDestroy 時にリセットにします。そして何かイベントが起きた時に都度 jQuery と Vue.js の仲介をします。jQuery と Vue.js の間でアダプターパターンをする感じです。jQuery のことはコンポーネント内に任せて、外には Vue.js
用の値とイベントのやり取りだけ出すとすっきりしやすいです。