Vue.js入門 基礎から実践アプリケーション開発まで

サポートページ

この記事を読むのに必要な時間:およそ 0.5 分

ダウンロード

(2020年8月12日更新)

以下のファイルをダウンロードできます。
圧縮ファイルをダウンロードして,適宜展開してご利用ください。
2019年9月9日,動作しなかったコードを修正しています。ダウンロードしなおしてください。

ダウンロード
sample20200811.zip

補足情報

P.167 # 5.2.3のslot-scopeを使った例がVue 2.6.0以降で動かない例

(2019年9月10日更新)

v2.6からslotはroot elementが必須になり,v-ifを用いた本書のサンプルは動作しなくなっていました。v2.6以降で動作を試したい場合は下記のようにv-showに修正して試してください。


<!DOCTYPE html>
<title>Vue app</title>
<!-- 最新のvue読み込み -->

<div id="app">
  <todo-list :todos="todos">
    <li v-show="todo.isCompleted" slot-scope="{ todo }" :key="todo.id">
        {{ todo.text }} 
    </li>
  </todo-list>
</div>


var TodoList = {
  props: {
    todos: {
      type: Array,
      required: true
    }
  },
  template: `
    <ul>
      <template v-for="todo in todos">
        <!-- v-bindディレクティブでtodoを親コンポーネントに渡す -->
        <slot :todo="todo">
          <li :key="todo.id">
            {{ todo.text }}
          </li>
        </slot>
      </template>
    </ul>
  `
}

new Vue({
  el: '#app',
  data: function() {
    return {
      todos: [
        { id: 1, text: 'C++',        isCompleted: true   },
        { id: 2, text: 'JavaScript', isCompleted: false  },
        { id: 3, text: 'Java',       isCompleted: true   },
        { id: 4, text: 'Perl',       isCompleted: false  }
      ]
    }
  },
  components: {
    TodoList: TodoList,
  }
})

P.370〜P.372 # 10.3.1のloginアクションハンドラに関するテスト

(2019年5月10日更新)

一部のコードがVue.js本体の変更に伴い動作しなくなっていました。Vue 2.6 以降では,Vue.nextTick のタスクが下記のissue対応によって処理されるタイミングが変わってしまったため(MutationObserverによるmicroTask),イベントループでうまく処理されなくなってしまいました。

以下のように Vue.nextTick を使わずに, Promise.then ,Promise.catch で done をハンドリングすることで,アサーションできるように修正してください。diff形式で掲載しています。


- import Vue from 'vue'
  import * as types from '@/store/mutation-types'
  
  // loginアクション内の依存関係をモック化する
  const mockLoginAction = login => {
    // inject-loaderを使ってアクション内の依存関係をモック化するための注入関数を取得する
    const actionsInjector = require('inject-loader!@/store/actions')
  
    // 注入関数でAuth APIモジュールをモック化する
    const actionsMocks = actionsInjector({
      '../api': {
        Auth: { login }
      }
    })
  
    return actionsMocks.default.login
  }
  
  describe('loginアクション', () => {
    const address = '[email protected]'
    const password = '12345678'
    let commit
    let future
  
    describe('Auth.loginが成功', () => {
      const token = '1234567890abcdef'
      const userId = 1
  
      beforeEach(done => {
        const login = authInfo => Promise.resolve({ token, userId })
        const action = mockLoginAction(login)
        commit = sinon.spy()
  
        // loginアクションの実行
        future = action({ commit }, { address, password })
-       Vue.nextTick(done)
+       future.then(() => done())
      })
  
      it('成功となること', () => {
        // commitが呼ばれているかチェック
        expect(commit.called).to.equal(true)
        expect(commit.args[0][0]).to.equal(types.AUTH_LOGIN)
        expect(commit.args[0][1].token).to.equal(token)
        expect(commit.args[0][1].userId).to.equal(userId)
      })
    })
  
    describe('Auth.loginが失敗', () => {
      beforeEach(done => {
        const login = authInfo => Promise.reject(new Error('login failed'))
        const action = mockLoginAction(login)
        commit = sinon.spy()
  
        // loginアクションの実行
        future = action({ commit })
-       Vue.nextTick(done)
+       future.catch(() => done())
      })
  
      it('失敗となること', done => {
        // commitが呼ばれていないかチェック
        expect(commit.called).to.equal(false)
  
        // エラーが投げられているかチェック
        future.catch(err => {
          expect(err.message).to.equal('login failed')
          done()
        })
      })
    })
  })

