kama0244
@kama0244 (カマ ちゃん)

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

【初心者です】Vue.js data()を配列で定義する時のpush()の使い方について

Q&A

Closed

解決したいこと

点数計算アプリを制作しました。
アプリ自体は意図通りに動作しています。

ただし、コードが長くてスッキリしていないと思っています。
データを配列で定義する箇所が、特に気になります。
(Vueインスタンスのdata()内の配列rowsの箇所)
もっとスッキリしたコードで書ける方法を教えていただきたいです。

上記の箇所以外でも、改善出来る箇所があれば教えていただきたいです。

※該当するソースコードにはCSSが適用されていないので、表示が崩れています。

該当するソースコード

<!-- HTML -->
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">

    <!-- Vue.js(開発用) -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
    <table class="table table-bordered table-striped">
        <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">
            <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>

    <!-- Test.js -->
    <script src="test.js"></script>
</body>
</html>

// JavaScript
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" v-model="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: {
        add() {
            if(this.value === "") {
                this.$emit('input', "");
            }
        },
        remove() {
            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="add" class="btn btn-info btn-add">○</button>
                </div>
                <input type="text" v-model="value" disabled class="form-control">
                <div class="input-group-append">
                    <button type="button" @click="remove" 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,
    },
});

自分で試したこと

push()を使って、配列を足していく方法があるそうですが、具体的にどのように書けば良いのか分かりませんでした。

0

1Answer

<!-- HTML -->
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">

    <!-- Vue.js(開発用) -->
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

    <style>
        [v-cloak] { display: none; }
    </style>
</head>
<body>
    <table id="app" class="table table-bordered table-striped" v-cloak>
        <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">
            <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>

    <!-- Test.js -->
    <script src="test.js"></script>
</body>
</html>
test.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" 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() {
            this.$emit('input', true);
        },
        uncheck() {
            this.$emit('input', false);
        },
    },
    computed: {
        displayValue() {
            if ( this.value ) {
                return '';
            } else {
                return '';
            }
        },
    },
    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="displayValue" 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: '#app',
    data() {
        return {
            rows: [],
        };
    },
    created() {
        for (const name of 'ABCDEF') {  // for (const name of ['A', 'B', 'C', 'D', 'E', 'F']) { と一緒
            this.rows.push({
                name,
                scores: {
                    gate1: { count: 0, in: false },
                    gate2: { count: 0, in: false },
                    gate3: { count: 0, in: false },
                    gate4: { count: 0, in: false },
                    goal: { count: 0, in: false },
                }
            });
        }
    },
    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,
    },
});

気になるところを直すとこんな感じでしょうか。

created(Vueインスタンスが生成された直後に実行されるフック)内でrowsの内容を生成して、その他細かいところをちょこちょこと。

1Like

Comments

  1. @kama0244

    Questioner

    うお! すごい!!
    同じ動作をするプログラムでも、ここまでコードが違うのか・・・。

    特に、crated()の中身は私が分からなかった部分で、とても勉強になります。
    その他の変更箇所も、私とは違うコードでスッキリしててメンテもしやすそう。
    時間をかけて、全ての変更箇所を勉強し直します。

    ありがとうございました。

Your answer might help someone💌