效果
demo:viewweiwu.github.io/light/
code:github.com/viewweiwu/l…
classDiagram
Animal <|-- Duck
Animal <|-- Fish
Animal <|-- Zebra
Animal : +int age
Animal : +String gender
Animal: +isMammal()
Animal: +mate()
class Duck{
+String beakColor
+swim()
+quack()
}
class Fish{
-int sizeInFeet
-canEat()
}
class Zebra{
+bool is_wild
+run()
}
规则
- 9 盏灯,分为点亮和不点亮,白色不点亮,蓝色点亮。
- 点击任意一盏灯,不仅本身会取反,上下左右的灯也会取反,点亮的会变成不点亮,不点亮的会点亮。
- 所有的灯都被点亮即胜利。
- 开场随机点亮灯。
实现思路
定义数据格式
let list = [
[0, 1, 0],
[0, 0, 0],
[0, 1, 1]
]
这里使用了二维数组,就如同界面所展示的一样,3 行 3 列。另外用 0 表示关,1 表示开。
数据渲染
已经定义好数据格式,渲染就非常容易了。
list.map((row, i) =>
row.map((item, j) =>
<span key={ `${i}-${j}` } onClick={ () => handleClick(i, j) } className={`item ${item ? 'active' : ''}`}></span>
)
)
事件绑定
给每一个开关绑定上单击事件。 先需要给开关取反工作,这里用了个小技巧,用取反的运算符。
1 ^ 0 // 1
1 ^ 1 // 0
这样子就可以给开关取反了。
const toggleItem = (newList, i, j) => {
newList[i][j] = 1^newList[i][j]
}
之后给除了本身之外的,上下左右四个方向取反就 ok 了。
胜利校验
校验胜利非常简单,只要判断 list 所有的数据全是 1,即是胜利。用 for 循环是方便中断循环,forEach,every 循环都不能中断。
const checkList = (newList) => {
for (let i = 0; i < newList.length; i++) {
for (let j = 0; j < newList[i].length; j++) {
if (newList[i][j] === 0) {
return false
}
}
}
return true
}
另外就是触发校验的时机了。react hook 里面可以用 useEffect 来保证数据渲染完成后触发事件。那么这里就使用这种方式。第二个参数表示要监测的参数变化。
useEffect(() => {
let result = checkList(list)
if (result) {
alert('win')
}
}, [list])
开局
刚开始定义的数据,所有的开关都是 0 || 1 ,让每次开局都是不一样的.
const getRandom = (min, max) => {
return Math.floor(Math.random() * 2)
}
const getRandomData = () => {
let list = []
for (let i = 0; i < 3; i++) {
let row = []
for (let j = 0; j < 3; j++) {
row.push(getRandom())
}
list.push(row)
}
return list
}
总结
- react hook 相比以前 ReactComponent 会减少很多的定义。
- react hook 里没有 setState,所以也没有 setState 后的回调,需要用 useEffect 替代实现。
- 开关取反可以使用 ^ 运算符,可以很方便让数字的取反。
- 使用跟画面一一对应的数据格式,后面操作思路会清晰很多。