Form options mutual exclusion (vue)

Keywords: Front-end Vue IE Attribute

There is a demand recently:
There are three multi selection boxes in the form, and their options are the same. However, if one of them is selected, it cannot be selected in the other two multi selection boxes.
Such a question reminds me of the example of "putting table tennis in different boxes".

Upper code

// index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>

        <link rel="stylesheet" href="./styles.css" />
        <script src="https://cdn.bootcss.com/vue/2.6.5/vue.min.js"></script>
    </head>
    <body>
        <div id="app">
            <p>Table tennis in different boxes (options are mutually exclusive)</p>
            <div class="ping-pong-list">
                <span
                    v-for="ball in ballList"
                    :key="ball.id"
                    :class="ball.className"
                    @click="onBallClick(ball.id)"
                    v-text="ball.id"
                ></span>
            </div>

            <div class="box-wrapper">
                <div
                    v-for="(category,index) in categories"
                    :key="index"
                    :class="['box', category, currCategory === category ? 'active' : null]"
                    @click="onBoxClick(category)"
                >
                    <span
                        v-for="ball in ballList"
                        :key="ball.id"
                        :class="ball.className"
                        v-show="ball.category === category"
                        v-text="ball.id"
                    ></span>
                </div>
            </div>
        </div>

        <script src="./main.js"></script>
    </body>
</html>
// main.js

const balls = Array(12)
    .fill(undefined)
    .map((v, i) => ({ id: i < 9 ? `0${i + 1}` : i + 1, category: null }))

const vm = new window.Vue({
    el: "#app",

    data: () => ({
        msg: "hahahhaha",
        balls,
        categories: ["red", "green", "blue"],
        currCategory: "red"
    }),

    computed: {
        ballList() {
            return this.balls.map(v => {
                let className = ["ping-pong-ball"]
                if (v.category) {
                    className.push(v.category)
                    if (v.category !== this.currCategory) {
                        className.push("disable")
                    }
                }
                return { ...v, className }
            })
        }
    },

    methods: {
        onBoxClick(category) {
            if (category !== this.currCategory) {
                this.currCategory = category
            }
        },

        onBallClick(id) {
            const ball = this.balls.find(v => v.id === id)
            if (ball) {
                ball.category = ball.category ? null : this.currCategory
            }
        }
    }
})
// styles.css

#app {
    user-select: none;
}

.ping-pong-list {
    display: flex;
    margin: 20px;
    justify-content: center;
    flex-wrap: wrap;
}

.ping-pong-ball {
    width: 50px;
    height: 50px;
    margin: 5px;
    border-radius: 50%;
    box-shadow: 0 0 10px 0 #aaa;
    text-align: center;
    line-height: 50px;
}

.ping-pong-list .ping-pong-ball {
    cursor: pointer;
}

.box-wrapper {
    display: flex;
    justify-content: space-around;
    margin-top: 30px;
}

.box {
    display: flex;
    align-content: flex-start;
    flex-wrap: wrap-reverse;
    width: 300px;
    height: 200px;
    border: 10px solid;
    border-top-width: 0;
    cursor: pointer;
    transition: all 0.25s;
}

.box.red {
    border-color: rgb(238, 97, 97);
}

.box.green {
    border-color: rgb(97, 238, 156);
}

.box.blue {
    border-color: rgb(97, 146, 238);
}

.box.active {
    box-shadow: 0 10px 20px 0 #aaa;
}

.ping-pong-ball.red,
.box.red .ping-pong-ball {
    background-color: rgb(238, 97, 97);
}

.ping-pong-ball.green,
.box.green .ping-pong-ball {
    background-color: rgb(97, 238, 156);
}

.ping-pong-ball.blue,
.box.blue .ping-pong-ball {
    background-color: rgb(97, 146, 238);
}

.ping-pong-ball.disable {
    opacity: 0.25;
    pointer-events: none;
}

Each ball object has a Category attribute that indicates which box it belongs to. Then, when rendering, the class name used is calculated according to category.

Posted by bugsuperstar37 on Sun, 01 Dec 2019 10:25:01 -0800