Vue.js

[Vue.js] template内で定数を簡単に使用したい


単一ファイルコンポーネントのtemplate構文内でJSの定数を使用したいことがよくある。色々対応方法はあると思うが、個人的に一番しっくり来る方法を考えてみた。

template内で定数を使いたい

例えばこんな定数を定義してあったとする。

📄 Colors.js

export default Object.freeze({
  Red: '#ff0000',
  Green: '#00ff00',
  Blue: '#0000ff',
});

これを <template> 内で使用したいという話。<script>内でimportしてもtemplate構文を解釈するコンテキストが異なるので、当然使用できない。何度かやっちゃった人はいるだろう。

よく見かける解

ネットでよくある解は、使用するコンポーネントのdataに定義しておくというもの。

<template>
<div :style="{color: Colors.Red}">
</div>
</template>

<script>
import Colors from 'Colors.js';
...
export default {
  data() {
    return {
      Colors: Colors,
    };
  },
  ...
};
</script>

これはこれで正しい。しかしColorsは定数でリアクティブである必要は全く無いのでdataに定義するのはどうかと思う。computedに変更しても本質的には同じである。

もうちょっとマシな方法

リアクティブである必要はないがvueインスタンス上に存在していてほしいのであれば、それはつまり this に定義を生やせばいいということになる。createdあたりでやってあげたらいいだろう。

<template>
<div :style="{color: Colors.Red}">
</div>
</template>

<script>
import Colors from 'Colors.js';
...
export default {
  created() {
    this.Colors = Colors;
  },
  ...
};
</script>

動作も問題ない。しかし面倒くさい。複数の定数を使用したかったら、createdの中身はかなり醜くなる。createdはコンポーネントの初期化処理を書く場所だ。定数を定義することはコンポーネントの初期化処理ではなく、仕方なくここでやってるだけなのである。そんなコードでcreatedを見づらくしたくない。もっとエレガントな方法はないだろうか?

私が思う最適解

さっきのcreatedの解をミックインで作ってあげたらいい。ポイントはミックスインをオブジェクトリテラルで定義するのではなくファクトリ関数にしてやること。ここではカッコよく ConstantsLoader と名付けてみた。(※この命名は良くない。要再考)

📄 ConstantsLoader.js

export default function (constants) {
  return {
    created: function () {
      for (const [key, value] of Object.entries(constants)) {
        this[key] = value;
      }
    },
  };
}

呼び出し側はこうだ。

<template>
<div :style="{color: Colors.Red}">
</div>
</template>

<script>
import ConstantsLoader from 'ConstantsLoader.js';
import Colors from 'Colors.js';
...
export default {
  mixins: [
    ConstantsLoader({ Colors }),
  ],
  ...
};
</script>

割とエレガントだと思う。定数を複数呼び出したい場合は ConstansLoader({ Colors, Shapes, Types }) などと並べられるので便利。使用する側のcreatedも汚れない。ちなみにES構文に慣れてない人は「なんじゃこの書き方?」と思うかもしれないが、これはvalueを省略する記法で、省略せずに書くと { Colors: Colors, Shapes: Shapes, Types: Types } となる。便利でしょ?

もちろん、thisを汚してしまうので、そこは使用上の注意である。this.$constants.Colors みたいな任意の名前空間に定義できるようにカスタマイズするのもいいだろう。(しかし<script>内と<template>内でアクセスする方法異なるのも気持ちが悪い話だが。)

ともあれ、今の所この方法が一番良さげと思っている。何かご意見等あれば遠慮なくコメント等いただければ👍

関連する記事


コメントする

メールアドレスが公開されることはありません。

CAPTCHA


このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください