Skip to content

Vue

Vue は、ユーザーインターフェースを構築するための JavaScript フレームワークです。標準の HTML、CSS、JavaScript を基礎にし、宣言的でコンポーネント化されたプログラミングモデルを提供します。これにより、効率よく UI を開発できます。

スキャフォールド

スキャフォールドの作成

まず、最新版の Node.js がインストールされていることを確認します。

次のコマンドを入力します。

shell
npm create vue@latest

次の内容が表示されます。

✔ Project name: … your-project-name ✔ Add TypeScript? … No / Yes ✔ Add JSX Support? … No / Yes ✔ Add Vue Router for Single Page Application development? … No / Yes ✔ Add Pinia for state management? … No / Yes ✔ Add Vitest for Unit testing? … No / Yes ✔ Add an End-to-End Testing Solution? … No / Cypress / Nightwatch / Playwright ✔ Add ESLint for code quality? … No / Yes ✔ Add Prettier for code formatting? … No / Yes ✔ Add Vue DevTools 7 extension for debugging? (experimental) … No / Yes

Scaffolding project in ./your-project-name... Done.

shell
cd your-project-name
npm install
npm run dev

プロジェクト構造

次は Vue CLI で作成した Vue プロジェクトの標準的な構造です。

plaintext
プロジェクトルート
├── node_modules/         // 依存モジュール(自動生成)
├── public/
│   ├── favicon.ico       // サイトアイコン
│   └── index.html        // プロジェクトのメインページテンプレート。Vue アプリの HTML 基礎で、id="app" の DOM 要素が Vue アプリのマウント先
├── src/
│   ├── assets/          // 画像、スタイルシート、フォントなどの静的リソース
│   ├── components/      // Vue コンポーネントを保存し、コード再利用性を高める
│   ├── App.vue           // Vue アプリのルートコンポーネント。UI 構造の最上位にあり、他のコンポーネントはここにネストされる
│   └── main.js           // プロジェクトのエントリーファイル。Vue アプリインスタンスを作成し、グローバルプラグインなどを設定して、index.html の指定要素へマウントする
├── .gitignore            
├── babel.config.js       // 構文変換ツール。新しい JS API を低いバージョンのブラウザでも動くコードへ変換する
├── package.json          // プロジェクト設定と依存宣言ファイル。依存、スクリプトコマンドなどを記録する
├── README.md             
└── vue.config.js         // CLI 設定ファイル。パスエイリアス、プロキシサーバー、ビルド最適化などを設定できる

テンプレート構文

テキスト補間

もっとも基本的なデータバインディングはテキスト補間です。「Mustache」構文、つまり二重波括弧を使います。

vue
<template>
    <span>Message: {{ msg }}</span>
</template>
<script>
export default {
    data() {
        return {
            msg: "こんにちは"
        }
    }
}
</script>

二重波括弧タグは、対応するコンポーネントインスタンスmsg 属性値に置き換えられます。また、msg 属性が変わるたびに同期して更新されます。

v-model データバインディング(双方向バインディング)

v-model ディレクティブは主にフォーム要素で使い、データの双方向バインディングを実現します。つまり、ユーザーがフォームに入力または選択した値は Vue インスタンスのデータへリアルタイムに反映され、データの変化もフォームへ反映されます。

html
<div>
  <input type="text" v-model="password">
  {{ password }}
</div>

Vue インスタンスの datapassword 変数を定義します。例:data: { password: '' }。ユーザーが入力欄に入力した内容は、下の補間式にも同時に表示されます。

原理v-model は本質的にシンタックスシュガーです。input 要素では、input イベント発生時にデータを更新し、value 属性にデータをバインドします。

v-if、v-else、v-else-if

v-if ディレクティブは、式の値に応じて要素を条件付きでレンダリングします。式の値が true なら要素は DOM にレンダリングされ、false なら DOM に現れません。

html
<div v-if="showElement">表示する要素</div>

v-else ディレクティブは、必ず v-if または v-else-if の直後に置き、別の条件分岐を提供します。

html
<div v-if="isTrue">条件が真の時に表示</div>
<div v-else>条件が偽の時に表示</div>

v-else-if は複数の条件分岐を追加するために使います。

html
<div v-if="score >= 90">優秀</div>
<div v-else-if="score >= 80">良好</div>
<div v-else-if="score >= 60">合格</div>
<div v-else>不合格</div>

注意v-if は本当の条件レンダリングです。切り替え時に、要素とその子要素を破棄または再作成します。

v-bind 属性バインディング

v-bind ディレクティブは要素の属性をバインドします。よく使う属性は hrefsrcclassstyle などです。

html
<a v-bind:href="href">検索する</a>

Vue インスタンスの datahref 変数を定義します。例:data: { href: 'https://www.example.com' }。すると、a タグの href 属性は指定したリンクになります。

v-bind: と省略できます。

html
<a :href="href">検索する</a>

v-on: クリックイベント

v-on ディレクティブは clickmouseenterkeyup などの DOM イベントをバインドします。イベントが発生すると、バインドされたメソッドを実行します。

html
<button v-on:click="functionName">閉じる</button>

Vue インスタンスの methodsfunctionName メソッドを定義します。

javascript
methods: {
  functionName() {
    // ボタンクリック時に実行する処理を書く
    console.log('ボタンがクリックされました');
  }
}

v-on@ と省略できます。

html
<button @click="functionName">閉じる</button>

v-for

v-for ディレクティブは、配列またはオブジェクトをもとに複数の要素をレンダリングします。配列またはオブジェクトのプロパティを反復し、各要素にテンプレートをレンダリングします。

