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
用の値とイベントのやり取りだけ出すとすっきりしやすいです。