CH7 より大規模なアプリケーション開発

コラム なぜ抽象化が必要なの?

このコラムはどうも抽象化言いたいだけでは?みたいになっているので、次の増刷があれば少し書き直す予定です。

  1. コードを抽出しよう:
    ある程度の範囲でコードをまとめて抜き出すとメンテしやすくなる(ユーザー情報・商品情報など)
  2. コードを共通化しよう:
    同じ処理を行っている場合は、関数で共通化するとメンテしやすくなる(算出処理など)
  3. 依存しないコードを書こう:
    たとえば、ポチがご飯を食べる処理をするとき「ドッグフードを食べる」と具体的に書いてしまうと、登場する動物の数だけ処理を書かなくてはいけないし、ドッグフード以外のものが食べられない…。

S35 単一ファイルコンポーネントとは

221~225ページ

Exampleコンポーネント
<template>
  <div class="example">
    <span class="title">{{ text }}</span>
  </div>
</template>

<script>
  export default {
    name: 'Example',
    data() {
      return {
        text: 'example'
      }
    }
  }
</script>

<!-- scoped CSS -->
<style scoped>
  .title {
    color: #ffbb00;
  }
</style>

S37 Node.js の導入

S38 Vue CLI の導入

231~237ページ

Vue CLI のインストール

Vue CLI をグローバルにインストール
npm install -g vue-cli

新しいプロジェクトの作成

プロジェクトの作成
vue init webpack my-app

最後に自動でインストールが開始されない場合は、次のコマンドで my-app ディレクトリに移動してモジュールをインストールしてください。

cd my-app
npm install

フォルダとファイルの構成

234ページ

次のように、ルートコンストラクタのテンプレートを描画関数に変更してそれ以外はすべて「.vue」ファイルを使用することで、ランタイム限定ビルド(ややコンパクトサイズ)の Vue.js を利用できます。 テンプレートオプションを使用していると、コンパイルが必要になるためランタイム限定ビルドは利用できません。

main.js 変更前
new Vue({
  el: '#app',
  components: { App },
  template: '<App/>'
})
main.js 変更後
new Vue({
  el: '#app',
  render: h => h(App)
})

ランタイムってなに?

ランタイム限定の「ランタイム」とは作成したアプリケーションを動かすために必要なコードのことをいいます。 コンパイラを含まず最低限になるため、少しサイズが小さくなります。

完全ビルドは、テンプレートを描画関数に変換する「コンパイラ」も含んだコードです。 そのため、webpack などを使って事前にコンパイルしておけば、コンパイラは不要になります。

[おまけ] Vue CLI バージョン3

ここからは、Vue CLI3の説明です。

WARNING

バージョン3のドキュメントは、リポジトリの「docs」フォルダに英語版がありますが、日本語はまだ整備されていません。 また、ベータ版のため仕様に変更が入ることもあります。不安がある場合はバージョン2を使用してください。

Vue CLI3 のインストール

npm install -g vue-cli の代わりに、次のコマンドで現在開発中のバージョン3の Vue CLI をインストールできます。

Vue CLI3 をグローバルにインストール
npm install -g @vue/cli
# or yarn がいい場合は…
yarn global add @vue/cli

プロジェクトの作成方法

プロジェクトの作成は vue init webpack my-app の代わりに、次のコマンドを使用します。

プロジェクトの作成
# プロジェクトの作成
vue create my-app

Vue CLI3 では、質問内容がだいぶ異なります。 また、テンプレートを指定するのではなく、質問に答えて必要なパッケージを選択します。 学習では、一番最初のプリセットで「simple」を選択するか、「Manually select features」を選択して「Babel」「CSS Pre-processors」のみを選択するのがオススメです。 上下の矢印キーで項目移動、スペースキーでチェックが付けられます。

Vuex と Vue Router については、インストール手順から説明しているため、この時点ではインストールしなくても問題ありません。 最初の質問でプリセットを選択した場合は、すぐにモジュールのインストールが開始されます。

Vue CLI3 ではビルドツール用のファイルは、ほぼすべて隠蔽されるため、フォルダがスッキリとします。 ビルド設定のカスタマイズは、プロジェクトルートに vue.config.js というファイル作成してそこに追加していきます。

ディレクトリ構造

「src」ディレクトリの中身はバージョン2と同じです。「public」フォルダには、インデックスの HTML のテンプレートとなる「index.html」ファイルと、ローダーを介さずそのまま公開する静的ファイルが入ります。(つまり、バージョン2の「static」フォルダと同じ)