お詫びと訂正(正誤表)

本書の以下の部分に誤りがありました。ここに訂正するとともに,ご迷惑をおかけしたことを深くお詫び申し上げます。

(2020年8月12日最終更新)

P.96 3.3.1のコンポーネントの表記例


<div id=app>


<div id="app">

(以下2019年10月9日更新)

P.135 # 4.4.5のグローバルメニューにログアウトメニュー・ログインメニューを追加したあとの解説

本来はグローバルメニューにログアウト・ログインメニュー実装後に下記のようにログイン関連の説明を追加すべきでした。


上記グローバルメニューのHTML内で認証モジュールAuthを利用するために、Vueインスタンス生成時のdataプロパティにAuthを指定しましょう。


var app = new Vue({
  data: {
    Auth: Auth
  },
  router: router
}).$mount('#app')

(以下2019年9月10日更新)

P.107 # 3.4.3のコンテンツを埋め込まずにslotを使った場合の画像例

画像が誤っていました。文言は同一ですがスタイルが一部異なります。

P.107 # 3.4.3のコンテンツを埋め込んだ場合の画像例

画像が誤っていました。「りんご、イチゴ」と表記されるべき部分が「いちご、りんご」となっていました。

P.167 # 5.2.3の「スコープ付きスロット」の例のHTML側の表記

slot-scopeを使わないもの,使うものそれぞれ動作しますが,:keyの指定が抜けていました。



<li slot-scope="slotProps" v-if="slotProps.todo.isCompleted" :key="slotProps.todo.id">



<li slot-scope="{ todo }" v-if="todo.isCompleted" :key="todo.id">

P.221 # 6.6.3の「名前付きスタイル識別子の算出プロパティ」の実行

vue serveに指定するファイル名が誤っていました。正しくはform.vueを開く箇所でした。


$ editor form.vue
$ vue serve form.vue --open

P.196 # 5.5.2のコード,authに関する記述

初出の$optionsに対する説明のコメントが不足していました。


var auth = this.$options.auth


var auth = this.$options.auth // $optionsでVueインスタンス生成時のオプションを参照できます

P.354〜P.355 # 10.2.1 kbnButtonコンポーネントの単体テストコード(disabledプロパティの値がfalseのテストコード)

本来はテストコードでpropsDataを指定しなければいけない箇所で指定していませんでした。直前のテストコードでtrueにしているのを参照してください。


  describe('false', () => {
    it('disabled属性が付与されていないこと', () => {
      const button = mount(KbnButton)
      expect(button.attributes().disabled).to.be.an('undefined')
    })
  })


  describe('false', () => {
    it('disabled属性が付与されていないこと', () => {
      const button = mount(KbnButton, {
        propsData: { disabled: false }
      })
      expect(button.attributes().disabled).to.be.an('undefined')
    })
  })

(以下2019年5月13日更新)

P.69 # 2.10.1のライフサイクルフック一覧表

表中の表記が誤っていました。

detroyed
destroyed

(以下2019年3月22日更新)

P.96 # 3.3.1のコンポーネントの書式の誤り

defaultとすべき箇所が,defalutと誤っていました。
正しくは以下の通りです。

Vue.component(コンポーネント名,{
  props: {
    親から受け取る属性名:{
      type: StringやObjectなどのデータ型,
      default: デフォルト値,
      required: 必須かどうかの真偽値,
      validator: バリデーション用の関数
    }
  }
  // ...template内で「親から受け取る属性」が使える
})

