HTML5テクニカルノート
Vue.js + ES6: コンポーネントをラップする
- ID: FN1803003
- Technique: HTML5 / ECMAScript 2015
- Library: Vue.js 2.6.11 / jQuery 3.4.1
Vue.js公式サイトの「ラッパーコンポーネントの例」は、カスタムコンポーネントの中にjQueryプラグインSelect2をラップして用いています。本稿では、この作例を下敷きにして、コードをより簡潔に書き改めました。また、応用例も加えてあります。なお、使う構文はECMAScript 2015 (ECMAScript 6)です。
01 コンポーネントでjQueryプラグインSelect2のドロップダウンリストを使う
Select2はjQueryのプラグインで、<select>
要素のドロップダウンリストにさまざまな表現や機能が加えられます。HTMLドキュメントには、Vue.jsに加えて、jQueryとSelect2のライブラリおよびSelect2のCSSファイルもCDNから読み込んでおきます。なお、Select2の基本的な使い方については「jQuery: プラグインSelect2で<select>
要素のドロップダウンリストを操作する」をお読みください。
<link href="https://cdn.jsdelivr.net/npm/select2@4.0.12/dist/css/select2.min.css" rel="stylesheet" /> <script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/select2@4.0.12/dist/js/select2.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
Vue.jsのアプリケーションを組み込むのは<div>
要素で、id
属性(demo
)を与えておきます。つぎのコード001に<style>要素の定めも併せて掲げました。
コード001■要素<body>と<style>の定め
<body>要素
<div id="demo"></div>
html, body {
font: 13px/18px sans-serif;
}
select {
min-width: 300px;
}
VueアプリケーションのJavaScriptコードはつぎのとおりです。以下のテンプレートを定め、DOMの読み込みが済んだら(DOMContentLoaded
イベント)対象の要素にvm.$mount()
メソッドでアプリケーションを組み込みます。テンプレートには、このあと定めるコンポーネント(select2
)の要素が加えてあります。
JavaScriptコードテンプレートconst vm = new Vue({ template: '#demo-template' }); document.addEventListener('DOMContentLoaded', (event) => vm.$mount('#demo') );
<script type="text/x-template" id="demo-template"> <div> <select2> </select2> </div> </script>
コンポーネント(select2
)のJavaScriptコードとテンプレートは以下のとおりです。vm.$el
プロパティはVue
インスタンスのルートとなるDOM要素を参照します。そのjQueryセレクタに対してselect2()
メソッドを呼び出すことによりSelect2が初期化されるのです(「Basic usage」参照)。
JavaScriptコードテンプレートVue.component('select2', { template: '#select2-template', mounted() { $(this.$el) .select2(); } });
<script type="text/x-template" id="select2-template"> <select> <option value="0">Vue.js</option> <option value="1" selected>React.js</option> <option value="2">Angular</option> </select> </script>
これで、Select2のスタイルのドロップダウンリストがページに加わります(図001)。もっとも、アプリケーションとコンポーネントの間でとくにデータのやり取りはありません。ドロップダウンリストとしてのふるまいを見せるだけです。
図001■Select2のドロップダウンリスト
02 Select2で項目データからドロップダウンリストをつくる
Select2は、項目のデータから動的にリストがつくれます。データの配列(options
)を定めるのはアプリケーションのdata
プロパティで、要素とする項目データはオブジェクトです。
プロパティのid
は値、text
が項目名としてリストに示されます。データをコンポーネントに渡すには、テンプレートでその要素(selec
t2)にv-bind
ディレクティブ(省略記法:
)でバインディングしなければなりません。
JavaScriptコードテンプレートconst vm = new Vue({ template: '#demo-template', data: { options: [ {id: 0, text: 'Vue.js'}, {id: 1, text: 'React.js'}, {id: 2, text: 'Angular'} ] } });
<select2 :options="options"> </select2>
コンポーネントの側は、親からバインディングされたデータはprops
プロパティに加えて受け取ります。このとき公式「スタイルガイド」にしたがえば、プロパティのデータ型はきちんと定めなければなりません(「プロパティの定義」参照)。select2()
メソッドの引数オブジェクトにdata
プロパティとして項目データを与えれば、ドロップダウンリストに加えられるのです。
JavaScriptコードテンプレートVue.component('select2', { props: { options: Array }, mounted() { $(this.$el) .select2({data: this.options}); } });
<select> <!--<option value="0">Vue.js</option> <option value="1" selected>React.js</option> <option value="2">Angular</option>--> </select>
03 指定項目を予め選んでおく
コンポーネントのテンプレートで項目を定めていたときは、<option>
要素のselected
属性で予め選択する項目を決めていました。同じことをjQueryのコードでやってみましょう。選ぶ項目番号(selected)は、アプリケーションのdata
プロパティに与えておきます。そして、テンプレートでコンポーネント(select2
)のv-model
ディレクティブに定めるのは、ユーザーのドロップダウンリストの操作により値が変わるように(双方向バインディング)するためです。
JavaScriptコードテンプレートconst vm = new Vue({ data: { selected: 1, ] } });
<select2 :options="options" v-model="selected">
コンポーネントがアプリケーションのデータを受け取るには、props
に加えなければなりません。このとき、v-model
ディレクティブの値はプロパティをvalue
とするのがデフォルトです(「model」参照)。そして、jQueryセレクタに.val()
メソッドで値を渡せば、要素のvalue
プロパティが書き替わります。さらに、trigger()
メソッドの呼び出しにより、v-model
ディレクティブでバインディングされた値がコンポーネントに反映されるのです。
JavaScriptコードVue.component('select2', { props: { value: Number }, mounted() { $(this.$el) .val(this.value) .trigger('change'); } });
これで、ドロップダウンリストの項目はデータから動的に定め、予め選んでおく項目も決められました。ここまでのJavaScriptコードとテンプレートはつぎのコード002のとおりです。実際の動きは、CodePenに掲げた以下のサンプル001でお確かめください。
コード002■データから動的に加えたドロップダウンリストに初期選択の項目を定める
JavaSciptコード
Vue.component('select2', {
props: {
options: Array,
value: Number
},
template: '#select2-template',
mounted() {
$(this.$el)
.select2({data: this.options})
.val(this.value)
.trigger('change');
}
});
const vm = new Vue({
template: '#demo-template',
data: {
selected: 1,
options: [
{id: 0, text: 'Vue.js'},
{id: 1, text: 'React.js'},
{id: 2, text: 'Angular'}
]
}
});
document.addEventListener('DOMContentLoaded', (event) =>
vm.$mount('#demo')
);
<script type="text/x-template" id="demo-template">
<div>
<select2 :options="options" v-model="selected">
</select2>
</div>
</script>
<script type="text/x-template" id="select2-template">
<select>
</select>
</script>
サンプル001■Vue.js + ES6: Wrapper component using jQuery plugin Select2 base
See the Pen Vue.js + ES6: Wrapper component using jQuery plugin Select2 base by Fumio Nonaka (@FumioNonaka) on CodePen.
04 選ばれた項目の値を示す
ドロップダウンリストから選ばれた項目の番号は、ページに表示しましょう。まずは、アプリケーションのテンプレートに、項目番号(selected)をデータバインディングで差し込みます。
テンプレート<div> <p>Selected: {{selected}}</p> <select2 :options="options" v-model="selected"> </select2> </div>
つぎに、ドロップダウンリストの選択項目が変わったとき、コンポーネントの側からデータを改めます。ただし、親であるアプリケーションの値は直にはいじれません。vm.$emit()
メソッドでinput
イベントによりデータを送るのです(「コンポーネントで v-model を使う」)。これで、ドロップダウンリストから選んだ項目の番号がページに示されます(図002)。JavaScriptコードとテンプレートは、以下のコード003にまとめました。また、動作が確かめられるように、サンプル002をCodePenに掲げます。
JavaSciptコードVue.component('select2', { mounted() { $(this.$el) .on('change', (event) => this.$emit('input', parseInt(event.target.value, 10)) ) .trigger('change'); } });
図002■ドロップダウンリストから選んだ項目の番号が示される
コード003■ドロップダウンリストから選んだ項目の番号をページに示す
JavaSciptコード
Vue.component('select2', {
props: {
options: Array,
value: Number
},
template: '#select2-template',
mounted() {
$(this.$el)
.select2({data: this.options})
.val(this.value)
.on('change', (event) =>
this.$emit('input', parseInt(event.target.value, 10))
)
.trigger('change');
}
});
const vm = new Vue({
template: '#demo-template',
data: {
selected: 1,
options: [
{id: 0, text: 'Vue.js'},
{id: 1, text: 'React.js'},
{id: 2, text: 'Angular'}
]
}
});
document.addEventListener('DOMContentLoaded', (event) =>
vm.$mount('#demo')
);
<script type="text/x-template" id="demo-template">
<div>
<p>Selected: {{selected}}</p>
<select2 :options="options" v-model="selected">
</select2>
</div>
</script>
<script type="text/x-template" id="select2-template">
<select>
</select>
</script>
サンプル002■Vue.js + ES6: Wrapper component using jQuery plugin Select2
See the Pen Vue.js + ES6: Wrapper component using jQuery plugin Select2 by Fumio Nonaka (@FumioNonaka) on CodePen.
05 項目が複数選べるリストにする
応用例として、ドロップダウンリストから項目が複数選べるようにしましょう。コンボーネントのテンプレートで、<select>
要素にmultiple
属性を加えます。これでドロップダウンリストの動きだけは複数撰択リストになるものの、選ばれる番号のデータが複数扱えるようにはなっていません。
テンプレート<script type="text/x-template" id="select2-template"> <select multiple> </select> </script>
そこで、アプリケーションのdata
に定める撰択番号データは配列に変えます。そして、テンプレートに示す番号は、配列をカンマ区切りの文字列にすればよいでしょう。
JavaScriptコードテンプレートconst vm = new Vue({ data: { selected: [], // 1, } });
<!--<p>Selected: {{selected}}</p>--> <p>Selected: {{selected.join(', ')}}</p>
コンポーネントも、props
に定めた項目データを受け取るプロパティは型をArray
に変えなければなりません。そして、選ばれた項目オブジェクトの配列は、<select>
要素のjQueryセレクタに対してメソッドselect2('data')
を呼び出せば得られます(「Using the data method」参照)。オブジェクトの配列から番号を取り出して新たな配列にするのはArray.prototype.map()
メソッドです。なお、jQueryセレクタの参照は定数(select
)に納めました。
JavaScriptコードVue.component('select2', { props: { value: Array // Number }, mounted() { const select = $(this.$el); // $(this.$el) select .on('change', (event) => { const selecions = select.select2('data') .map((element) => parseInt(element.id, 10)); // this.$emit('input', parseInt(event.target.value, 10)) this.$emit('input', selecions); }) } });
これで複数項目の選べるドロップダウンリストで、撰択番号が示されるようになりました(図003)。JavaScriptコードとテンプレートは以下のコード004のとおりです。
図003■ドロップダウンリストから選んだ複数の項目番号が示される
コード004■複数項目の選べるドロップダウンリストで撰択番号をページに示す
JavaSciptコード
Vue.component('select2', {
props: {
options: Array,
value: Array
},
template: '#select2-template',
mounted() {
const select = $(this.$el);
select
.select2({data: this.options})
.val(this.value)
.on('change', (event) => {
const selecions = select.select2('data')
.map((element) => parseInt(element.id, 10));
this.$emit('input', selecions);
})
.trigger('change');
}
});
const vm = new Vue({
template: '#demo-template',
data: {
selected: [],
options: [
{id: 0, text: 'Vue.js'},
{id: 1, text: 'React.js'},
{id: 2, text: 'Angular'}
]
}
});
document.addEventListener('DOMContentLoaded', (event) =>
vm.$mount('#demo')
);
<script type="text/x-template" id="demo-template">
<div>
<p>Selected: {{selected.join(', ')}}</p>
<select2 :options="options" v-model="selected">
</select2>
</div>
</script>
<script type="text/x-template" id="select2-template">
<select multiple>
</select>
</script>
サンプル003■Vue.js + ES6: Wrapper component of multi-select dropdown list with Select2
See the Pen Vue.js + ES6: Wrapper component of multi-select dropdown list with Select2 by Fumio Nonaka (@FumioNonaka) on CodePen.
作成者: 野中文雄
更新日: 2019年12月15日 ライブラリを最新にし、本文の一部を補正。サンプルはCodePenに差し替えた。
作成日: 2018年03月15日
Copyright © 2001-2019 Fumio Nonaka. All rights reserved.