見出し画像

(7) コンポーネントの属性 - デザイナー向けのVue.js紹介

「HTML/CSSはわかるけれど、JavaScriptは少し読んだことがあるくらい」というデザイナー向けの、Vue.js紹介記事です。
この記事では、コンポーネントに属性値を渡す方法を解説します。
連載をまとめたマガジンはこちら↓

コンポーネントの属性

前回作成したBaseButtonコンポーネントは、現段階ではまだリンクやボタンとして動作しません。BaseButtonコンポーネントにリンク先のURLクリック時のイベントなどを設定できるようにしていきましょう。

まずは、BaseButtonをリンクとして使用する方法を考えてみましょう。標準の<a>タグの場合、以下のようにしてリンク先URLなどを指定します。

<a href="./xxx.html" target="_blank">
  続きを読むリンク
</a>

今回は、BaseButtonコンポーネントでも同様にhref属性target属性が使えるようにしてみましょう。完成形は以下のような形になります。

<BaseButton href="./xxx.html" target="_blank">
  続きを読むボタン
</BaseButton>

コンポーネントへ渡した属性値の行方

前回作成したBaseButtonコンポーネントの中身は、スタイル付きの<a>タグでした。つまり、BaseButtonコンポーネントに指定されたhref属性やtarget属性が、そのまま中身の<a>タグに反映されれば、想定した動作が実現できます。