P.193 # 5.5.1の説明文

Consoleの出力から、ミックスイン→コンポーネントの順番フック関数が呼ばれていることが分かります。
Consoleの出力から、ミックスイン→コンポーネントの順番フック関数が呼ばれていることが分かります。

(以下2019年2月18日更新)

P.107 # 3.4.3の最後のJSFiddleのURL

本来挿入されるべき,Vue.jsの読み込みが行われていませんでした。


https://jsfiddle.net/bha18soe/


https://jsfiddle.net/upd9843j/ 

P.182,P.183 # 5.4.3のデータオブジェクト中のソースコード

P.182の下段からP.183中段にかけての,my-buttonのコードに不足があり動作しませんでした。正しくは下記のコードです。


new Vue({
  el: '#app',
  render: function (createElement) {
    return createElement('my-button', {
      attrs: {
        href: 'https://vuejs.org/'
      },
      props: {
        tag: 'a'
      }
    }, 'anchor')
  },
  components: {
    MyButton: MyButton
  }
})




new Vue({
  el: '#app',
  render: function (createElement) {
    return createElement(MyButton, {
      attrs: {
        href: 'https://vuejs.org/'
      },
      props: {
        tag: 'a'
      }
    }, 'anchor')
  }
})

(以下,2019年2月4日更新)

P.200 # 6.1.1冒頭のVue CLIに関する解説のページ

Vue CLIは、Vue.js向けのアプリケーション開発環境をセットアップなどの機能を提供する公式のコマンドラインツールです。
Vue CLIは、Vue.js向けのアプリケーション開発環境セットアップなどの機能を提供する公式のコマンドラインツールです。

P.331 # 9.2.1のディレクトリ作成


$ mkdir -p src/ components/{ atoms, molecules, organsms, templates}


$ mkdir -p src/ components/{ atoms, molecules, organisms, templates}

P.346 # 9.4.1最初の構成図

図中の番号表記が誤っていました。正しくは下記です。

(以下2018年11月14日更新)


(以下2018年11月14日更新)

P.123 # 4.4の最初のコードブロック


<!-- router-link による ナビゲーション 定義 -->>


<!-- router-link による ナビゲーション 定義 -->

P.125 # 4.4.2の説明文

UserListコンポーネントのテンプレートとJavaScriptを回収していきます。
UserListコンポーネントのテンプレートとJavaScriptを改修していきます。

P.215 6章の「コラム スコープ付きCSSのメリット」のコードのbar.vue

コードが誤っていました。正しくは下記のコードです。


<template>
  <div class="bar">
    <h1 class="header">Barコンポーネント</h1>
    <p>これはBarコンポーネントです。</p>
    <foo/> <!-- Fooコンポーネントの利用。scriptブロックも要注目 -->
  </div>
</template>

<script>
import Foo from './foo'
export default { // FooコンポーネントをBarコンポーネントに登録
  components: {
    Foo
  }
}
</script>

<style scoped>
.bar {
  border: 1px solid red;
  margin: 4px;
  padding: 4px;
}
.header { font-size: 125%; }
</style>

P.280~281 # 7.6.1 の最後のコードブロックのコード例

actionsとすべき個所がactionになっていました。正しくは下記のコードです。


import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

const store = new Vuex.Store({
  modules: {
    // fooモジュール
    foo: {
      state: {
        value: 123
      },

      actions: {
        log (ctx) {
          console.log('モジュールfooのステート', ctx.state)
        }
      }
    },

    // barモジュール
    bar: {
      state: {
        message: 'Hello!'
      },

      actions: {
        log (ctx) {
          console.log('モジュールbarのステート', ctx.state)
        }
      }
    }
  }
})

// logアクションを呼び出す
// fooモジュール内のステートと、barモジュール内のステートが出力される
store.dispatch('log')

