Vue.js③・コンポーネント
コンポーネントとは
コンポーネント はHTMLを構成する部品のことです.
Vue.jsでは,Vue.component()
を使ってコンポーネントを定義します.
コンポーネントには,複数のHTML要素をまとめたtemplate
オプション,データバインディングのためのdata
オプション,関数を定義するためのmethods
オプションなどを記述します.
コンポーネントとして定義することで,コンポーネントの再利用が可能となり,プログラムの設計が簡単になります.
また,props
オプションを利用することで,コンポーネントに任意のデータを渡すことが可能です.
今回は日進市の観光地を紹介するアプリを開発します.
観光地の情報や画像を表示するHTML要素をコンポーネントとして実装します.
CodePenの準備
CodePenにアクセスして,Penを作成し,タイトルを設定しましょう. Penのタイトルは「Chapter10」に設定しましょう.
前回と同様にVue.jsのライブラリをペンに追加してください. Vue.jsのバージョンは2.6.11を採用します.
また,Vue.jsの基本構造も記述しておきます.
Vueクラスのインスタンスには,el
,data
,methods
を指定します.
Webアプリのタイトルと説明文も記載しておきましょう.
<!-- HTML -->
<div id="app">
<h1> {{ title }} </h1>
<p> {{ description }} </p>
<div>
// JavaScript
let app = new Vue({
el: "#app",
data: {
title: "日進市観光アプリ",
description: "日進市の観光地を紹介するアプリです.",
},
methods: {
},
})
コンポーネントの作成
日進市の観光情報を表示するためのHTML要素を コンポーネント として定義します.
コンポーネントを定義するには,Vue.component()
を利用します.
コンポーネントには名前を付けることが可能で,ここではpanel-component
に設定しています.
コンポーネントには,template
オプションを記述します.
template
オプションでは,テンプレート文字列を利用して,コンポーネントで表示するHTMLを記述します.
ここでは,マスタッシュ記法を利用して,data
プロパティで定義したname
を表示しています.
この他にも,data
オプション,methods
オプションなどを定義することができます.
data
オプションで定義する変数は,return
を使って関数として定義する必要があることに注意してください(インスタンス間で変数の競合を避けるため).
// JavaScript
// templateオプションはテンプレート文字列(``)を使って定義
Vue.component("panel-component", {
template: `
<div class="panel">
<h3>{{ name }}</h3>
</div>
`,
data(){
return {
name: "日進市立図書館",
}
},
})
上記のtemplate
プロパティで記述したdiv
タグを装飾するためのpanelクラスのCSSを記述します.
幅(width),背景色(background),パディング(padding),マージン(margin),角丸(border-radius),中央寄せ(text-align)を設定しています.
/* CSS */
.panel{
width: 300px;
background: #DDFFDD;
padding: 10px;
margin: 10px;
border-radius: 20px;
text-align: center;
}
HTMLで上記で定義したコンポーネントを作成します.
コンポーネントの名前であるpanel-component
を要素名として記述するだけです.
template
プロパティで記述したHTML要素が表示されていることがわかります.
<!-- HTML -->
<div id="app">
<h1> {{ title }} </h1>
<p> {{ description }} </p>
<!-- コンポーネントの作成 -->
<panel-component></panel-component>
</div>
観光地の名前を表すname
だけでは寂しいので,観光地の写真image
と,観光地の説明文description
を追加します.
観光地の写真は,日進市オープンデータミュージアム・画像データサイトで提供されている画像を利用しました.
画像を表示するためのimgタグでは,v-bind
ディレクティブを利用してsrc
属性を設定しています.
// JavaScript
Vue.component("panel-component", {
template: `
<div class="panel">
<h3>{{ name }}</h3>
<p>
<img v-bind:src="image" height="200px">
</p>
<p>{{ description }}</p>
</div>
`,
data(){
return{
name: "日進市立図書館",
image: "https://assets.codepen.io/4660782/nissin-tosyokan.jpg",
description: "2008年に岡田新一設計事務所の設計による現行館が開館した."
}
},
})
キーポイント
- コンポーネントはVue.component()で定義
- templateプロパティで記述したHTML要素が表示される
propを利用したデータの引き渡し
コンポーネントとして定義することで,簡単に複数のコンポーネントを並べて表示することができます.
しかし,上記の方法では,name
,image
,description
がコンポーネント内で定義されているため,全く同じ内容のコンポーネントが複数表示されるだけです.
下記の例では,日進市立図書館のコンポーネントが2回表示されています.
<!-- HTML -->
<div id="app">
<h1> {{ title }} </h1>
<p> {{ description }} </p>
<!-- 複数のコンポーネントを作成 -->
<panel-component></panel-component>
<panel-component></panel-component>
</div>
コンポーネントごとに異なる情報を保持させるにはprops
オプションを利用します.
props
で定義された変数は,panel-component
タグの属性として,コンポーネントに渡すことができます.
このとき,{変数名: 型}
のように,変数の型を合わせて記述することが奨励されています.
今回はいずれも文字列String
として,変数のデータを受け取ります.
// JavaScript
Vue.component("panel-component", {
template: `
<div class="panel">
<h3>{{ name }}</h3>
<p>
<img v-bind:src="image" height="200px">
</p>
<p>{{ description }}</p>
</div>
`,
// propsで変数を受け取る
props: {
name: String,
image: String,
description: String,
}
})
HTMLでは,上記のprops
で定義した3つの変数を,属性として設定します.
このように,コンポーネントは共通の枠組みで,異なる情報を表示させることができます.
<!-- HTML -->
<div id="app">
<h1> {{ title }} </h1>
<p> {{ description }} </p>
<!-- 異なる情報を保持するコンポーネントを作成 -->
<panel-component name="日進市立図書館" image="https://assets.codepen.io/4660782/nissin-tosyokan.jpg" description="2008年に岡田新一設計事務所の設計による現行館が開館した."></panel-component>
<panel-component name="五色園" image="https://assets.codepen.io/4660782/goshikien.jpg" description="日本で唯一の宗教公園.浄土真宗系単立寺院の大安寺がある."></panel-component>
</div>
キーポイント
- コンポーネントで受け取りたい変数はpropsオプションで宣言
- HTMLタグの属性としてコンポーネントに変数のデータを渡す
繰り返しを利用したコンポーネントの作成
配列の要素を繰り返して取り出すことが可能なv-for
ディレクティブを利用して,
複数のコンポーネントを定義してみましょう.
まずは,Vue
クラスのdata
プロパティにpanels
を定義し,3箇所の観光情報(日進市立図書館,五色園,岩崎城)を配列として代入します.
// JavaScript
panels = [
{
"name": "日進市立図書館",
"image": "https://assets.codepen.io/4660782/nissin-tosyokan.jpg",
"description": "2008年に岡田新一設計事務所の設計による現行館が開館した."
},
{
"name": "五色園",
"image": "https://assets.codepen.io/4660782/goshikien.jpg",
"description": "日本で唯一の宗教公園.浄土真宗系単立寺院の大安寺がある."
},
{
"name": "岩崎城",
"image": "https://assets.codepen.io/4660782/iwasaki.jpg",
"description": "岩崎城は日進市の戦国時代の様子を今に伝える貴重な城址."
}
]
let app = new Vue({
el: "#app",
data: {
title: "日進市観光アプリ",
description: "日進市の観光地を紹介するアプリです.",
panels: panels,
},
methods: {
},
}
HTMLでは,v-for
ディレクティブを利用して,配列panels
から要素panel
を取り出し,
コンポーネントに,panel.name
,panel.image
,panel.description
を属性として渡しています.
ここでdisplay:flex
は,子要素を横並びで表示するためのCSSです.
この結果,3箇所の観光情報(日進市立図書館,五色園,岩崎城)が横並びで表示されます.
<!-- HTML -->
<div id="app">
<h1> {{ title }} </h1>
<p> {{ description }} </p>
<div style="display:flex">
<div v-for="(panel, index) in panels">
<panel-component v-bind:name="panel.name" v-bind:image="panel.image" v-bind:description="panel.description"></panel-component>
</div>
</div>
</div>
フォントアイコンを利用したページャー
ページャー とはウェブページのページを切り替える機能のことを指します. ここでは,全ての観光情報を表示するのではなく,1ページに1箇所の観光情報を表示させることにします. また,ボタンをクリックすることで,ページが切り替わるように実装します.
ページャーのアイコンには,ウェブフォントを利用することにします. ここでは,Font Awesomeというサービスを利用します. Pen SettingのCSSで,Font AwesomeのスタイルシートをCDNを追加しておきます.
表示するページを制限するために,v-ifディレクティブ
を利用して,
panelsの要素番号がnumber
とnumber+1
であるときだけ表示させています.
また,ページャーの役割を担う2種類のボタンを設置しています.
ボタンには,Font Awesomeを利用して,矢印形のフォントアイコン(fa-arrow-left
とfa-arrow-right
)を表示しています.
また,v-on
ディレクティブを利用して,ボタンのクリック時にprevPanel()
とnextPanel()
が呼び出されるように設定します.
<!-- HTML -->
<div id="app">
<h1> {{ title }} </h1>
<p> {{ description }} </p>
<div style="display:flex">
<div v-for="(panel, index) in panels">
<!-- v-ifディレクティブを利用して表示する観光情報を制限 -->
<panel-component v-if="(index == number)" v-bind:name="panel.name" v-bind:image="panel.image" v-bind:description="panel.description"></panel-component>
</div>
</div>
<div>
<!-- フォントアイコンを利用したページャー -->
<button v-on:click="prevPanel()"><i class="fas fa-arrow-left"></i></button>
{{ number+1 }}
<button v-on:click="nextPanel()"><i class="fas fa-arrow-right"></i></button>
</div>
</div>
JavaScriptでは,data
オプションでnumber
を宣言します.
また,methods
オプションで,nextPanel()
とprevPanel()
を定義します.
// JavaScript
let app = new Vue({
el: "#app",
data: {
title: "日進市観光アプリ",
description: "日進市の観光地を紹介するアプリです.",
panels: panels,
number: 0, // 表示するpanelsの要素番号
},
methods: {
nextPanel(){
// 番号を1だけ増やす
this.number = this.number + 1;
},
prevPanel(){
// 番号を1だけ減らす
this.number = this.number - 1;
}
},
})
キーポイント
- フォントアイコンはFont Awesomeが便利
アプリの確認
See the Pen Chapter10 課題 by Naoto Mukai (@nmukai) on CodePen.
課題
観光地のURLの情報を追加し,クリックしたら対応するページに遷移するリンクを設置してください.
課題を完成させたら,Penの ZIPファイル と リンク を提出してください. 提出方法は初回のWebアプリの開発を参考にしてください.