この記事は?
今まで、フロントエンドJavaScriptフレームワークはReact.jsを少し触ったことがあったのですが、今後Vue.jsを仕事で使いそうなのでまとめます。この記事では以下のようなことをまとめ、Vue.jsにHello Worldとしてカウンターアプリを作ってみます。
- Vue.jsの概要
- Vue.jsのエコシステム
Vue.jsとは
Webフロントエンドを作成するためのJavaScriptフレームワークの1つです。Vue.jsと同様のフレームワークにはReact.js、Angular.jsなどがあります。公式ドキュメントでVue.jsはプログレッシブフレームワークとして紹介され、すでに存在するフロントエンドに対してプラガブルに差し込んだりすることが可能です。
Vue.jsではそれぞれのコンポーネントでHTML、CSS、JavaScriptを内包しています。また、状態変化はVue.jsによって管理され、反応的に画面の再構成を行います。
Vue.jsの特徴には以下の2つのものがあります。
- コンポーネントシステム
- リアクティブ
コンポーネントシステム
Vue.jsにおけるコンポーネントとはあらかじめ定義されたオプションを持つインスタンスです。Vue.jsでは小さなコンポーネントを組み合わせて大規模なアプリケーションを作成することが想定されています。
コンポーネント志向の設計では、画面を構成する。JavaScript、HTML、CSSを1つのコンポーネントとして扱い他の機能と分離できるという特性があります。それにより、「JavaScriptやCSSがどこで使われているか」といった複雑性を排除することができます。
また、Vue.jsのコンポーネントはツリー構造のように考えるとができます。
Vueコンポーネントを登録しておくことにより、他のコンポーネントからの利用することが可能となります。
// todo-itemというコンポーネントを登録
Vue.component('todo-item', {
template: '<li>This is a todo</li>'
})
登録したコンポーネントは下記のように利用することができます。
// 登録したコンポーネントを利用
<ol>
<todo-item></todo-item>
</ol>
また、利用側コンポーネントから、利用される側のコンポーネントへデータを受け渡すこともできます。
リアクティブ
Vue.jsではDataをプレーンなJavaScriptオブジェクトとして持ち、それらが更新されるとリアクティブに画面が更新されます。
各コンポーネントはそれぞれがWatcherインスタンス
と呼ばれるものを持っています。
Watcherはコンポーネントは描写時にふれたデータをすべて依存性として管理しており、依存性の変更が検知されるとWatcherが再描写の指示を行う仕組みになっています。
Vue.jsのエコシステム
Vue.jsのエコシステムには様々なものがあります。
開発ツール
主なVue.jsの開発ツールとして以下のようなものがあります。
-
vue-devtools
- Chrome、Firefox、Electron等の拡張機能として提供される、Vue.jsの開発者ツールです。
- コンソールを開かなくても、データの中身が見れたりします。
-
Vue CLI
- Vue.jsの開発を手助けするためのCLIです。
- ブランクプロジェクトの作成等が行えます。
-
Vue Loader
- webpackをロードするためのツール
コアライブラリー
Vue.jsのコアライブラリとして以下のようなものがあります。
Hello World
Hello Worldとしてカウンターアプリを作成してみたいと思います。
環境
- Vue CLI(v3.11.0)
- Node(v11.9.0)
- Chrome
カウンターアプリの作成
まずはブランクプロジェクトを作成します。ブランクプロジェクトはVue CLIを用いて作成します。
$ vue create hello-world-countor
すると以下のようなことをまず聞かれます。
Vue CLI v3.11.0
? Please pick a preset: (Use arrow keys)
> default (babel, eslint)
Manually select features
どうやら、babel等のツールを入れるかどうか選べるみたいですね。
今回はとりあえずHello Worldがしたいだけなので、深く突っ込まずにdefault
を選択します。
以下のようなブランクプロジェクトが作成されました。
hello-world-counter
│ .gitignore
│ babel.config.js
│ package.json
│ README.md
├─node_modules
├─public
│ favicon.ico
│ index.html
└─src
│ App.vue
│ main.js
│
├─assets
│ logo.png
│
└─components
HelloWorld.vue
package.json
はこんな感じになってます。
{
"name": "hello-world-counter",
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
"dependencies": {
"core-js": "^2.6.5",
"vue": "^2.6.10"
},
"devDependencies": {
"@vue/cli-plugin-babel": "^3.11.0",
"@vue/cli-plugin-eslint": "^3.11.0",
"@vue/cli-service": "^3.11.0",
"babel-eslint": "^10.0.1",
"eslint": "^5.16.0",
"eslint-plugin-vue": "^5.0.0",
"vue-template-compiler": "^2.6.10"
},
"eslintConfig": {
"root": true,
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"rules": {},
"parserOptions": {
"parser": "babel-eslint"
}
},
"postcss": {
"plugins": {
"autoprefixer": {}
}
},
"browserslist": [
"> 1%",
"last 2 versions"
]
}
サーバの起動コマンドの定義がされていたり、core-js
、vue
が依存に入ってたりしますね。
とりあえずDevサーバを起動して動かしてみます。vue-cli-service serve
で起動できそうです。
すると以下のような画面が表示されました。
この画面はApp.vue
とHelloWorld.vue
で構成されています。
ソースコードは下みたいな感じ
HelloWorld.vue
<template>
<div class="hello">
<h1>{{ msg }}</h1>
<p>
For a guide and recipes on how to configure / customize this project,<br>
check out the
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
</p>
<h3>Installed CLI Plugins</h3>
<ul>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
</ul>
<h3>Essential Links</h3>
<ul>
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
</ul>
<h3>Ecosystem</h3>
<ul>
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
</ul>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>
App.vue
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
}
}
</script>
<style>
# app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
*.vue
で定義されるVueコンポーネントは<script>
、<style>
、<template>
で構成されるみたいです。
名前の通りそれぞれでテンプレート、スクリプト、スタイルを書きます。
App.vue
をもう少し細かく見てみます。まずはtemplate
から
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
</div>
</template>
ロゴの表示とHelloWorld
コンポーネントを表示してます。
msg
の所でコンポーネントに対して変数を渡せるみたいですね。
変数の参照はHelloWorld.vue
の{{ msg }}
の所です。
次にscript
を見てみます。
<script>
import HelloWorld from './components/HelloWorld.vue'
export default {
name: 'app',
components: {
HelloWorld
}
}
</script>
HelloWorld.vue
のインポートとコンポーネントとしての登録が行われています。
ここでは、コンポーネントシステム
の所で説明したコンポーネント登録のやり方とは違うローカルのコンポーネント登録が行われています。
最後にstyle
<style>
# app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
ここではCSSを記述してますね。Vue.jsの勉強として突っ込めそうなところはないのでこれ以上の深堀はしないです。
このApp.vue
をmain.js
でVueオブジェクトで読み込んでVueインスタンスを作成しています。
import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app')
ちなみにここのh
はhyperscript
の略で、hyperscript
は仮想DOMの実装のことを表すそうです。
ざっくりとプロジェクトを把握したところで、カウンターアプリを作っていきます。
せっかくなのでVue.jsのロゴとWelcome to Your Vue.js App
の所は残しておきます。
まずは、カウンターコンポーネントを作成します。
Counter.vue
<template>
<div id="counter">
<span>{{ num }} </span>
<button @click="addOne">up</button>
<button @click="substractOne">down</button>
<p v-if="num === 0">
Press 'up' or 'down' button!!!!
</p>
</div>
</template>
<script>
export default {
name: 'Counter',
data() {
return {
num: 0
}
},
methods: {
addOne: function () {
this.num = this.num + 1;
},
substractOne: function () {
this.num = this.num - 1;
}
}
}
</script>
template
はデフォルトでHTMLを記述します。数字とカウントアップ、ダウンのボタンを用意しました。
@click
の所はボタンが押された際に実行するメソッドを書くことができます。+ 1
する関数と- 1
する関数をそれぞれ呼び出します。
v-if
ディレクティブは条件付きレンダリングと呼ばれるもので、Vue.jsのディレクティブ内の式がtrue
を返す場合に描写が行われます。
script
のdate()
の部分でnum
プロパティを作成し、methods
の部分ではプラスとマイナスそれぞれのメソッドを作成しています。
作ったコンポーネントをApp.vue
に追加します。
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<HelloWorld msg="Welcome to Your Vue.js App"/>
<Counter/>
</div>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
import Counter from './components/Counter'
export default {
name: 'app',
components: {
HelloWorld,
Counter
}
}
しょぼいですが、カウンターアプリが作成できました。
感想
とりあえずアプリを作って、動かしてみました。
わからんところだらけだけど雰囲気で動くなーって感じました。