サイトトップ

Director Flash 書籍 業務内容 プロフィール

HTML5テクニカルノート

Vue.js + ES6: コンポーネントをラップする


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>

<style>要素

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のドロップダウンリスト

図001

02 Select2で項目データからドロップダウンリストをつくる

Select2は、項目のデータから動的にリストがつくれます。データの配列(options)を定めるのはアプリケーションのdataプロパティで、要素とする項目データはオブジェクトです。 プロパティのidは値、textが項目名としてリストに示されます。データをコンポーネントに渡すには、テンプレートでその要素(select2)に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■ドロップダウンリストから選んだ項目の番号が示される

図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■ドロップダウンリストから選んだ複数の項目番号が示される

図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.