Vue.js 長い配列のdataをcreatedでスッキリ短く

Vue.jsプログラミング備忘録
https://jp.vuejs.org/からの画像

どうも、ちゃんカマでございます。

Vue.jsで同じコードの繰り返しで長くなったJavascriptの配列データを、スッキリと短く書く方法についてお調べですか?
それならVue.jsのcreated()やpush()を使えば、スッキリとしたコードを書くことが出来ますよ。

私はオリジナルの点数計算アプリを制作する過程で、Vue.jsのcreated()やpush()を使用しました。
その結果、同じコードの繰り返しで長かったJavascriptの配列データを、スッキリと短く書くことが出来ました。

今回はVue.jsのcreated()やpush()を使って、Javascriptの長い配列データをスッキリと短いコードで書く方法について解説します。

ちなみに私が作ったアプリはこんな感じです。( ↓ GIF動画参照)

点数計算アプリの動作の様子
点数計算アプリの動作の様子
この記事ではこんな疑問や悩みにお答えします
  • 繰り返しで長くなっている配列データを、短くスッキリと書きたい
  • Vue.jsのcreated()やpush()の使い方を知りたい
この記事の内容
  • 繰り返しで使用する配列データを、短くスッキリと書く方法
  • Vue.jsのcreated()やpush()の使用方法
  • 完成前と完成後のコードも記載しています
スポンサーリンク

完成前のコード【配列で指定しているdata()がとても長い】

完成前のコードを下記に記載します。
※ normalize.cssの掲載は割愛しています。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	
	<!-- Normalize CSS -->
	<link rel="stylesheet" href="normalize.css">
	
	<!-- BootStrap CSS -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">

	<!-- Style CSS -->
	<link rel="stylesheet" href="style.css">
	
	<!-- Vue.js(本番用) -->
	<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script> -->

	<!-- Vue.js(開発用) -->
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<table class="table table-bordered table-striped mt-3">
		<thead class="thead-light">
			<tr>
				<th class="col-sm"></th>
				<th class="col-lg">ゲート1</th>
				<th class="col-lg">ゲート2</th>
				<th class="col-lg">ゲート3</th>
				<th class="col-lg">ゲート4</th>
				<th class="col-lg">ゴール</th>
				<th class="col-md">総打数</th>
				<th class="col-md">加算点</th>
				<th class="col-md">Total</th>
			</tr>
		</thead>
		<tbody class="row-item" v-cloak>
			<tr
				v-for="(row, index) in rows"
				:key="index"				
			>
				<th class="col-sm">{{ row.name }}</th>
				<td>
					<counter-hit v-model="row.countGate1"></counter-hit>
					<hoop-in v-model="row.inGate1"></hoop-in>
				</td>
				<td>
					<counter-hit v-model="row.countGate2"></counter-hit>
					<hoop-in v-model="row.inGate2"></hoop-in>
				</td>
				<td>
					<counter-hit v-model="row.countGate3"></counter-hit>
					<hoop-in v-model="row.inGate3"></hoop-in>
				</td>
				<td>
					<counter-hit v-model="row.countGate4"></counter-hit>
					<hoop-in v-model="row.inGate4"></hoop-in>
				</td>
				<td>
					<counter-hit v-model="row.countGoal"></counter-hit>
					<hoop-in v-model="row.inGoal">ネットイン</hoop-in>
				</td>
				<td>
					<div class="sum">{{ sum(index) }}</div>
				</td>
				<td>
					<div class="addition">{{ addition(index) }}</div>
				</td>
				<td>
					<div class="total">{{ sum(index) + addition(index) }}</div>
				</td>
			</tr>
		</tbody>
	</table>

	<!-- Bootstrap JavaScript -->
	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>

	<!-- FontAwesome JavaScript -->
	<script defer src="https://use.fontawesome.com/releases/v5.7.2/js/all.js"></script>
	
	<!-- Main.js -->
	<script src="main.js"></script>
</body>
</html>
main.js
const counterHit = {
	props: ['value'],
  methods: {
		countUp() {
			this.$emit('input', this.value + 1);
		},
		countDown() {
			if ( this.value > 0 ) {
				this.$emit('input', this.value - 1);
			}
		},
	},
	template: `
		<form>
			打数
			<div class="form-group input-group">
				<div class="input-group-prepend">
					<button type="button" @click="countUp" class="btn btn-primary btn-up">+</button>
				</div>
				<input type="number" :value="value" min="0" disabled class="form-control">
				<div class="input-group-append">
					<button type="button" @click="countDown" class="btn btn-secondary btn-down">-</button>
				</div>
			</div>
		</form>
	`,
};