P.358 # 10.2.2の
test/unit/specs/components/molecules/kbnLoginForm.spec.js中のdescribeに与える文言

メールアドレス形式のフォーマットを検証する部分で,itの第一引数に与える説明が誤っていました。


describe('メールアドレス形式のフォーマット', () => {
    it('validation.email.requiredがvalidであること', () => {


describe('メールアドレス形式のフォーマット', () => {
    it('validation.email.formatがvalidであること', () => {


P.371 # 10.3.1のコード中のコメント


 // commitが呼ばれていなかチェック


 // commitが呼ばれていないかチェック


(以下2018年10月10日更新)

P.299  8.4.1のvue init時の引数の文字列

$ vue init webpack kandan-app
$ vue init webpack kanban-app

(以下2018年10月3日更新)

P.305 8.5冒頭の箇条書き

・複数のHTMLテンプレート
・CSSやSassなどのスタイルシート
・JavaScriptファイルによって
・HTMLテンプレート
・CSSやSassなどのスタイルシート
・JavaScript

P.308の脚注部を除く最下行 8.6.1のKarmaのインストールに関する説明

文章が途中で抜けていました。

Karma公式でサポートする
Karma公式でサポートするKarmaランチャ

(以下2018年9月21日更新)

P.2 1章のプロジェクトに関する説明

プロジェクトして開発を行っています。
プロジェクトとして開発を行っています。

P.10 1.2.1のコード例に関する説明

まだ文法事項を解説してないので、
まだ文法事項を解説していないので、

P.11の5行目 1.2.1の説明

Vue.jsは先に上げた現代のWebフロントエンド開発の
Vue.jsは先に挙げた現代のWebフロントエンド開発の

P.18 1.5.1の単一ファイルコンポーネントのコード例

templateの閉じタグが誤っていました。



<template>
  <p>{{message}}!</p>
<template>
<script>
export default = {
  data () {
    return {
      message: 'こんにちは'
    }
  }
}
</script>
<style scoped>
p {
  color: red;
}
</style>




<template>
  <p>{{message}}!</p>
</template>
<script>
export default = {
  data () {
    return {
      message: 'こんにちは'
    }
  }
}
</script>
<style scoped>
p {
  color: red;
}
</style>


P.22 1.6の冒頭の説明

ユーザーのWebアプリケーションを開発をサポートするために
ユーザーのWebアプリケーション開発をサポートするために

P.23 1.6のVue Curatedの説明

Vue.jsコアチームが激選したプラグイン、
Vue.jsコアチームが厳選したプラグイン、

P.34 2.3 Vueオブジェクトの説明文

基本機能を紹介してきます。
基本機能を紹介していきます

P.47 2.7の実行結果の画面

実行結果画面が誤っていました。正しくは下記画面です。画像をクリックすると大きく表示できます。

P.55 2.9.2のstyleの記述例を説明した文中のコード表記例


styleはセミコロン("collor: tomato; background: yellow")で


styleはセミコロン("color: tomato;; background: yellow")で

P.71 2.10.4のコード例中のコメント


// データに参照できる


// データ参照できる

P.73 コラム 算出プロパティのキャッシュ機構の最初の説明

ここで説明したメソッドと先程の算出プロパティは、いずれも関数の形と取るという点では同じで、
ここで説明したメソッドと先程の算出プロパティは、いずれも関数の形取るという点では同じで、

P.85 3.2.1 グローバルコンポーネントの定義内のオプション表のfilters行

データを文字列と整形する
データを文字列整形する

P.96 3.3.1のフルーツの名前をリストするコンポーネント中のコメント


<!-- v-forで繰り返した各furitをprops(fruits-item)に与えている --> 


<!-- v-forで繰り返した各fruitをprops(fruits-item)に与えている --> 

P.104 コラム Atomic DesignのOrganisms中の例の説明

ログインフォームやコメントフォームなナビゲーションバーなど。
ログインフォームやコメントフォームナビゲーションバーなど。

P.108 3.4.4 箇条書きの項目名

ユーザーID入力欄
ログインID入力欄

P.118の3行目 4.2.2の「HTML側の指定とページ遷移の実行」のrouter-viewなどの説明箇所

〜部分にレンダリングされます。ページを開いてからページ遷移が
〜部分にレンダリングされます。しかし、ページを開いてからページ遷移が

P.123 4.4の冒頭の解説

例として、ユーザー情報登録・閲覧が可能なアプリケーション用います。
例として、ユーザー情報登録・閲覧が可能なアプリケーション用います。

P.123 4章の脚注7

ES2015以降でプログラムを作成したい場合もWebpackの利用はほぼ必須です。
ES2015以降でプログラムを作成したい場合もwebpackの利用はほぼ必須です。

P.124 4.4リスト中のライブラリの読み込み部分

動作はしますがバージョンが古いものでした。



<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/vue-router.min.js"></script>




<script src="https://unpkg.com/vue@2.5.17"></script>
<script src="https://unpkg.com/vue-router@3.0.1"></script>


P.136 4.4.6のリスト中のvue-routerのバージョン指定

<script src="https://unpkg.com/[email protected]"></script>
<script src="https://unpkg.com/vue-router@3.0.1"></script>

P.147 「コラムVue Routerを使った大規模なアプリケーションの実装」の表記

propを使ったデータの受け渡しチェーン
propsを使ったデータの受け渡しチェーン

P.151 5.1.3の記述

実際にコードと見ていきます。
実際にコード見ていきます。

P.160 5.1.4最後のアニメーション関連の文章

Velocity.js,jQueryのアニメーション機能、
Velocity.jsjQueryのアニメーション機能、

P.161 5.2のスロットの説明

プロパティでテキストを渡して表示されても
プロパティでテキストを渡して表示しても

P.168 5.3のビルトインのディレクティブとの比較解説

Vue.jsのアプリケーションを実装する上で、ビルドインの
Vue.jsのアプリケーションを実装する上で、ビルトイン

P.168 5.3のローカルディレクティブの利用例

ブログエントリの要素付けのUIなどです。
ブログエントリのタグ付けのUIなどです。

P.170 5.3.1の画像の説明の表記

すると以下のようにnoimageの画像が
すると以下のようにno imageの画像が

P.172 5.3.3の「updateフックによる値の変更の検知」内のoldValueプロパティの説明

そこで、bindingのvalue、oldValueプロパティの値を比較して...
そこで、bindingのvalue、updateとcomponentUpdatedフックで利用できる変更前の値oldValueプロパティを比較して...

P.174 5.3.4のコード中のbindの表記

本来「:」とすべき個所が「!」になっていました。


bind! function (el, binding) {


bind: function (el, binding) {

P.175 5.3.4のコード中のupdateとdataの表記

本来「:」とすべき個所が「!」になっていました。


update! function (el, binding) {


update: function (el, binding) {


data! function() {


data: function() {

P.175 5.3.4のnoImageURLプロパティに関する記述

文字列をセットして、属性値と指定します。
文字列をセットして、属性値指定します。

P.176 5.3.4の何も表示されない状態に関する記述

no_image画像も何も表示されなくなるはずです。
no image画像も何も表示されなくなるはずです。

P.182 5.4.3の「データオブジェクト」コード中のrenderの表記


render! function (createElement) {


render: function (createElement) {

P.192 5.5.1のmixinsプロパティの説明

コンポーネントオプジョンのmixins
コンポーネントオプションのmixins

P.194 5.5.1のオプションに関する記述

methodsやcomponents,directives等の
methodsやcomponentsdirectives等の

P.194 5.5.1のシェアメソッドに関する記述

コンポーネントで同名のシェアというメソッドを
コンポーネントで同名のshareというメソッドを

P.197 5.5.2の最後にJSONを文字列に変更する際のコードの誤り


JSON.strinfigy({name: 'Evan You'})


JSON.stringify({name: 'Evan You'})

P.210,p.211 6.6.2の「複数の<style>ブロックの定義」における参照先

参照先が誤っていました。正しくは6.6.2以降で利用するコラムを参照します。

先に利用した単一ファイルコンポーネントのFooコンポーネントとRootコンポーネントを以下のように変更します。
「コラム スコープ付きCSSのメリット(後述)」の単一ファイルコンポーネントfoo.vueとroot.vueを以下のように変更し、bar.vueをそのまま利用します。適宜サンプルを参照してください。
先程と同じ画面がWebブラウザに
コラムと同じ画面がWebブラウザに

P.214 6.6.2の「子コンポーネントのルート要素におけるスタイルの注意事項」の表示例画像のキャプション

socped属性によるカプセル化が
scoped属性によるカプセル化が

P.215 6章の「コラム スコープ付きCSSのメリット」のコード

コラム内のfoo.vue,root.vueのコードがtemplate部分のみ抜粋する形になっていたため全体を掲載いたします。

foo.vue


<template>
  <div class="foo">
    <h1 class="header">Fooコンポーネント</h1> <p>これはFooコンポーネントです。</p>
  </div>
</template>
<style scoped>
.foo { border: solid 1px green; margin: 4px; padding: 4px; }
.header { font-size: 150%; }
</style>

root.vue


<template>
  <div id="root">
    <h1 class="header">Rootコンポーネント</h1> <p>これはRootコンポーネントです。</p>
    <foo/> <bar/>
  </div>
</template>
<script>
import Foo from './foo'
import Bar from './bar'
export default {
  components: { Foo, Bar }
}
</script>
<style>
#root { border: solid 1px blue; margin: 4px; padding: 4px; }
.header { font-size: 200%; }
p { text-decoration: underline; }
</style>

P.219 6.6.3の$styleに関する記述

Vue.jsのクラスに対して使用可能なのオブジェクト
Vue.jsのクラスに対して使用可能オブジェクト

P.225 6.6.4のpug関連のパッケージをインストールする部分

pug-plain-loaderの追加が必要です。

npm install --save-dev pug
npm install --save-dev pug pug-plain-loader

P.227,p.228 6章「コラム カスタムブロックの定義」内のVue Loader周りの最新版での動作

$ npm install --save-dev deepmerge marked
$ npm install --save-dev marked


const merge = require('deepmerge')
const loader = require.resolve('./loader.js') // カレントディレクトリに作成したカ
スタムローダーを読み込む
module.exports = {
  chainWebpack: config => {
    // Vue Loaderの設定をカスタマイズする
    config.module
      .rule('vue')
      .use('vue-loader')
      .tap(options =>
        merge(options, {
          loaders: {
            // カスタムブロックをインポートしたカスタムローダーで処理する
            docs: loader
          }
      })
    )
    .end()
  }
}





const loader = require.resolve('./loader.js') // カレントディレクトリに作成したカスタムローダーを読み込む

module.exports = {
  chainWebpack: config => {
  // Vue Loaderの設定をカスタマイズする
    config.module
      .rule('docs')
      .resourceQuery(/blockType=docs/)
      .use('docs')
      .loader(loader)
  }
}



P.287 7.7.2の最後の説明

ここで上げた2つの手法は
ここで挙げた2つの手法は

P.236 7.1の最後のリスト内のimport


import TaskList from './TaskList'


import TaskList from './TaskList.vue'

P.251 7章の脚注*15

「この例では、incrementAsyncを使わずに書くと以下のようになります」の一文は必要ありません。

この例では、incrementAsyncを使わずに書くと以下のようになります。この例では、incrementAsync...
この例では、incrementAsync...

P.278 7.6.1のストア登録に関する説明

アクションがどのようにストアに登録にされるかを
アクションがどのようにストアに登録されるかを

P.286 7.7.2の説明文中の氏名の表記

Danは初めから正しく分類...
Danは初めから正しく分類...