Vue単一ファイルコンポーネントを使用して再利用可能なコードブロックを作成する方法
著者は、 Write for DOnations プログラムの一環として、 Open Sourcing MentalIllnessを選択して寄付を受け取りました。
序章
Vue.js を使用してWebアプリケーションを作成する場合は、小さなモジュール式のコードブロックでアプリケーションを構築することをお勧めします。 これにより、アプリケーションの一部に焦点が当てられるだけでなく、複雑さが増すにつれてアプリケーションの更新が容易になります。 Vue CLI から生成されたアプリにはビルド手順が必要なため、シングルファイルコンポーネント(SFC)にアクセスして、アプリにモジュール性を導入できます。 SFCには.vue
拡張子があり、HTML <template>
、<script>
、および<style>
タグが含まれており、他のコンポーネントに実装できます。
SFCを使用すると、開発者は、コンポーネントごとに独自の HTML タグを作成し、それらをアプリケーションで使用することができます。 <p>
HTMLタグがブラウザで段落をレンダリングし、レンダリングされない機能も保持するのと同じように、コンポーネントタグはVueテンプレートに配置されている場所にSFCをレンダリングします。
このチュートリアルでは、SFCを作成し、props
を使用してデータを渡し、slots
を使用してタグ間にコンテンツを挿入します。 このチュートリアルを終了するまでに、SFCとは何か、およびコードの再利用性にアプローチする方法についての一般的な理解が得られます。
前提条件
- Node.jsバージョン
14.16.0
以降がコンピューターにインストールされています。 これをmacOSまたはUbuntu20.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはのPPAを使用したインストール]セクションの手順に従います。 Ubuntu20.04にNode.jsをインストールする方法 - Vue CLIがマシンにインストールされ、新しいプロジェクトが生成されました。 このチュートリアルではVue3Composition APIを使用しているため、アプリを生成するときに必ず
3.x (Preview)
オプションを選択してください。 このプロジェクトの名前はsfc-project
になり、ルートディレクトリとして機能します。 - また、JavaScript、HTML、およびCSSの基本的な知識も必要です。これは、 HTMLを使用してWebサイトを構築する方法シリーズ、CSSを使用してWebサイトを構築する方法シリーズにあります。 、およびJavaScriptでコーディングする方法。
ステップ1—プロジェクトの設定
このチュートリアルでは、一連のカードにいくつかの空港とそのコードを表示する空港カードコンポーネントを作成します。 前提条件のセクションに従うと、sfc-project
という名前の新しいVueプロジェクトが作成されます。 このセクションでは、この生成されたアプリケーションにデータをインポートします。 このデータは、ブラウザに情報を表示するために使用するいくつかのプロパティで構成されるオブジェクトの配列になります。
プロジェクトが生成されたら、ターミナルとcd
を開くか、ディレクトリをルートsrc
フォルダに変更します。
cd sfc-project/src
そこから、mkdir
コマンドを使用してdata
という名前の新しいディレクトリを作成し、touch
コマンドを使用してus-airports.js
という名前の新しいファイルを作成します。
mkdir data touch data/us-airports.js
選択したテキストエディタで、この新しいJavaScriptファイルを開き、次のローカルデータを追加します。
sfc-project / data / us-airports.js
export default [ { name: 'Cincinnati/Northern Kentucky International Airport', abbreviation: 'CVG', city: 'Hebron', state: 'KY' }, { name: 'Seattle-Tacoma International Airport', abbreviation: 'SEA', city: 'Seattle', state: 'WA' }, { name: 'Minneapolis-Saint Paul International Airport', abbreviation: 'MSP', city: 'Bloomington', state: 'MN' } ]
このデータは、米国内のいくつかの空港で構成されるオブジェクトの配列です。 これは、チュートリアルの後半で単一ファイルコンポーネントにレンダリングされます。
ファイルを保存して終了します。
次に、別の空港データのセットを作成します。 このデータはヨーロッパの空港で構成されます。 touch
コマンドを使用して、eu-airports.js
という名前の新しいJavaScriptファイルを作成します。
touch data/eu-airports.js
次に、ファイルを開き、次のデータを追加します。
sfc-project / data / eu-airports.js
export default [ { name: 'Paris-Charles de Gaulle Airport', abbreviation: 'CDG', city: 'Paris', state: 'Ile de France' }, { name: 'Flughafen München', abbreviation: 'MUC', city: 'Munich', state: 'Bavaria' }, { name: 'Fiumicino "Leonardo da Vinci" International Airport', abbreviation: 'FCO', city: 'Rome', state: 'Lazio' } ]
このデータセットは、それぞれフランス、ドイツ、イタリアのヨーロッパの空港に関するものです。
ファイルを保存して終了します。
次に、ルートディレクトリで、ターミナルで次のコマンドを実行して、ローカル開発サーバーで実行されているVueCLIアプリケーションを起動します。
npm run serve
これにより、localhost:8080
のブラウザでアプリケーションが開きます。 ポート番号は、マシンによって異なる場合があります。
ブラウザでアドレスにアクセスします。 次の起動画面が表示されます。
次に、新しいターミナルを起動し、src
フォルダにあるApp.vue
ファイルを開きます。 このファイルで、<template>
およびcomponents
セクションのimg
およびHelloWorld
タグと、<script>
。 App.vue
は次のようになります。
sfc-project / src / App.vue
<template> </template> <script> export default { name: 'App', } </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
その後、先ほど作成したus-airports.js
ファイルをインポートします。 このデータをリアクティブにして<template>
で使用できるようにするには、vue
からref関数をインポートする必要があります。 データをHTMLテンプレートで使用できるように、airport
参照を返す必要があります。
次の強調表示された行を追加します。
sfc-project / src / App.vue
<template> <div class="wrapper"> <div v-for="airport in airports" :key="airport.abbreviation" class="card"> <p>{{ airport.abbreviation }}</p> <p>{{ airport.name }}</p> <p>{{ airport.city }}, {{ airport.state }}</p> </div> </div> </template> <script> import { ref } from 'vue' import data from '@/data/us-airports.js' export default { name: 'App', setup() { const airports = ref(data) return { airports } } } </script> ...
このスニペットでは、データをインポートし、テンプレートの<div>
要素とv-forディレクティブを使用してレンダリングしました。
この時点で、データがインポートされ、App.vue
コンポーネントで使用できるようになります。 ただし、最初に、ユーザーがデータを読みやすくするためにスタイルを追加します。 この同じファイルで、<style>
タグに次のCSSを追加します。
sfc-project / src / App.vue
... <style> #app { ... } .wrapper { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-column-gap: 1rem; max-width: 960px; margin: 0 auto; } .card { border: 3px solid; border-radius: .5rem; padding: 1rem; margin-bottom: 1rem; } .card p:first-child { font-weight: bold; font-size: 2.5rem; margin: 1rem 0; } .card p:last-child { font-style: italic; font-size: .8rem; } </style>
この場合、 CSSグリッドを使用して、これらの空港コードのカードを3つのグリッドに構成しています。 このグリッドが.wrapper
クラスでどのように設定されているかに注目してください。 .card
クラスは、各空港コード、名前、および場所を含むカードまたはセクションです。 CSSの詳細については、CSSを使用してHTMLのスタイルを設定する方法をご覧ください。
ブラウザを開き、localhost:8080
に移動します。 空港コードと情報が記載されたカードがいくつかあります。
最初のアプリを設定したので、次のステップでデータを単一ファイルコンポーネントにリファクタリングできます。
ステップ2—単一ファイルコンポーネントの作成
VueCLIはWebpackを使用して、ブラウザーが読み取れるものにアプリを構築するため、アプリはプレーンJavaScriptの代わりにSFCまたは.vue
ファイルを使用できます。 これらのファイルは、スケーラブルで再利用可能なコードの小さなブロックを作成するための方法です。 1つのコンポーネントを変更すると、どこでも更新されます。
これらの.vue
コンポーネントは通常、<template>
、<script>
、および<style>
要素の3つで構成されます。 SFCコンポーネントは、スコープ付きまたはスコープなしスタイルのいずれかを持つことができます。 コンポーネントにスコープスタイルがある場合、<style>
タグ間のCSSは、同じファイル内の<template>
内のHTMLにのみ影響します。 コンポーネントにスコープ外のスタイルがある場合、CSSは親コンポーネントとその子に影響します。
プロジェクトが正常にセットアップされたら、これらの空港カードをAirportCards.vue
というコンポーネントに分割します。 現在のところ、App.vue
のHTMLはあまり再利用できません。 これを独自のコンポーネントに分割して、機能とビジュアルを維持しながら、他の場所からこのアプリにインポートできるようにします。
ターミナルで、components
ディレクトリに次の.vue
ファイルを作成します。
touch src/components/AirportCards.vue
テキストエディタでAiportCards.vue
コンポーネントを開きます。 コンポーネントを使用してコードのブロックを再利用する方法を説明するために、ほとんどのコードをApp.vue
ファイルからAirportCards.vue
コンポーネントに移動します。
sfc-project / src / components / AirportCards.vue
<template> <div class="wrapper"> <div v-for="airport in airports" :key="airport.abbreviation" class="card"> <p>{{ airport.abbreviation }}</p> <p>{{ airport.name }}</p> <p>{{ airport.city }}, {{ airport.state }}</p> </div> </div> </template> <script> import { ref } from 'vue' import data from '@/data/us-airports.js' export default { name: 'Airports', setup() { const airports = ref(data) return { airports } } } </script> <style scoped> .wrapper { display: grid; grid-template-columns: 1fr 1fr 1fr; grid-column-gap: 1rem; max-width: 960px; margin: 0 auto; } .card { border: 3px solid; border-radius: .5rem; padding: 1rem; margin-bottom: 1rem; } .card p:first-child { font-weight: bold; font-size: 2.5rem; margin: 1rem 0; } .card p:last-child { font-style: italic; font-size: .8rem; } </style>
ファイルを保存して閉じます。
次に、App.vue
ファイルを開きます。 これで、App.vue
コンポーネントをクリーンアップして、AirportCards.vue
をインポートできます。
sfc-project / src / App.vue
<template> <AirportCards /> </template> <script> import AirportCards from '@/components/Airports.vue' export default { name: 'App', components: { AirportCards } } </script> <style scoped> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
AirportCards
がスタンドアロンコンポーネントになったので、<p>
タグと同じように、<template>
HTMLに配置しました。
ブラウザでlocalhost:8080
を開いても、何も変わりません。 <AirportCards />
要素で新しいSFCをレンダリングしているため、同じ3つの空港カードが引き続き表示されます。
次に、この同じコンポーネントをテンプレートに再度追加して、コンポーネントの再利用性を示します。
/src/App.vue
<template> <AirportCards /> <airport-cards /> </template> ...
AirportCards.vue
のこの新しいインスタンスは、PascalCaseではなくkebab-caseを使用していることに気付くかもしれません。 コンポーネントを参照するとき、Vueはどのコンポーネントを使用するかを気にしません。 大文字の単語と文字はすべてハイフンで区切られ、小文字になります。 同じことが小道具にも当てはまります。これについては次のセクションで説明します。
注:使用するケースは個人の好み次第ですが、一貫性が重要です。 Vue.jsは、HTML標準に準拠しているため、kebab-caseの使用をお勧めします。
ブラウザを開き、localhost:8080
にアクセスします。 カードが複製されていることがわかります。
これにより、アプリにモジュール性が追加されますが、データは静的です。 カードの列は、同じ3つの空港を表示する場合に役立ちますが、データソースを変更するには、ハードコードされたデータを変更する必要があります。 次のステップでは、小道具を登録し、親から子コンポーネントにデータを渡すことによって、このコンポーネントをさらに拡張します。
ステップ3—小道具を活用してデータを渡す
前の手順では、us-airports.js
ファイルのデータから多数のカードをレンダリングするAirportCards.vue
コンポーネントを作成しました。 それに加えて、同じコンポーネント参照を2倍にして、<template>
にそのコンポーネントの別のインスタンスを追加することでコードを簡単に複製する方法を示しました。
ただし、データを静的なままにしておくと、将来的にデータを変更することが困難になります。 SFCを使用する場合、コンポーネントを関数と考えると役立ちます。 これらの関数は、引数(props)を受け取り、何か(HTML)を返すことができるコンポーネントです。 この場合、データをairportsパラメータに渡して、ダイナミックHTMLを返します。
テキストエディタでAirportCards.vue
コンポーネントを開きます。 現在、us-airports.js
ファイルからdata
をインポートしています。 このインポートステートメントと、<script>
タグのsetup
関数を削除します。
sfc-project / src / components / AirportCards.vue
... <script> export default { name: 'Airports', } </script> ...
ファイルを保存します。 この時点では、ブラウザには何も表示されません。
次に、小道具を定義して前に進みます。 この小道具には何でも名前を付けることができます。 入ってくるデータを説明し、それを名前に関連付けるだけです。
小道具を作成するには、コンポーネントにprops
プロパティを追加します。 この値は、一連のキーと値のペアです。 キーは小道具の名前であり、値はデータの説明です。 できるだけ多くの説明を提供することをお勧めします。
sfc-project / src / components / AirportCards.vue
... <script> export default { name: 'Airports', props: { airports: { type: Array, required: true } } } </script> ...
現在、AirportCard.vue
では、プロパティairports
は渡されるデータを参照しています。 ファイルを保存して終了します。
次に、テキストエディタでApp.vue
コンポーネントを開きます。 以前と同様に、us-airports.js
ファイルのimport
データとVueのimport
関数を使用して、HTMLテンプレートに反応するようにする必要があります。
sfc-project / src / App.vue
<template> <AirportCards :airports="usAirports" /> <airport-cards /> </template> <script> import { ref } from 'vue' import AirportCards from '@/components/Airports.vue' import usAirportData from '@/data/us-airports.js' export default { name: 'App', components: { AirportCards }, setup() { const usAirports = ref(usAirportData) return { usAirports } } } </script>
ブラウザを開いてlocalhost:8080
にアクセスすると、以前と同じ米国の空港が見つかります。
テンプレートには別のAirportCards.vue
インスタンスがあります。 そのコンポーネント内で小道具を定義したので、同じ構造の任意のデータを渡して、さまざまな空港からの多数のカードをレンダリングできます。 ここで、初期設定のeu-airports.js
ファイルが入ります。
App.vue
で、eu-airports.js
ファイルをインポートし、ref
関数でラップしてリアクティブにし、次のように返します。
/src/App.vue
<template> <AirportCards :airports="usAirports" /> <airport-cards :airports="euAirports" /> </template> <script> ... import usAirportData from '@/data/us-airports.js' import euAirportData from '@/data/eu-airports.js' export default { ... setup() { const usAirports = ref(usAirportData) const euAirports = ref(euAirportData) return { usAirports, euAirports } } } </script> ...
ブラウザを開き、localhost:8080
にアクセスします。 ヨーロッパの空港データは、米国の空港データの下に表示されます。
これで、別のデータセットを同じコンポーネントに正常に渡すことができました。 props
を使用すると、基本的にデータを新しい名前に再割り当てし、その新しい名前を使用して子コンポーネントのデータを参照します。
この時点で、このアプリケーションはより動的になり始めています。 しかし、これをさらに集中させて再利用できるようにするためにできることはまだ他にもあります。 Vue.jsでは、slotと呼ばれるものを使用できます。 次のステップでは、HTMLをプレースホルダーに挿入するデフォルトのslot
を使用してCard.vue
コンポーネントを作成します。
ステップ4—スロットを使用して一般的なカードコンポーネントを作成する
スロットは、特にそのコンポーネントのHTMLが類似しているかどうかわからない場合に、再利用可能なコンポーネントを作成するための優れた方法です。 前の手順では、異なるデータを使用して別のAirportCards.vue
インスタンスを作成しました。 その例では、HTMLはそれぞれ同じです。 これは、段落タグ付きのv-for
ループ内の<div>
です。
ターミナルを開き、touch
コマンドを使用して新しいファイルを作成します。 このファイルの名前はCard.vue
になります。
touch src/components/Card.vue
テキストエディタで、新しいCard.vue
コンポーネントを開きます。 AirportCards.vue
からCSSの一部を取得し、この新しいコンポーネントに追加します。
<style>
タグを作成し、次のCSSを追加します。
sfc-project / src / components / Card.vue
<style> .card { border: 3px solid; border-radius: .5rem; padding: 1rem; margin-bottom: 1rem; } </style>
次に、このコンポーネントのHTMLテンプレートを作成します。 <style>
タグの前に、次の<template>
タグを追加します。
sfc-project / src / components / Card.vue
<template> <div class="card"> </div> </template> ...
<div class="card">
の間に、<slot />
コンポーネントを追加します。 これは、Vueによって提供されるコンポーネントです。 このコンポーネントをインポートする必要はありません。 Vue.jsによってグローバルにインポートされます。
sfc-project / src / components / Card.vue
<template> <div class="card"> <slot /> </div> </template>
このslot
は、他の場所で参照されている場合にCard.vue
コンポーネントのタグの間にあるHTMLのプレースホルダーです。
ファイルを保存して終了します。
次に、AirportCards.vue
コンポーネントに戻ります。 まず、作成したばかりの新しいCard.vue
SFCをインポートします。
sfc-project / src / components / AirportCards.vue
... <script> import Card from '@/components/Card.vue' export default { name: 'Airports', props: { ... }, components: { Card } } </script> ...
あとは、<div>
を<card>
に置き換えるだけです。
/src/components/AirportCards.vue
<template> <div class="wrapper"> <card v-for="airport in airports" :key="airport.abbreviation"> <p>{{ airport.abbreviation }}</p> <p>{{ airport.name }}</p> <p>{{ airport.city }}, {{ airport.state }}</p> </card> </div> </template> ...
Card.vue
コンポーネントに<slot />
があるため、<card>
タグ間のHTMLがその場所に挿入され、カードに関連付けられているすべてのスタイルが保持されます。
ファイルを保存します。 localhost:8080
でブラウザを開くと、以前と同じカードが見つかります。 違いは、AirportCards.vue
がCard.vue
コンポーネントを参照するようになったことです。
スロットのパワーを表示するには、アプリケーションでApp.vue
コンポーネントを開き、Card.vue
コンポーネントをインポートします。
sfc-project / src / App.vue
... <script> ... import Card from '@/components/Card.vue' export default { ... components: { AirportCards, Card }, setup() { ... } } </script> ...
<template>
で、<airport-cards />
インスタンスの下に以下を追加します。
sfc-project / src / App.vue
<template> <AirportCards :airports="usAirports"/> <airport-cards :airports="euAirports" /> <card> <p>US Airports</p> <p>Total: {{ usAirports.length }}</p> </card> <card> <p>EU Airports</p> <p>Total: {{ euAirports.length }}</p> </card> </template> ...
ファイルを保存し、ブラウザでlocalhost:8080
にアクセスします。 ブラウザは、データセット内の空港の数を表示する追加の要素をレンダリングします。
<card />
タグ間のHTMLは完全に同じではありませんが、それでも汎用カードをレンダリングします。 スロットを活用する場合、この機能を使用して、さまざまな用途を持つ小さな再利用可能なコンポーネントを作成できます。
結論
このチュートリアルでは、単一ファイルコンポーネントを作成し、props
およびslots
を使用して再利用可能なコードブロックを作成しました。 このプロジェクトでは、多数の空港カードをレンダリングするAirportCards.vue
コンポーネントを作成しました。 次に、AirportCards.vue
コンポーネントを、デフォルトのスロットを持つCard.vue
コンポーネントに分割しました。
最終的には、動的で、さまざまな用途に使用できる多くのコンポーネントが作成されました。その一方で、コードは保守可能であり、DRYソフトウェアの原則に準拠しています。
Vueコンポーネントの詳細については、Vueドキュメントから準備することをお勧めします。 Vueのその他のチュートリアルについては、Vue.jsシリーズページを使用してWebサイトを開発する方法を確認してください。