const hoopIn = {
	props: ['value'],
	methods: {
		check() {
			if(this.value === "") {
				this.$emit('input', "○");
			}
		},
		uncheck() {
			if(this.value === "○") {
				this.$emit('input', "");
			}
		},
	},
	template: `
		<form>
			<slot>フープイン</slot>
			<div class="form-group input-group">
				<div class="input-group-prepend">
					<button type="button" @click="check" class="btn btn-info btn-add">○</button>
				</div>
				<input type="text" :value="value" disabled class="form-control">
				<div class="input-group-append">
					<button type="button" @click="uncheck" class="btn btn-secondary btn-remove">☓</button>
				</div>
			</div>
		</form>
	`,
};

new Vue({
	el: '.row-item',
	data() {
		return {
			rows: [
				{
					name: 'Aさん',
					countGate1: 0,
					countGate2: 0,
					countGate3: 0,
					countGate4: 0,
					countGoal: 0,
					inGate1: "",
					inGate2: "",
					inGate3: "",
					inGate4: "",
					inGoal: "",
				},
				{
					name: 'Bさん',
					countGate1: 0,
					countGate2: 0,
					countGate3: 0,
					countGate4: 0,
					countGoal: 0,
					inGate1: "",
					inGate2: "",
					inGate3: "",
					inGate4: "",
					inGoal: "",
				},
				{
					name: 'Cさん',
					countGate1: 0,
					countGate2: 0,
					countGate3: 0,
					countGate4: 0,
					countGoal: 0,
					inGate1: "",
					inGate2: "",
					inGate3: "",
					inGate4: "",
					inGoal: "",
				},
				{
					name: 'Dさん',
					countGate1: 0,
					countGate2: 0,
					countGate3: 0,
					countGate4: 0,
					countGoal: 0,
					inGate1: "",
					inGate2: "",
					inGate3: "",
					inGate4: "",
					inGoal: "",
				},
				{
					name: 'Eさん',
					countGate1: 0,
					countGate2: 0,
					countGate3: 0,
					countGate4: 0,
					countGoal: 0,
					inGate1: "",
					inGate2: "",
					inGate3: "",
					inGate4: "",
					inGoal: "",
				},
				{
					name: 'Fさん',
					countGate1: 0,
					countGate2: 0,
					countGate3: 0,
					countGate4: 0,
					countGoal: 0,
					inGate1: "",
					inGate2: "",
					inGate3: "",
					inGate4: "",
					inGoal: "",
				},
			],
		};
	},
	methods: {
		sum(index) {
			return (
				this.rows[index].countGate1 +
				this.rows[index].countGate2 +
				this.rows[index].countGate3 +
				this.rows[index].countGate4 +
				this.rows[index].countGoal
			);
		},
		addition(index) {
			let additionGate1 = 0;
			let additionGate2 = 0;
			let additionGate3 = 0;
			let additionGate4 = 0;
			let additionGoal = 0;

			if(this.rows[index].countGate1 === 1 && this.rows[index].inGate1 === "○") {
				additionGate1 = -3;
			} else if(this.rows[index].countGate1 === 1) {
				additionGate1 = -2;
			} else if(this.rows[index].inGate1 === "○" && this.rows[index].countGate1 !== 0) {
				additionGate1 = -1;
			}
			
			if(this.rows[index].countGate2 === 1 && this.rows[index].inGate2 === "○") {
				additionGate2 = -3;
			} else if(this.rows[index].countGate2 === 1) {
				additionGate2 = -2;
			} else if(this.rows[index].inGate2 === "○" && this.rows[index].countGate2 !== 0) {
				additionGate2 = -1;
			}

			if(this.rows[index].countGate3 === 1 && this.rows[index].inGate3 === "○") {
				additionGate3 = -3;
			} else if(this.rows[index].countGate3 === 1) {
				additionGate3 = -2;
			} else if(this.rows[index].inGate3 === "○" && this.rows[index].countGate3 !== 0) {
				additionGate3 = -1;
			}

			if(this.rows[index].countGate4 === 1 && this.rows[index].inGate4 === "○") {
				additionGate4 = -3;
			} else if(this.rows[index].countGate4 === 1) {
				additionGate4 = -2;
			} else if(this.rows[index].inGate4 === "○" && this.rows[index].countGate4 !== 0) {
				additionGate4 = -1;
			}

			if(this.rows[index].countGoal === 1 && this.rows[index].inGoal === "○") {
				additionGoal = -4;
			} else if(this.rows[index].countGoal === 1) {
				additionGoal = -2;
			} else if(this.rows[index].inGoal === "○" && this.rows[index].countGoal !== 0) {
				additionGoal = -2;
			}

			return (
				additionGate1 + 
				additionGate2 +
				additionGate3 + 
				additionGate4 +
				additionGoal
			);
		},
	},
	components: {
		'counter-hit': counterHit,
		'hoop-in': hoopIn,
	},
});
style.css
@charset "UTF-8";

