大ちゃんの駆け出し技術ブログ

RUNTEQ受講生のかわいいといわれるアウトプットブログ

【Vue】moment-js

moment-jsとは

こんにちは!大ちゃんの駆け出し技術ブログです。

この記事では日付フォーマットを変換するプラグインmoment-jsについて紹介します。自分のPF作成で使用したため忘れぬうちにアウトプットさせていただきます。

Moment.js | Home

今回自分がこのプラグインを使用した理由は、railsAPIで渡されるdatetimeの値のフォーマットを変更したいためです。

通常created_atupdated_atなどのdatetimeカラムは保存されると以下のようなフォーマットになるかと思います。

"created_at":"2019-04-21T00:00:00.000Z"

自分のPFでは誕生日と入社日というカラムをdatetimeで追加していたため、これをrailsサーバーからJSON形式で値を受け取ると同様のフォーマットで受け取っていました。これをvue.js側で表示すると、表示される画面は以下のようになります。

[該当コード]

<div>{{ profile.birthday }}</div>

[表示画面] (画質が荒く申し訳ございません。)

https://i.gyazo.com/52d169cae2423134ced35cbd5ed56f61.png

これを解消する方法としては2つあるかなと思いました。

  • バックエンド側でJSONの値を加工してフォーマットを整形する
  • フロント側で受け取ったJSONを加工してフォーマットを整形する

上記2つの違いはバックエンドがフロントエンドかということだけです。JSONの値のフォーマットを変更するという点では共通なので、処理内容は同じになるかと思います。

まずバックエンド側で整形する方法ですが、これは個人的に思ったのですが好ましくないのかなと思いました。理由としては、本来のサーバー側でレンダリングしているフォーマットはサーバー側で保存しているフォーマットと一致しているのが一般的だと思います。(enumは話が別になりますが、、、)。ですのでサーバー側で表示する誕生日のJSONの値だけフォーマットを部分的に変更するという仕様は違和感がありました。また、フロント側で値を加工することが多いので値自体の加工はフロント側で統一した方がいいのかなとも思いました。

ではフロント側で受け取った値を加工するというのはどうでしょうか。これはvuexgettersのように受け取った値を加工するという仕様があるため問題なさそうです。

computed: {
  doneTodosCount () {
    return this.$store.state.todos.filter(todo => todo.done).length
  }
}

ゲッター | Vuex

しかし、javascriptに慣れていないためか処理が冗長になると感じました。上記の例とは違い、プロフィール群の全てのプロフィールの誕生日の値のフォーマットを変更するという処理はかなり文が長くなることが予想されます。もっと簡単に処理できる方法はないのかと悩んでいました。

そこで今回使用するプラグインmoment-jsを使用することにしました。導入するとmoment-jsYYYY年/mm月/dd日というフォーマットに変更することができました。

インストール方法

railsを使用しているのでwebpackerに任せてインストールします。個人的にmoment-jsの他の記事はそのままのvue(vue-clii)での開発のパターンが多くyarnでインストールしている記事は見当たりませんでしたが、問題なく実装できますのでご安心ください。

$ yarn add moment
yarn add v1.22.10
[1/4] 🔍  Resolving packages...
[2/4] 🚚  Fetching packages...
[3/4] 🔗  Linking dependencies...
warning " > vue-loader@15.9.6" has unmet peer dependency "css-loader@*".
warning " > vue-loader@15.9.6" has unmet peer dependency "webpack@^3.0.0 || ^4.1.0 || ^5.0.0-0".
warning " > webpack-dev-server@3.11.2" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
warning "webpack-dev-server > webpack-dev-middleware@3.7.3" has unmet peer dependency "webpack@^4.0.0 || ^5.0.0".
[4/4] 🔨  Building fresh packages...
success Saved lockfile.
success Saved 1 new dependency.
info Direct dependencies
└─ moment@2.29.1
info All dependencies
└─ moment@2.29.1
✨  Done in 4.07s.

次にコンポーネント自体にインポートします。誕生日をフォーマットを変更して表示するページが今のところ1ページのみですので、今回はページのコンポーネントに直接インストールしました。

<script>
import moment from "moment";

export default {
};
</script>

次にexport defaulltの中にfiltersでフォーマットを指定します。

<script>
import moment from "moment";

export default {
    filters: {
      moment: function(date) {
        return moment(date).format("YYYY年/MM月/DD日");
      },
    }
};
</script>

filtersに関しては全く知らなかったのですが、どうやらmustacheなどで値のフォーマットや大文字小文字を加工する時などに使われているようです。公式にも記載がありました。

フィルター - Vue.js

format("YYYY年/MM月/DD日")の部分で好きなフォーマットを指定します。format("YYYY/MM/DD")といった年などを削除しても可能です。

これで準備は完了です。あとは以下のように変換したい日付 | momentmustacheの中に記載します。

[変更前]

<div>誕生日: {{ profile.birthday }}</div>

[変更後]

<div>誕生日: {{ profile.birthday | moment }}</div>

これにより値のフォーマットが意図したものに加工されました。

https://i.gyazo.com/3aa40700275edf95722ca4a0191bd60a.png

問題点

今回はあまりフォーマットの実装自体に時間をかけたくなかったのでmoment-jsで実装しましたが、今後こちらの実装で予想される問題点もあります。

例えば、誕生日カラムだけでなく、記念日というカラムを追加しようとした時に、そのページには2箇所のmomentの記載が必要です。

<div>誕生日: {{ profile.birthday | moment }}</div>
<div>誕生日: {{ profile.memorial | moment }}</div>

さらに増えると3箇所というふうにそのページでmomentを記載しなければならない箇所がどんどん増えていきます。それはかなり冗長に思えますので、それだったらvuexのgettersで一度に加工してしまった方が処理が冗長でも管理が楽なのかもしれません。それについてわかったらこちらの記事に追記したいと思います。

以上、大ちゃんの駆け出し技術ブログでした!