デフォルト
.git/ 3では最初から作成される!✨
public/ そのまま公開したいファイル
src/
 ├ assets/
 ├ components/
 ├ App.vue
 └ main.js
Vuex と VueRouterを使う場合はこんなかんじ
.git/ 
public/
src/
 ├ assets/
 ├ components/
 ├ store/ Vuex モジュール
 ├ views/ ページ用コンポーネント
 ├ App.vue
 ├ main.js
 ├ router.js
 └ store.js

開発サーバーの起動のコマンドも変わり、次のようになります。

npm run serve
# or
yarn serve

S39 Vue.jsプラグイン

238~241ページ

プラグインを自作してみよう

238ページ

スクロール数値を共有するプラグイン
var windowPlugin = {
  install: function(Vue) {
    // プラグインデータ用にVueインスタンスを利用する
    var store = new Vue({
      data: {
        scrollY: 0
      }
    })
    // ウィンドウのスクロールイベントをハンドル
    var timer = null
    window.addEventListener('scroll', function() {
      if (timer === null) {
        timer = setTimeout(function() {
          // 200ms間隔でscrollYプロパティに代入
          store.scrollY = window.scrollY
          clearTimeout(timer)
          timer = null
        }, 200)
      }
    })
    // インスタンスプロパティに登録
    Vue.prototype.$window = store.$data
  }
}
プラグインを登録
Vue.use(windowPlugin)
すべての Vue インスタンスで使用可能
Vue.component('my-component', {
  template: '<div>{{ scrollY }}</div>',
  computed: {
    scrollY: function() {
      return this.$window.scrollY
    }
  }
})

S40 ES2015 で書いてみよう

242~250ページ

変数宣言の書き方

再代入
let x = 0
console.log(x++) // -> 1
const x = 0
console.log(x++) // -> Identifier 'x' has already been declared
スコープ
{
  let x = 1
}
console.log(x) // -> x is not defined
配列を空にする
const array = [1, 2]
array.push(3)
console.log(array) // -> (3) [1, 2, 3]
array.length = 0
console.log(array) // -> []

関数とメソッドの書き方

function の省略

Vue の this を使いたい場合はこれ!
new Vue({
  methods: {
    handleClick() { ... }
  }
})

アロー関数

STEP1
const newArray = array.map(el => {
  return el * 2
})
STEP2 return を省略
const newArray = array.map(el => el * 2)
STEP3 複数の引数
const newArray = array.map((el, index) => el * 2)
STEP4 オブジェクトの return
const newArray = array.map(el => ({ value: el * 2 }))

テンプレートリテラル

const name = 'たま'
const template = `
  <div class="template">
    <strong>${ name }</strong>
  </div>`
console.log(template)

プロパティのショートハンド

const a = 'foo'
const b = 'bar'
const newObject = { a, b }

分割代入

// 配列要素1,2をそれぞれ変数a,bに代入
const [a, b] = [1, 2]
console.log(a) // -> 1
// nameプロパティだけ代入
const { name } = { id: 1, name: 'りんご' }
console.log(name) // -> りんご
function myFunction({ id, name }) {
  console.log(name) // -> りんご
}
myFunction({ id: 1, name: 'りんご' })

スプレッド演算子

const array = [1, 2, 3]
// バラバラの3つの引数として渡す
myFunction(...array)
// arrayを展開して4を加えた新しい一次配列を作成
const newArray = [...array, 4] // -> (4) [1, 2, 3, 4]

配列メソッド

find

const array = [
  { id: 1, name: 'りんご' },
  { id: 2, name: 'ばなな' }
]
const result = array.find(el => el.id === 2)
console.log(result) // -> { id: 2, name: 'ばなな' }

findIndex

const array = [
  { id: 1, name: 'りんご' },
  { id: 2, name: 'ばなな' }
]
const result = array.findIndex(el => el.id === 2)
console.log(result) // -> 1

Promise

成功を知る
function myFunction() {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      // 成功したことを通知
      resolve('success!')
    }, 1000)
  })
}
// 1秒後にmyFunctionが終わった知らせを受けてthenの処理が行われる
myFunction().then(value => {
  console.log(value) // -> success!
})
失敗を知る
function myFunction(num) {
  return new Promise((resolve, reject) => {
    if (num < 10) {
      resolve('success!')
    } else {
      reject('error!')
    }
  })
}
myFunction(100).catch(value => {
  console.log(value) // -> error!
})
どっちでもいい
myFunction().then().catch().finally(() => {
  // 成功でも失敗でも行われる
})