0基础从前端到Web3 —— Mine Clearance Frontend(一)

初始化项目以及通过dapp-kit连接钱包的部分就不再赘述,具体可以点击查看,如果篇幅当中遇到了一些未添加的依赖项,直接通过pnpm add -D <name>一般都可以解决。

一:链上网络切换

这里提供一个最简单的切换方式,不需要放置下拉框,也不需要添加任何其它更多的设置,只需要在调用SuiClientProvider的时候增加一个参数onNetworkChange={(network) => setNetwork(network)},它的作用是当Sui钱包插件改变链上网络的时候触发setNetwork方法,并将新的链上网络传入设置。

tsx 复制代码
function App() {
	const queryClient = new QueryClient();
	const [network, setNetwork] = React.useState("testnet");
	const networks = {
		testnet: { url: getFullnodeUrl('testnet') },
		mainnet: { url: getFullnodeUrl('mainnet') },
	};

	return (
		<div>
			<QueryClientProvider client={queryClient}>
				<SuiClientProvider networks={networks} network={network as keyof typeof networks} onNetworkChange={(network) => setNetwork(network)}>
					<WalletProvider>
						<div className='ConnectButton'>
							<ConnectButton />
						</div>
						<MineClearance />
						<FeedBack />
					</WalletProvider>
				</SuiClientProvider>
			</QueryClientProvider>
		</div>
	);
}

二:游戏区域

首先是一个开始游戏的按钮,它的运行逻辑要在连接钱包之后,因为后面与链上的交互都需要事先明确"我是谁"。

tsx 复制代码
function MineClearance() {
	const account = useCurrentAccount();

	const StartGame = () => {
		document.getElementById('NotConnect')!.hidden = true;

		if (!account) {
			document.getElementById('NotConnect')!.hidden = false;
			return;
		}

		// console.log("Connected");
		return;
	};

	return (
		<div className='Game'>
			<div className='StartButton'>
				<Button variant="contained" onClick={StartGame}>Game</Button>
				<br></br>
				<i id="NotConnect" hidden={true}>Please Connect First!!!</i>
			</div>
			<div id='Checkerboard'>
				<DrawCheckerboard />
			</div>
		</div>
	);
}

其次我们来考虑扫雷区域该如何进行描绘,很自然联想到,它是由一个又一个小方块依次拼接而成的,而mui正好又提供了一系列的ButtonGroup,所以问题就简化成了如何通过循环进行处理这些个按钮,包括放置、点击以及后续得到反馈后实时更改按钮状态等等。

本篇只涉及放置以及最基本的点击逻辑,而链上调用以及反馈信息处理等部分将留到下一篇文章。

tsx 复制代码
function DrawCheckerboard() {
	const clickBoard = (event: any) => {
		const r = event.target.getAttribute('button-key')
		const l = event.target.parentElement.getAttribute('button-key');
		console.log(`(${r}, ${l})`);

		let str1 = event.currentTarget.innerHTML.split('<', 1)[0];
		const str2 = event.currentTarget.innerHTML.substring(str1.length);
		str1 = str1 == "x" ? "1" : "x";
		const str = str1.concat(str2);
		console.log(str);
		event.currentTarget.innerHTML = str;

		event.target.disabled = true;

		HiddenFeedBack();
		ShowFeedBack("circular_progress");
		// ShowFeedBack("success_alert");
		// ShowFeedBack("encourage_alert");
		// ShowFeedBack("failure_alert");
	}

	const childboard = [];
	let i = 1;
	while (i <= MaxRow) {
		childboard.push(<Button key={i} button-key={i} size="large" onClick={clickBoard} sx={{width: "1px"}}>&nbsp;</Button>);
		i += 1;
	}

	const checkerboard = [];
	let j = 1;
	while (j <= MaxList) {
		checkerboard.push(<ButtonGroup orientation='vertical' aria-label='Vertical button group' variant='outlined' key={j} button-key={j}>{childboard}</ButtonGroup>);
		j += 1;
	}

	return (
		<Box>
			{checkerboard}
		</Box>
	);
}

三:提示信息

mui提供了加载等待、成功失败提示等ui选择,我们直接选取其中的一些进行调用,目的是当后续实现了链上调用后的信息反馈,包括但不限于游戏成功、游戏失败等提示信息。

这些信息出现的位置应当是游戏区域下方,而且若非特殊需求,应当一次只出现一个,其它的都应该隐藏,这里就需要令写函数对这系列的<div>标签进行统一管理。

tsx 复制代码
function FeedBack() {
	return (
		<div className='FeedBack'>
			<div id="circular_progress" hidden={true}>
				<CircularProgress />
			</div>
			<div id="success_alert" className='SuccessAlert' hidden={true}>
				<Alert variant="outlined" severity="success">
					Congratulations on your successful mine clearance!
				</Alert>
			</div>
			<div id="encourage_alert" className='EncourageAlert' hidden={true}>
				<Alert variant="outlined" severity="info">
					Fortunately you didn't touch a landmine, please consider your next step!
				</Alert>
			</div>
			<div id="failure_alert" className='FailureAlert' hidden={true}>
				<Alert variant="outlined" severity="error">
					Unfortunately, the minesweeper failed!
				</Alert>
			</div>
		</div>
	);
}

function ShowFeedBack(id: string) {
	// document.getElementById(id)!.hidden = false;
	if (id == "circular_progress")
		document.getElementById(id)!.hidden = false;
	else
		document.getElementById(id)!.style.display = "inline-flex";
}

function HiddenFeedBack() {
	document.getElementById("circular_progress")!.hidden = true;
	// document.getElementById("success_alert")!.hidden = true;
	// document.getElementById("encourage_alert")!.hidden = true;
	// document.getElementById("failure_alert")!.hidden = true;
	document.getElementById("success_alert")!.style.display = "none";
	document.getElementById("encourage_alert")!.style.display = "none";
	document.getElementById("failure_alert")!.style.display = "none";
}

这里的实现方式多样,呈现的只是其中一种也绝非是最优解,毕竟自己看着都有点累赘(后面可能会视情况更改)。

四:其它

完整代码可以点击查看,下面是几张实际运行图。

五:加入组织,共同进步!

相关推荐
卸任8 小时前
Vibe coding工具使用心得
前端·ai编程
brien98 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance9 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M9 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写9 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李9 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易9 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马9 小时前
前沿视界
前端
kyriewen9 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易9 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员