最近有一个需求:
表单中有3个多选框,而他们的选项是一样的,但是如果其中一个选项被选择之后,在另外2个多选框里面就不能再选了。
这样的问题,让我想到了“将乒乓球放入不同盒子”的例子。
上代码
// 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>乒乓球放入不同的盒子(选项互斥)</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;
}
每个ball
对象都有一个category
属性,用来表示它属于哪个盒子。然后在渲染的时候,根据category
来计算使用的类名。