
お勉強用リポジトリ
https://github.com/yuukanehiro/Vue-Study
Udemyと参考書をやってみてメモ
もくじ
きほんのき
はろわ!
hello.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Vue.js</title>
</head>
<body>
<div id="app">
<p>{{ message }}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script src="js/hello.js"></script>
</body>
</html>
js/hello.js
let app = new Vue({
el: '#app',
data: {
message: 'はろわ!'
}
})
v-bind
bind.html
<div id="app">
<a v-bind:href="url">優技録</a>
</div>
js/bind.js
let app = new Vue({
el: '#app',
data: {
url: 'https://www.yuulinux.tokyo'
}
})
v-model 双方向データバインディング
vmodel.html
<div id="app">
<input type="text" v-model="data">
<p>{{ data }}</p>
</div>
js/vmodel.js
let app = new Vue({
el: '#app',
data: {
data: '優技録だよ',
}
})
computed
computed.html
<div id="app">
<p>{{ localEmail }}</p>
</div>
js/computed.js
let app = new Vue({
el: '#app',
data: {
email: 'YUU3@example.net'
},
computed: {
localEmail: function() {
return this.email.split('@')[0].toLowerCase() + '@' +this.email.split('@')[1];
}
}
})
methods
methods.html
<div id="app">
<p>{{ localEmail }}</p>
</div>
js/methods.js
let app = new Vue({
el: '#app',
data: {
email: 'YUU3@example.net'
},
methods: {
localEmail: function() {
return this.email.split('@')[0].toLowerCase() + '@' +this.email.split('@')[1];
}
}
})
v-on
on.html
<div id="app">
<button v-on:click="onclick">押して!</button>
<p>{{ now }}</p>
</div>
js/on.js
let app = new Vue({
el: '#app',
data: {
now: '',
},
methods: {
onclick: function() {
this.now = new Date().toLocaleString();
}
}
})
v-if
vif.html
<div id="app">
<p>{{ message }}</p>
<p v-if="toggle">
<a v-bind:href="url">優技録</a>
</p>
</div>
js/vif.js
let app = new Vue({
el: '#app',
data: {
message: 'こんにちわん!',
url: 'https://www.yuulinux.tokyo/',
toggle: true
}
})
v-for
vfor.html
<div id="app">
<p>{{ message }}</p>
<p v-if="toggle">
<a v-bind:href="url">優技録</a>
</p>
<ul>
<li v-for="language in languages">{{ language }}</li>
</ul>
</div>
js/vfor.js
let app = new Vue({
el: '#app',
data: {
message: 'こんにちわん!',
url: 'https://www.yuulinux.tokyo/',
toggle: true,
languages: [
'JavaScript',
'PHP',
'Python'
]
}
})
component
component.html
<div id="app">
<hello-component></hello-component>
</div>
js/component.js
Vue.component('hello-component', {
template: '<p>こんにちゃ!</p>'
})
let app = new Vue({
el: '#app'
})
computedとmethodsの違い
- computed
・getter, setter
・キャッシュされる - methods
・getter
・キャッシュされない
computed2.html
<div id="app">
<p>
base price: <input type="text" v-model="basePrice">
</p>
<p>
tax included price: <input type="text" v-model="taxIncludedPrice">
</p>
</div>
js/computed2.js
let app = new Vue({
el: '#app',
data: {
basePrice: 100
},
computed: {
taxIncludedPrice: {
get: function() {
return parseInt(this.basePrice * 1.08); // 整数値を返す
},
set: function(taxIncludedPrice) {
this.basePrice = Math.ceil(taxIncludedPrice / 1.08); // 小数点以下を切り上げてからbasePriceプロパティに代入
}
}
}
})
watch
watch.html
<div id="app">
<p>
{{ message }}
</p>
<p>
<input type="text" v-model:value="message">
</p>
<pre>{{ $data }}<pre>
</div>
js/watch.js
let app = new Vue({
el: '#app',
data: {
message: '優技録'
},
watch: {
message: function(newValue, oldValue) {
console.log('new: %s, old: %s', newValue, oldValue)
}
}
})
lodashライブラリ
- _.debounce(関数名, ミリ秒)
画面同期やサーバ問い合わせでミリ秒待ってから、関数名を実行する
クラスのデータバインディング
classbind.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<title>Vue.js</title>
<style>
.large {
font-size: 36px;
}
.text-danger {
color: red;
}
</style>
</head>
<body>
<div id="app">
<p>
Hello <span v-bind:class="{large: isLarge, 'text-danger': hasError}">優技録</span>
</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script src="js/classbind.js"></script>
</body>
</html>
js/classbind.js
let app = new Vue({
el: '#app',
data: {
isLarge: true,
hasError: true
}
})
セレクトボックス
単体選択
select-single.html
<div id="app">
<select v-model="selected">
<option disable value="">選択してちょ</option>
<option>りんご</option>
<option>ばなな</option>
<option>しゅーまい</option>
</select>
{{ selected }}
</div>
select-single.js
let app = new Vue({
el: '#app',
data: {
selected: ''
}
})
複数選択
select-multiple.html
<div id="app">
<select v-model="selected" multiple>
<option disable value="">選択してちょ</option>
<option>りんご</option>
<option>ばなな</option>
<option>しゅーまい</option>
</select>
{{ selected }}
</div>
select-multiple.js
let app = new Vue({
el: '#app',
data: {
selected: []
}
})
簡単なアプリをつくろう
todolist
todolist.html
<!DOCTYPE html>
<html lang="ja">
<head>
<style>
#app ul {
list-style: none;
}
#app li > span.done {
text-decoration: line-through;
}
</style>
<meta charset="UTF-8" />
<title>Vue.js</title>
</head>
<body>
<h2>ToDo list</h2>
<div id="app">
<form v-on:submit.prevent>
<input type="text" v-model="newItem">
<button v-on:click="addItem">
追加だ!
</button>
</form>
<ul>
<li v-for="(todo, index) in todos">
<input type="checkbox" v-model="todo.isDone">
<span v-bind:class="{ done: todo.isDone }">{{ todo.item }}</span>
<button v-on:click="deleteItem(index)">削除</button>
</li>
</ul>
<pre>{{ $data }}</pre>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script src="js/todolist.js"></script>
</body>
</html>
js/todolist.js
let app = new Vue({
el: '#app',
data: {
newItem: '',
todos: []
},
methods: {
addItem: function(event) {
// 入力が空の場合はアーリーリターン
if (this.newItem == '') {
return;
}
var todo = {
item: this.newItem,
isDone: false
};
this.todos.push(todo); // タスク追加
this.newItem = ''; // クリア
},
deleteItem: function(index) {
this.todos.splice(index, 1); // splice(削除を開始する配列のインデックス, 削除する個数)
}
}
})
bitcoin
bitcoin.html
<!DOCTYPE html>
<html lang="ja">
<head>
<style>
#app ul {
list-style: none;
}
#app li > span.done {
text-decoration: line-through;
}
[v-cloak] {
display: none;
}
</style>
<meta charset="UTF-8" />
<title>Vue.js</title>
</head>
<body>
<h2>BitCoin App</h2>
<div id="app">
<section v-if="hasError">Errorが起きたよ</section>
<section v-else>
<div v-if="loading">
Now Loading...
</div>
<ul v-cloak>
<li v-for="(rate, currency) in bpi">
{{ currency }} : {{ rate.rate_float | currencyDecimal }}
</li>
</ul>
</section>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.18.0/dist/axios.min.js"></script> <!-- ●←Axiosを読み込み -->
<script src="js/bitcoin.js"></script>
</body>
</html>
js/bitcoin.js
let app = new Vue({
el: '#app',
data: {
bpi: null,
hasError: false,
loading: true
},
mounted: function() {
axios.get('https://api.coindesk.com/v1/bpi/currentprice.json')
.then(function(response) {
// console.log(response);
// console.log(response.data.bpi);
//console.log(response.data.bpi.EUR.rate_float);
this.bpi = response.data.bpi;
}.bind(this)) // このクラスにバインド。bindで指定しないとthen()の中のthisがWindowオブジェクトを意味してしまう
.catch(function(error) {
console.log(error);
this.hasError = true;
}.bind(this))
.finally(function() { // 通信が全て終わった時に、loadingをfalseにする
this.loading = false;
}.bind(this))
},
filters: {
currencyDecimal(value) {
return value.toFixed(2);
}
}
})
Qiita App
index.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Real time search</title>
</head>
<body>
<div id="app">
<p>
<input type="text" v-model="keyword">
</p>
<p>
{{ message }}
</p>
<ul>
<li v-for="item in items">
<a v-bind:href="item.url">{{ item.title }}</a> Likes: {{ item.likes_count }}
</li>
</ul>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.18.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
<script src="js/main.js"></script>
</body>
</html>
js/main.js
var app = new Vue({
el: '#app',
data: {
items: null,
keyword: '',
message: ''
},
watch: {
keyword: function(newKeyword, oldKeyword) {
// console.log(newKeyword);
this.message = '入力が終わるのを待っています...';
this.debouncedGetAnswer();
}
},
created: function() {
this.keyword = 'JavaScript';
this.getAnswer();
this.debouncedGetAnswer = _.debounce(this.getAnswer, 1000)
},
methods: {
getAnswer: function() {
if(this.keyword === '') {
this.items = null;
this.message = '';
return;
}
this.message = 'Loading...';
var vm = this;
var params = { page: 1, per_page: 20, query: this.keyword }
axios.get('https://qiita.com/api/v2/items', { params} )
.then(function(response) {
vm.items = response.data;
console.log(response);
})
.catch(function(error) {
vm.message = 'Error! + error';
})
.finally(function() {
vm.message = '';
})
}
}
})
Vue-Cli
インストール
$ npm install -g @vue/cli
プロジェクト作成
$ vue create my-cli $ cd my-cli
ライブラリのインストール
$ vue add element $ vue add router $ vue add vuex
$ npm install -g @vue/cli-service-global
サーバ立ち上げ
$ npm run serve DONE Compiled successfully in 12040ms 22:47:27 App running at: - Local: http://localhost:8080/ - Network: http://192.168.11.2:8080/ Note that the development build is not optimized. To create a production build, run npm run build.

