Vue componentで気をつけるべきこと!

さてさて、このところLaravel関連の記事ばかりを投稿していることに気づいたんで、今回はこれもすでに私の開発環境には欠かせない存在のVueのお話です。

Vueには「Component」という、簡単に言うと「使いまわしができる独自のHTMLタグ」をつくることができる便利機能が備わっています。

例えば、以下のようにすると、Googleマップへのリンクに特化したHTMLタグを作成することができます。

Vue.component('google-map-link', {
    props: ['address'],
    template: '<a :href="mapUrl" v-text="address"></a>',
    computed: {
        mapUrl: function() {

            return 'https://maps.google.co.jp/maps/search/'+ encodeURIComponent(this.address);

        }
    }
});

これをHTMLタグとして使いたい場合は、こうします。

<google-map-link address="東京都墨田区押上1丁目1−2"></google-map-link>

実際の表示はこうなります。

もちろんVueで指定した要素内で実行しないといけいませんが、一回こういったコンポーネントを作っておくと、後からいくらでも使いまわしができるのでとても重宝しています。

何が問題なのか?

このようにVue componentを利用すると、開発の効率化が進むためできるだけ導入するように心がけているんですが、気をつけておかないとコンポーネントがうまく動作しない状況があります。

そのうちのひとつが「テーブル内でコンポーネントを使う」場合です。

例えば、以下のケースを見てみましょう。

new Vue({
    el: '#app',
    data: {
        names: [
            '桃太郎',
            '金太郎',
            'かぐや姫',
            '浦島太郎',
            '一寸法師'
        ]
    }
});

Vueの中に、変数としてnamesという名前の配列が入ったシンプルなコードです。

通常だと、以下のように「tdタグ」を使ったりして内容を表示するかと思います。

<table>
    <tr v-for="name in names">
        <td v-text="name"></td>
    </tr>
</table>

実行結果はこうなります。

うまく行かない例

では、次は通常の「tdタグ」ではなく、独自のコンポーネントを使ってやってみましょう。コンポーネント自体は、名前を表示するだけのシンプルな内容です。

Vue.component('name-td', {
    props: ['name'],
    template: '<td v-text="name"></td>'
});

もちろん、テーブルの一部として表示したいので、template内には「tdタグ」のみを配置します。

では、このコンポーネントを使ってさっきと同じように名前を表示してみましょう。

<!-- 間違った例 -->
<table>
    <tr v-for="name in names">
        <name-td :name="name"></name-td>
    </tr>
</table>

コメントにも書いてあるとおり、この例はうまく名前は表示されません。(画面に何も表示されません。)

うまくいく例

では、どうすればうまくいくかというと、Vueは解決策として「is」という専用の属性を提供しています。

使い方はこうなります。

<!-- 正しい例 -->
<table>
    <tr v-for="name in names">
        <td is="name-td" :name="name"></td>
    </tr>
</table>

「is」の中に表示したいコンポーネント名を入れるだけでOKです。
これでうまく表示することができるようになりました。

なぜうまくいかないのか??

では、なぜうまくいかないかを検証するために以下のようなもっとシンプルな例で見てみましょう。

<table>
    <tr>
        <name-td name="桃太郎"></name-td>
    </tr>
</table>

これを実行すると、実は「桃太郎」という文字は表示されます。

ただ、デベロッパーツールを使って表示コードを見てみるとこうなっています。

<td>桃太郎</td>
<table>
    <tbody>
        <tr></tr>
    </tbody>
</table>

本来あるべき「桃太郎」の「tdタグ」がテーブルの外にはじき出されてしまっています。

そうです。つまり「tableタグ」のように、

HTMLタグの中には「決められたタグ以外は無効にします」という制限がかかっているものがある

ために、うまく表示ができなくなってしまったのです。そのため、「is」属性を使った解決策でも「tdタグ」を使っていたというわけなんですね。

ちなみに、こういった制限を受けるのは以下の4つです。(どれも内部で決められたタグを使う構造になってますね)

  • ul
  • ol
  • table
  • select

ということで、今回は短いですがこんなところです。
ぜひ今後のVueを使った開発では気をつけておいてくださいね。

ではでは〜。