デフォルトで、コンポーネントへ渡した属性値は、templateのルート要素にそのまま渡されます。なので実は、BaseButtonに渡したhrefやtargetはすでに<a>に渡されていて、実際に動作します。(動作しているサンドボックス

これでは困る場合
一見すると、このデフォルト動作ですべてが上手くいくように見えますが……実は、この仕様では困る場合もあります。例えば、デザイン等の都合で、BaseButtonコンポーネントのルートに<span>を使うような場合を考えてみましょう。

画像1

このようなコンポーネントだと、BaseButtonに渡したhrefやtargetの属性値は、ルートのspan要素だけに渡されます。そのため、a要素には属性値が渡らず、リンクは動作しません。(動作していないサンドボックス

このような場合は、「コンポーネントに渡された属性を特定の要素に渡す」指定ができないと困ってしまいます。次はその方法を解説します。

属性値を渡す「v-bind」と「$attrs」

解説より先に、まず完成形を見てみます。(サンドボックスはこちら

画像2

BaseButtonのtemplateの<a>タグ内に、v-bind="$attrs"という見慣れない属性と値が追加されています。これが「コンポーネントに渡された属性をこの要素に渡す」という意味になります。なぜそうなるのか、ひとつずつ解説していきます。

$attrs

先に$attrsを解説します。"attrs"は英語のattributesの略で、attributeは「属性」です。つまりattrsは「属性の集合」を意味します。

Vueでは、$attrsは「コンポーネントに渡された属性の集合」です。例えば今回のBaseButtonコンポーネントの$attrsには、以下のようなデータが入っています。

{
  href: "https://note.com/noonworks/m/mb02c69d755ea",
  target: "_blank"
}

このデータは、JavaScriptのデータ形式です。といっても、「属性名:"属性値"」のペアが並んでいるだけなので、難しく考える必要はありません。

$attrsには、BaseButtonコンポーネントに渡した属性の集合がすべて入っています。つまり、この$attrsを<a>タグにそのまま渡すことができれば、目的の動作が実現できそうです。

v-bind

先ほどの動作するサンプルには、v-bindという見慣れない属性?がでてきました。

v-bindってどういう意味?
v-bindの頭の「v-」は「Vueの機能で~」という意味でつけられています。続くbindは「縛る、結ぶ」という意味の英語です。つまりv-bindは「Vueの機能で結びつける」というような意味になります。

ここで、サンプルのコードをもう一度見てみましょう。

画像3

<a>タグの中に、v-bind="$attrs"という記述があります。$attrsは先に説明した通り、「コンポーネントに渡された属性の集合」でした。

そしてv-bindは「Vueの機能で結びつける」という指示です。つまり、$attrsの属性集合データを、このタグ(<a>)に結び付けているのです。

(おまけ)独自の属性?
v-bindはVueの独自記法です。HTML標準の<a>タグにはv-bindという属性はありませんし、完成したHTMLファイルのソースを見ても、v-bindという属性はどこにもありません。v-bindは、ビルドや実行のときにVueの機能を使って標準のHTML記法に変換されているのです。
Vueにはv-bind以外にもいくつか独自属性のようなものがありますが、これらは「属性」そのものではなく、後々Vueの機能を使って変換される「指示」のようなものであるため、「ディレクティブ」と呼ばれています。(ディレクティブ directive は英語で「指示」という意味です。)

一部の属性だけを結びつける

v-bindには「一部の属性だけを結びつける」使い方もあります。

画像4

上の図では、以下の2つのテクニックを使用して、コンポーネントに渡された属性のうちhref属性だけを<a>タグに結びつけています。

v-bind:href という形にすると、href属性だけを結びつける
$attrs.href と書くと、$attrsの属性集合の中のhrefの値だけを取り出せる

この状態だと、<a>タグにはhref属性は渡されるがtarget属性は渡っていないので、ボタンを押したときに新しいタブではなく同じタブでリンクが開きます。(サンプルのサンドボックス

v-bindの省略記法

v-bindはよく使うので、省略記法が存在します。v-bind:href は v-bind を省略して、単に :href と書けます。(href以外の属性でも同じです。)

<a v-bind:href="$attrs.href">

<a :href="$attrs.href"> <!-- これは↑と同じ -->

第5回の「スタイルの閉じ込め② CSS Modules」で出てきた「:class」という表記も、「v-bind:class」の省略記法です。
当時は説明しませんでしたが、CSS Modulesを利用するために記述していた:class="$style.line" も、class属性に「$style.line」の値を結びつけていたのです。

今回のまとめ

・コンポーネントに渡した属性は、デフォルトではルート要素に渡される
・コンポーネントに渡した属性の集合は、$attrsに入っている
v-bindを使うと、属性に値を結びつけられる
・v-bindと$attrsを使って、コンポーネントに渡された属性と値を任意のタグに結び付けることができる
・「v-bind:属性名」を使うと、一部の属性だけを結びつけられる
・「v-bind:属性名」は「:属性名」と省略して書ける

-----------------------------

ここまでお読みいただきありがとうございました。次回は、コンポーネントに独自の属性を追加する方法を解説します。

-----------------------------

おまけ:練習課題

このサンプルのサンドボックスでは、<a>タグにhref属性が渡されるものの、target属性は渡されませんでした。

・target属性も<a>タグに渡されるように、v-bind:targetを追加してみましょう。
・v-bindを省略して書いてみましょう。

v-bind="$attrs"ですべて渡したときと、v-bind:href, v-bind:targetを使ってそれぞれを渡したときの違いを確認しましょう。

・App.vueを編集し、<BaseButton>に id="button1" を追加してみましょう。
・v-bind="$attrs"の場合は、idがどこに渡されるか予想しましょう。
・v-bind:href, v-bind:targetを使った場合は、idがどこに渡されるか予想しましょう。

おまけ:応用課題

v-bindを使って<a>タグに属性値を渡すことができましたが、それとは別に、<span>タグにも属性値が渡されています。

・ブラウザの開発者ツールを使って、spanにもaにもhrefとtargetが渡されていることを確認しましょう。

BaseButtonコンポーネントに以下の設定(12行目の「inheritAttrs: false」)を行うと、「コンポーネントに渡された属性をルート要素に渡す」デフォルト機能をオフにできます。

画像5

上記の設定を追加したサンプルで、ブラウザの開発者ツールを使って、spanにhrefとtargetが渡されなくなっていることを確認しましょう。

🐥はげみになります!