http://localhost:8080/
Vuex
Vuex 公式のサンプルアプリ
https://jsfiddle.net/n9jmu5v7/1269/
html
<div id="app">
<p>{{ count }}</p>
<p>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</p>
</div>
js
// make sure to call Vue.use(Vuex) if using a module system
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment: state => state.count++,
decrement: state => state.count--
}
})
new Vue({
el: '#app',
computed: {
count () {
return store.state.count
}
},
methods: {
increment () {
store.commit('increment')
},
decrement () {
store.commit('decrement')
}
}
})
モジュール
https://vuex.vuejs.org/ja/guide/modules.html
const moduleA = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: () => ({ ... }),
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> `moduleA` のステート
store.state.b // -> `moduleB` のステート
Udemyの講座やる
$ vue create udemy-vuejs $ npm run build $ npm run serve
main.js
import Vue from 'vue';
import App from './App.vue';
Vue.config.productionTip = false
console.log(App);
new Vue({
render: h => h(App),
}).$mount('#app');

Appオブジェクトが確認できた。
コンポーネント props, $emit
main.js
import Vue from 'vue';
import App from './App.vue';
Vue.config.productionTip = false
new Vue({
render: h => h(App),
}).$mount('#app');
App.vue
<template>
<div>
<LikeHeader :total-number="number"></LikeHeader>
<LikeNumber :total-number="number" @my-click="incrementNumber"></LikeNumber>
<LikeNumber :total-number="number"></LikeNumber>
</div>
</template>>
<script>
import LikeHeader from './components/LikeHeader.vue';
import LikeNumber from './components/LikeNumber.vue';
export default {
components: {
LikeHeader,
LikeNumber
},
data() {
return {
number: 10
}
},
methods: {
incrementNumber(value) {
this.number = value;
}
}
}
</script>
components/LikeHeader.vue
<template>
<div>
<h2>いいね{{ number() }}</h2>
</div>
</template>
<script>
export default {
props: ["totalNumber"],
methods: {
number() {
return this.totalNumber;
}
}
}
</script>>
<style scoped>
div {
border: 1px solid blue;
}
</style>>
components/LikeNumber.vue
<template>
<div>
<p>いいね{{ halfNumber }}
<button @click="increment">+1</button>
</p>
</div>
</template>
<script>
export default {
props: {
totalNumber: {
type: Number
}
},
computed: {
halfNumber() {
return this.totalNumber / 2;
}
},
methods:{
increment() {
//this.totalNumber += 1;
this.$emit("my-click", this.totalNumber + 1)
}
}
}
</script>
<style scoped>
div {
border: 1px solid red;
}
</style>>