[v-cloak] {
	display: none;
}

body {
	min-width: 1024px;
	font-size: 18px;
	padding: 5px;
}

.col-sm {
	width: 8%;
}

.col-lg {
	width: 14%;
}

.col-md {
	width: 8%;
}

th {
	text-align: center;
}

.form-control {
	padding: 0;
	text-align: center;
}

input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

input[type="number"][disabled],
input[type="text"][disabled]{
	background-color: #fff;
}

.btn-up,
.btn-down,
.btn-add,
.btn-remove {
	width: 37px;
}

.table thead th {
	position: sticky;
	top: 0;
	z-index: 10;
}

.table tbody th {
	position: sticky;
	left: 0;
	z-index: 10;
	background-color: #eee;
}

.button-alert {
	font-size: 18px;
}

main.jsのコードが長いです。
コードが長い原因は、new Vueの中のdata()の箇所にあるかと思われます。
同じ内容のデータを配列で繰り返し指定しています。
また、methods()の箇所も改善出来るような気がします。

ちなみに上記のコードでページを表示すると、このようになります。

点数計算アプリの画像
スポンサーリンク

Vue.js の created() とは

Vue.js の created() については、下記の公式サイト内の「インスタンスライフサイクルフック」の項目が参考になるかと思います。

Vue インスタンス — Vue.js
Vue.js - The Progressive JavaScript Framework

例えば、created フックはインスタンスが生成された後にコードを実行したいときに使われます。

Vue.jsの公式サイトより抜粋

要するにcreated()は、Vueインスタンスが生成される度に実行される関数のようなものかと。

created()を使って配列データを指定する

完成前のコードでは、data()の中に1行目のAさんの配列データ、2行目のBさんの配列データ、3行目のCさんの配列データ・・・と、全ての行の配列データを指定していました。

data() {
	return {
		rows: [
			{
				name: 'Aさん',
				countGate1: 0,
				countGate2: 0,
				countGate3: 0,
				countGate4: 0,
				countGoal: 0,
				inGate1: "",
				inGate2: "",
				inGate3: "",
				inGate4: "",
				inGoal: "",
			},
			{
				name: 'Bさん',
				countGate1: 0,
				countGate2: 0,
				countGate3: 0,
				countGate4: 0,
				countGoal: 0,
				inGate1: "",
				inGate2: "",
				inGate3: "",
				inGate4: "",
				inGoal: "",
			},
			{
				name: 'Cさん',
				countGate1: 0,
				countGate2: 0,
				countGate3: 0,
				countGate4: 0,
				countGoal: 0,
				inGate1: "",
				inGate2: "",
				inGate3: "",
				inGate4: "",
				inGoal: "",
			},

// ーーーーーーーー 省略 ーーーーーーーー

			},
		],
	};
},

これがコードが長くなっていた原因ですね。
そこで配列データを全て指定するのではなく、created()を使ってVueインスタンスが生成される度に、新たに配列データを指定するコードを書いてみたいと思います。

まずはmain.jsのnew Vueのdata()の箇所を、下記のとおりに書き換えます。

main.js
// ーーーーー 以上は省略 ーーーーー