配列に基づく反復

html
<div v-for="item in students" :key="item">{{ item.name }}</div>

Vue インスタンスの datastudents 配列を定義します。

javascript
data: {
  students: [{name: '張三さん'},{name: '李四さん'},{name: '王五さん'}]
}

上のコードは、students 配列内の各オブジェクトに対して div 要素をレンダリングし、学生名を表示します。

v-for は配列要素のインデックスも同時に取得できます。

html
<div v-for="(item, index) in usernames" :key="index">{{index+1 + '==>' + item}}</div>

Vue インスタンスの datausernames 配列を定義します。

javascript
data: {
  usernames: ['張三','李四','王五']
}

上のコードは、各 div に要素の番号と値を表示します。

オブジェクトに基づく反復

html
<div v-for="(value, key) in userInfo">
  {{ key }}: {{ value }}
</div>

Vue インスタンスの datauserInfo オブジェクトを定義します。

javascript
data: {
  userInfo: { name: '小明', age: 20, city: '北京' }
}

上のコードは、userInfo オブジェクトの各プロパティに対して div 要素をレンダリングし、プロパティ名と値を表示します。

注意v-for を使う時は、各要素に一意の :key 属性を与えることが重要です。Vue が DOM を効率よく更新でき、性能が上がります。

ルーティング(Vue Router)

Vue Router は Vue.js 公式のルーティングマネージャーです。次は一つの例です。

javascript
import Vue from 'vue';
import VueRouter from 'vue-router';
import Home from './views/Home.vue';
import About from './views/About.vue';

Vue.use(VueRouter);

const routes = [
    {
        path: '/',
        name: 'Home',
        component: Home
    },
    {
        path: '/about',
        name: 'About',
        component: About
    }
];

const router = new VueRouter({
    routes
});

new Vue({
    router,
    render: h => h(App)
}).$mount('#app');

テンプレートでルートリンクを使います。

html
<router - link to="/">Home</router - link>
<router - link to="/about">About</router - link>
<router - view></router - view>

ルートナビゲーションガード

ルートナビゲーションガードを使うと、ルートへのアクセス権などを制御できます。例:グローバル前置ガード。

javascript
router.beforeEach((to, from, next) => {
    // ユーザーがログインしているか確認
    const isLoggedIn = localStorage.getItem('isLoggedIn');
    if (to.meta.requiresAuth &&!isLoggedIn) {
        next('/login');
    } else {
        next();
    }
});

状態管理(Vuex)

コア概念

  • state:アプリの状態です。コンポーネントの data に似ています。
  • mutationsstate を変更できる唯一の場所です。同期関数でなければなりません。
  • actions:任意の非同期処理を含められます。mutations をコミットして state を変更します。
  • getters:算出プロパティに似ており、state 内のデータを取得します。

簡単な例

javascript
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {
        increment(state) {
            state.count++;
        }
    },
    actions: {
        incrementAsync({ commit }) {
            setTimeout(() => {
                commit('increment');
            }, 1000);
        }
    },
    getters: {
        getCount(state) {
            return state.count;
        }
    }
});

export default store;

コンポーネントで使います。

javascript
export default {
    computed: {
        count() {
            return this.$store.getters.getCount;
        }
    },
    methods: {
        increment() {
            this.$store.commit('increment');
        },
        incrementAsync() {
            this.$store.dispatch('incrementAsync');
        }
    }
};

ライフサイクルフック

Vue インスタンスには複数のライフサイクルフック関数があり、特定の段階でコードを実行できます。例:

javascript
new Vue({
    data() {
        return {
            message: 'Hello'
        };
    },
    // Vue インスタンスライフサイクルの最初のフック
    // インスタンス初期化後、データ監視と event/watcher イベント設定の前に実行
    beforeCreate() {
        console.log('Before create');
    },
    // インスタンス作成完了後に呼ばれる
    created() {
        console.log('Instance created');
    },
    beforeMount() {
        console.log('Before mount');
    },
    mounted() {
        console.log('Component mounted');
    },
    beforeUpdate() {
        console.log('Before update');
    },
    updated() {
        console.log('Component updated');
    },
    beforeDestroy() {
        console.log('Before destroy');
    },
    destroyed() {
        console.log('Instance destroyed');
    }
});

コンポーネント化

コンポーネント基礎

コンポーネントは Vue アプリの最も重要な概念の一つです。ページを複数の小さく再利用可能な部分に分けられます。たとえば、簡単な HelloWorld コンポーネントを作ります。

javascript
// HelloWorld という名前のコンポーネントを定義
const HelloWorld = {
    template: '<div>Hello, World!</div>'
};

// Vue インスタンスでこのコンポーネントを使う
new Vue({
    el: '#app',
    components: {
        HelloWorld
    }
});

テンプレートでコンポーネントを使います。

html
<div id="app">
    <HelloWorld></HelloWorld>
</div>

コンポーネント通信

  • props:親コンポーネントから子コンポーネントへデータを渡すために使います。
javascript
// 子コンポーネント
const ChildComponent = {
    props: ['message'],
    template: '<div>{{ message }}</div>'
};

// 親コンポーネントで子コンポーネントを使い、データを渡す
new Vue({
    el: '#app',
    components: {
        ChildComponent
    },
    data() {
        return {
            parentMessage: 'Hello from parent'
        };
    }
});
html
<div id="app">
    <ChildComponent :message="parentMessage"></ChildComponent>
</div>

Released under the MIT License.