React中如何根据下拉框选中值触发对应函数?
解决React下拉框选中值触发对应球员绘制函数的问题
核心思路
先维护好下拉框选中的球员类型状态,再把不同球员的绘制逻辑封装成独立函数,用映射对象将球员类型和对应绘制函数关联起来。当画布被点击时,根据当前选中的球员类型调用对应的绘制函数即可。
完整实现代码
import { useState, useRef, useEffect } from 'react'; const TacticalDraw = () => { // 维护选中的球员类型状态 const [selectedPlayer, setSelectedPlayer] = useState("Player 1"); const [players, setPlayers] = useState([]); const [addingPlayer, setAddingPlayer] = useState(false); const canvasRef = useRef(null); // 下拉框变更事件:更新选中的球员类型 const handlePlayerChange = (e) => { setSelectedPlayer(e.target.value); }; // 不同球员的绘制逻辑函数 const drawPlayer1 = (ctx, x, y) => { // Player 1:红色圆形球员标记 ctx.fillStyle = "#ff0000"; ctx.beginPath(); ctx.arc(x, y, 15, 0, Math.PI * 2); ctx.fill(); }; const drawPlayer2 = (ctx, x, y) => { // Player 2:蓝色方形球员标记 ctx.fillStyle = "#0000ff"; ctx.fillRect(x - 15, y - 15, 30, 30); }; const drawPlayer3 = (ctx, x, y) => { // Player 3:绿色三角形球员标记 ctx.fillStyle = "#00ff00"; ctx.beginPath(); ctx.moveTo(x, y - 15); ctx.lineTo(x + 15, y + 15); ctx.lineTo(x - 15, y + 15); ctx.closePath(); ctx.fill(); }; // 球员类型与绘制函数的映射表 const playerDrawMap = { "Player 1": drawPlayer1, "Player 2": drawPlayer2, "Player 3": drawPlayer3 }; // 画布点击事件:处理球员添加与绘制 const handleCanvasClick = (event) => { if (!addingPlayer || !canvasRef.current) return; const rect = canvasRef.current.getBoundingClientRect(); const x = event.clientX - rect.left; const y = event.clientY - rect.top; const ctx = canvasRef.current.getContext("2d"); // 创建新球员数据 const newPlayer = { x, y, id: players.length + 1, playerType: selectedPlayer }; // 调用对应球员的绘制函数 const drawFunc = playerDrawMap[selectedPlayer]; drawFunc && drawFunc(ctx, x, y); // 更新球员列表状态 setPlayers(prev => [...prev, newPlayer]); }; // 监听球员列表变化,重绘所有球员 useEffect(() => { if (!canvasRef.current) return; const ctx = canvasRef.current.getContext("2d"); // 清空画布 ctx.clearRect(0, 0, canvasRef.current.width, canvasRef.current.height); // 重绘所有已添加的球员 players.forEach(player => { const drawFunc = playerDrawMap[player.playerType]; drawFunc && drawFunc(ctx, player.x, player.y); }); }, [players]); return ( <div> {/* 球员选择下拉框 */} <div> <label>Players: </label> <select value={selectedPlayer} onChange={handlePlayerChange}> <option value="Player 1">Player 1</option> <option value="Player 2">Player 2</option> <option value="Player 3">Player 3</option> </select> {/* 切换添加球员状态的按钮 */} <button onClick={() => setAddingPlayer(prev => !prev)}> {addingPlayer ? "停止添加球员" : "开始添加球员"} </button> </div> {/* 战术画布 */} <canvas ref={canvasRef} width={800} height={600} style={{ border: "1px solid #333", marginTop: "10px" }} onClick={handleCanvasClick} /> </div> ); }; export default TacticalDraw;
关键细节说明
- 状态管理:
selectedPlayer存储当前选中的球员类型,handlePlayerChange负责同步下拉框选中值到状态中。 - 映射表优势:用
playerDrawMap替代繁琐的if-else判断,后续新增球员类型时,只需添加对应的绘制函数和映射项即可,扩展性更强。 - 画布交互:点击画布时,先计算相对画布的坐标,再根据当前选中的球员类型调用对应绘制函数,同时将新球员数据加入状态。
- 重绘同步:通过
useEffect监听players状态变化,每次状态更新时清空画布并重绘所有球员,保证画布内容与状态完全同步。
内容的提问来源于stack exchange,提问作者Thoss
相关产品推荐
相关产品推荐