new Vue({
	el: '.row-item',
	data() {
		return {
			rows: [],
		};
	},

// ーーーーー 以下は省略 ーーーーー

配列「rows」の中に、全ての行のデータをガチガチで指定していたのをやめて、中身を空っぽにしました。

rows: [],

rowsという名前の、中身が空っぽな配列の箱を作ったイメージですね。

次はcreated()を使って、中身が空っぽのrowsに配列データを指定するコードを書きます。
main.jsを下記のとおりに書き換えます。

main.js
// ーーーーー 以上は省略 ーーーーー

new Vue({
	el: '.row-item',
	data() {
		return {
			rows: [],
		};
	},
	created() {
		for (const name of 'ABCDEF') {
			this.rows.push({
				name,
				scores: {
					gate1: { count: 0, in: "" },
					gate2: { count: 0, in: "" },
					gate3: { count: 0, in: "" },
					gate4: { count: 0, in: "" },
					goal: { count: 0, in: "" },
				}
			});
		}
	},

// ーーーーー 以下は省略 ーーーーー

new Vueの中にcreated()を書いています。
順に解説します。

for (const name of 'ABCDEF')

上記のコードでループを回しています。
変数nameにA〜Fの文字を代入し、forでループを回しています。
Aさん〜Fさんまでのデータを繰り返し書くのではなく、ループで処理していくんですね。

では、ループ処理の中身をみていきます。

this.rows.push

thisはnew Vueで生成されるVueインスタンスのことです。
rowsは先程指定した、中身が空っぽな配列の箱です。
push()で配列にデータを追加することが出来ます。
つまりthis.rows.push()で、空っぽな配列の箱rowsに新たにデータを追加しています。

では、追加するデータの中身をみていきます。

name,
scores: {
	gate1: { count: 0, in: "" },
	gate2: { count: 0, in: "" },
	gate3: { count: 0, in: "" },
	gate4: { count: 0, in: "" },
	goal: { count: 0, in: "" },
}

追加するデータの中身は、上記のコードになります。
nameはconst nameの中の値、つまりA〜Fの文字になります。

scoresの中にgate1〜4とgoalを追加し、それぞれの値としてcount: 0とin: “”を与えています。
これでAさんからFさんまでの6行分のデータを、1つのコードで指定することが出来ました。
例えばrow.scores.gate1.countは、ゲート1の打数の値になります。
同じようにrow.scores.gate1.inは、フープインの値になります。

HTMLを書き換える

created()で指定した配列データを表示させるため、HTMLを書き換えます。
index.htmlの<tbody></tbody>内を、下記のとおりに書き換えます。

index.html
<!-- 以上は省略 -->

<tbody class="row-item" v-cloak>
	<tr
		v-for="(row, index) in rows"
		:key="index"				
	>
		<th class="col-sm">{{ row.name }}さん</th>
		<td>
			<counter-hit v-model="row.scores.gate1.count"></counter-hit>
			<hoop-in v-model="row.scores.gate1.in"></hoop-in>
		</td>
		<td>
			<counter-hit v-model="row.scores.gate2.count"></counter-hit>
			<hoop-in v-model="row.scores.gate2.in"></hoop-in>
		</td>
		<td>
			<counter-hit v-model="row.scores.gate3.count"></counter-hit>
			<hoop-in v-model="row.scores.gate3.in"></hoop-in>
		</td>
		<td>
			<counter-hit v-model="row.scores.gate4.count"></counter-hit>
			<hoop-in v-model="row.scores.gate4.in"></hoop-in>
		</td>
		<td>
			<counter-hit v-model="row.scores.goal.count"></counter-hit>
			<hoop-in v-model="row.scores.goal.in">ネットイン</hoop-in>
		</td>
		<td>
			<div class="sum">{{ sum(index) }}</div>
		</td>
		<td>
			<div class="addition">{{ addition(index) }}</div>
		</td>
		<td>
			<div class="total">{{ sum(index) + addition(index) }}</div>
		</td>
	</tr>
</tbody>

<!-- 以下は省略 -->

v-modelの値を、先程の配列のデータに書き換えています。

<counter-hit v-model="row.scores.gate1.count"></counter-hit>
<hoop-in v-model="row.scores.gate1.in"></hoop-in>

しかし、この時点でページを表示させてもダメです。正常に表示されません。
なぜならsum(index)やaddition(index)を、まだ書き換えていないからです。

methodsも書き換える

では、methodsのsum(index)やaddition(index)も書き換えていきます。
まずはsum(index)から。
main.jsを下記のとおりに書き換えます。

main.js
// ーーーーー 以上は省略 ーーーーー

methods: {
	sum(index) {
		let sumValue = 0;
	
		const row = this.rows[index];
		
		for (const key in row.scores) {
			sumValue += row.scores[key].count;
		}
		
		return sumValue;
	},

// ーーーーー 以下は省略 ーーーーー

上記のコードを順に解説します。

変数sumValueを作成し、初期値0を代入しています。

let sumValue = 0;

変数rowに各行のデータ(scoresの中身)を代入しています。
[index]を指定することで、何行目のデータなのか(何行目のscoresなのか)を判別しています。

const row = this.rows[index];

変数keyにscoresの中のプロパティ(gate1〜4とgoal)を代入しています。
このkeyの数だけ、ループ処理を行っています。
つまり、keyの中身はgate1・・・gate2・・・と順に値が代入され、最後のgoalまでループ処理が行われます。
ゲート1からゴールまでの間のループ処理になります。

ループ処理の中身は、打数の合計を求める式です。
変数sumValueに打数の値countを順番に足していっています。
gate1のcount・・・gate2のcount・・・と順番に足していき、最後のgoalのcountまで足し算が行われます。

for (const key in row.scores) {
	sumValue += row.scores[key].count;
}

最後に、合計が計算されたsumValueの値を返しています。
これが無いと合計の計算はされていても、その値をページに表示することが出来ません。

return sumValue;

次はaddition(index)を書き換えます。
main.jsを下記のとおりに書き換えます。

main.js
// ーーーーー 以上は省略 ーーーーー

methods: {
	sum(index) {
		let sumValue = 0;
	
		const row = this.rows[index];
		
		for (const key in row.scores) {
				sumValue += row.scores[key].count;
		}
		
		return sumValue;
	},
	addition(index) {
		let additionalValue = 0;
		const row = this.rows[index];
		for (const key in row.scores) {
			const gate = row.scores[key];
			if (gate.count === 1 && gate.in) {
				additionalValue -= key === 'goal' ? 4 : 3;
			} else if (gate.count === 1) {
				additionalValue -= 2;
			} else if (gate.in && gate.count !== 0) {
				additionalValue -= key === 'goal' ? 2 : 1;
			}
		}
		
		return additionalValue;
	},
},

// ーーーーー 以下は省略 ーーーーー

sum(index)の下にaddition(index)のメソッドを書いています。
上記のコードを順に解説します。

変数additionalValueを作成し、初期値0を代入。
変数rowに各行のデータ(scoresの中身)を代入。

let additionalValue = 0;
const row = this.rows[index];

sum(index)と同じように、ゲート1からゴールまでの間でループ処理を行っています。

for (const key in row.scores)

ループ処理の中身を解説します。
変数gateにrow.scoresのプロパティを代入しています。
[key]を指定することで、どのプロパティなのか(gate1なのか・・・gate2なのか・・・)を判別出来ます。

const gate = row.scores[key];

後はif文で、加算点が得られる条件式を書いています。

最初の条件式は「打数が1で、さらにフープインも◯の時は」という意味になります。

if (gate.count === 1 && gate.in)

この条件に該当する場合、「keyがgoalなら変数additionalValueを−4、keyがgoal以外なら変数additionalValueを−3する」という計算式になります。
ここでは「条件式 ? 条件に該当するとき(true)の処理 : 条件に該当しないとき(false)の処理」という、JavaScriptの三項演算子を使っています。

additionalValue -= key === 'goal' ? 4 : 3;

else if 以降の条件式も、同じように三項演算子を用いて書いています。

最後に、加算点が計算されたadditionalValueの値を返しています。

return additionalValue;

これで完成です。

完成後のコード

完成後のコードを下記に記載します。
※ normalize.cssの掲載は割愛しています。

index.html
<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	
	<!-- Normalize CSS -->
	<link rel="stylesheet" href="normalize.css">
	
	<!-- BootStrap CSS -->
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">

	<!-- Style CSS -->
	<link rel="stylesheet" href="style.css">
	
	<!-- Vue.js(本番用) -->
	<!-- <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"></script> -->

	<!-- Vue.js(開発用) -->
	<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
	<table class="table table-bordered table-striped mt-3">
		<thead class="thead-light">
			<tr>
				<th class="col-sm"></th>
				<th class="col-lg">ゲート1</th>
				<th class="col-lg">ゲート2</th>
				<th class="col-lg">ゲート3</th>
				<th class="col-lg">ゲート4</th>
				<th class="col-lg">ゴール</th>
				<th class="col-md">総打数</th>
				<th class="col-md">加算点</th>
				<th class="col-md">Total</th>
			</tr>
		</thead>
		<tbody class="row-item" v-cloak>
			<tr
				v-for="(row, index) in rows"
				:key="index"				
			>
				<th class="col-sm">{{ row.name }}さん</th>
				<td>
					<counter-hit v-model="row.scores.gate1.count"></counter-hit>
					<hoop-in v-model="row.scores.gate1.in"></hoop-in>
				</td>
				<td>
					<counter-hit v-model="row.scores.gate2.count"></counter-hit>
					<hoop-in v-model="row.scores.gate2.in"></hoop-in>
				</td>
				<td>
					<counter-hit v-model="row.scores.gate3.count"></counter-hit>
					<hoop-in v-model="row.scores.gate3.in"></hoop-in>
				</td>
				<td>
					<counter-hit v-model="row.scores.gate4.count"></counter-hit>
					<hoop-in v-model="row.scores.gate4.in"></hoop-in>
				</td>
				<td>
					<counter-hit v-model="row.scores.goal.count"></counter-hit>
					<hoop-in v-model="row.scores.goal.in">ネットイン</hoop-in>
				</td>
				<td>
					<div class="sum">{{ sum(index) }}</div>
				</td>
				<td>
					<div class="addition">{{ addition(index) }}</div>
				</td>
				<td>
					<div class="total">{{ sum(index) + addition(index) }}</div>
				</td>
			</tr>
		</tbody>
	</table>

	<!-- Bootstrap JavaScript -->
	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>

	<!-- FontAwesome JavaScript -->
	<script defer src="https://use.fontawesome.com/releases/v5.7.2/js/all.js"></script>
	
	<!-- Main.js -->
	<script src="main.js"></script>
</body>
</html>
main.js
const counterHit = {
	props: ['value'],
  methods: {
		countUp() {
			this.$emit('input', this.value + 1);
		},
		countDown() {
			if ( this.value > 0 ) {
				this.$emit('input', this.value - 1);
			}
		},
	},
	template: `
		<form>
			打数
			<div class="form-group input-group">
				<div class="input-group-prepend">
					<button type="button" @click="countUp" class="btn btn-primary btn-up">+</button>
				</div>
				<input type="number" :value="value" min="0" disabled class="form-control">
				<div class="input-group-append">
					<button type="button" @click="countDown" class="btn btn-secondary btn-down">-</button>
				</div>
			</div>
		</form>
	`,
};

const hoopIn = {
	props: ['value'],
	methods: {
		check() {
			if(this.value === "") {
				this.$emit('input', "○");
			}
		},
		uncheck() {
			if(this.value === "○") {
				this.$emit('input', "");
			}
		},
	},
	template: `
		<form>
			<slot>フープイン</slot>
			<div class="form-group input-group">
				<div class="input-group-prepend">
					<button type="button" @click="check" class="btn btn-info btn-add">○</button>
				</div>
				<input type="text" :value="value" disabled class="form-control">
				<div class="input-group-append">
					<button type="button" @click="uncheck" class="btn btn-secondary btn-remove">☓</button>
				</div>
			</div>
		</form>
	`,
};

new Vue({
	el: '.row-item',
	data() {
		return {
			rows: [],
		};
	},
	created() {
		for (const name of 'ABCDEF') {
			this.rows.push({
				name,
				scores: {
					gate1: { count: 0, in: "" },
					gate2: { count: 0, in: "" },
					gate3: { count: 0, in: "" },
					gate4: { count: 0, in: "" },
					goal: { count: 0, in: "" },
				}
			});
		}
	},
	methods: {
		sum(index) {
			let sumValue = 0;
		
			const row = this.rows[index];
			
			for (const key in row.scores) {
				sumValue += row.scores[key].count;
			}
			
			return sumValue;
		},
		addition(index) {
			let additionalValue = 0;

			const row = this.rows[index];

			for (const key in row.scores) {
				const gate = row.scores[key];
				if (gate.count === 1 && gate.in === "○") {
					additionalValue -= key === 'goal' ? 4 : 3;
				} else if (gate.count === 1) {
					additionalValue -= 2;
				} else if (gate.in === "○" && gate.count !== 0) {
					additionalValue -= key === 'goal' ? 2 : 1;
				}
			}
			
			return additionalValue;
		},
	},
	components: {
		'counter-hit': counterHit,
		'hoop-in': hoopIn,
	},
});

style.cssに変更はありません。

上記のコードでページを表示させてみます。( ↓ GIF動画参照)

点数計算アプリの動作の様子
ページの表示や動作に問題は無い

完成後のコードでも、ページの表示やアプリの動作に問題はありません。

おわりに

Vue.jsで、長くなったJavascriptの配列データを、スッキリと短く書く方法について解説しました。
created()やpush()を使って書くことが出来ました。

今回の記事が皆さんの参考になれば幸いです。
以上、ちゃんカマでした。

コメント

タイトルとURLをコピーしました