🔖

Vue でテンプレートとロジックを切り分ける | Vue3

に公開

概要

Vue でウェブアプリケーションを作っているときに、<script>(ロジック)の部分は違うんだけど、<template>(テンプレート)の部分は一緒、ということがあった。そこで、テンプレートとロジックを切り分けて、テンプレートは一つのファイルで使いまわして、ロジックは個々のファイルで管理できるよう構造を考えた。コンポーネントを使えばいいようなものだが、そうすると、テンプレート部分が全てコンポーネントに行ってしまう。テンプレートでは、いくつかのコンポーネントをすでに使用しており、もしテンプレートをコンポーネントにしてしまうと、コンポーネントからコンポーネントを呼び出す形になってしまい、管理が複雑になってしまうと思った。だから、今回はその手段を使わなかった。

環境

  • Vue CLI で作った環境
  • Vue3(Options API)
  • Vuex4

構造

不要な部分は省略。

root/
├ views/
│  ├ LayoutView.vue
│  └ ChildrenView.vue
├ store/
├  └ index.js
└ App.vue ← 今回は関係ない

コード

Views 系

以下は、テンプレートを保持する Vue ファイル。一つだけ作成する。

LayoutView.vue
<template>
    <div>
        <!-- ここで共通のレイアウト(テンプレート)を設定する -->
        <p>{{ $store.getters.getMessage }}</p>
        <!-- 以下は必須(無いと、子のスクリプトが機能しない) -->
        <router-view />
    </div>
</template>
<style>
/* ここで様々なスタイルを設定する */
p {
    font-weight: bold;
}
</style>

以下は、ロジックを保持する Vue ファイル。これを複数個作ることで、共通のテンプレートを持つアプリケーションを作成できる。

ChildrenView.vue
// 以下は必須(無いと、Vueから警告が出る)
<template></template>

<script>
// ここで様々なロジックを設定する
export default {
    name: 'ChildrenView',
    mounted() {
        this.$store.commit('setMessage', 'Hello from ChildrenView');
    },
};
</script>

Store 系

以下は Vuex のルートファイル。LayoutView と ChildrenView 間の変数のやり取りは Vuex を介して行う。

index.js
import { createStore } from 'vuex';
const store = createStore({
    state() {
        return {
            message: 'No Message',
        };
    },
    getters: {
        getMessage: (state) => state.message,
    },
    mutations: {
        setMessage: (state, msg) => {
            state.message = msg;
        },
    },
});

Discussion