// 解决 IE 和非 IE 浏览器在事件绑定方面的兼容性 function addEventHandler(elem, event, handler) { if (elem.addEventListener) { elem.addEventListener(event, handler, false); } else if (elem.attachEvent) { elem.attachEvent("on" + event, handler); } else { elem["on" + event] = handler; } } // 以下关于 css 前缀的处理方法借鉴自 jQuery :jquery-3.1.0.js function getProperName(cssPropertyName) { var name = cssPropertyName; var cssPrefixes = ["Webkit", "Moz", "ms"]; var emptyStyle = document.createElement("div").style; if (name in emptyStyle) { return name; } var capName = name[0].toUpperCase + name.slice(1); var i = cssPrefixes.length; while (i--) { name = cssPrefixes[i] + capName; if (name in emptyStyle) { return name; } } } function generateInlineStyle(degree) { var deg = degree || 0; return 'rotate(' + deg + 'deg)'; } // DOM // var squareDOM = document.getElementById("square"); var boardDOM = document.getElementById("board"); var dirInputDOM = document.getElementById("directives"); var dirInputBtnDOM = dirInputDOM.nextElementSibling; // 区域 var board = (function() { var ROW = 10; var COLUMN = 10; var bd = []; var generateBoard = function() { var cell = null; for (var i = 0; i < ROW; i++) { var rowTmp = []; for (var j = 0; j < COLUMN; j++) { cell = document.createElement("div"); cell.className = "grid"; if (j === 0) { cell.className += " clearfix"; } else if (j === 9) { cell.className += " rightmost"; } if (i === 9) { cell.className += " downmost"; } boardDOM.appendChild(cell); rowTmp.push(0); } bd.push(rowTmp); } }; return { generateBoard: function() { generateBoard(); }, getRowNum: function() { return ROW; }, getColNum: function() { return COLUMN; }, getBoardState: function() { return bd; } }; })(); // 小方块 var square = (function() { var sqPos = { x: 1, y: 1 }; // default position // 1~10 var sqDir = 0; // default direction // 0,1,2,3 var squareDOM = null; var PROPERTY = getProperName("transform"); console.log("当前浏览器支持的是 " + PROPERTY); var directionMod4 = function(direction) { return (direction % 4 + 4) % 4; }; var moveSqDOM = function() { squareDOM.style.top = (sqPos.x - 1) * 40 - 1 + "px"; squareDOM.style.left = (sqPos.y - 1) * 40 - 1 + "px"; }; var traDir = function(direction, pace) { // var pace = pace || 1; console.log("direction: " + direction) console.log("pace: " + pace); console.log("Before, sqPos is ") console.log(sqPos) var furPos = sqPos; if (direction === 0 && furPos.x >= pace + 1) { furPos.x -= pace; } else if (direction === 1 && furPos.y <= board.getColNum() - pace) { furPos.y += pace; } else if (direction === 2 && furPos.x <= board.getRowNum() - pace) { furPos.x += pace; } else if (direction === 3 && furPos.y >= pace + 1) { furPos.y -= pace; } else { throw new Error("将抵达边界,无法继续前进 XO"); } return furPos; }; var tryMove = function(direction, pace) { var pac = pace || 1; var dir = (typeof direction === "number") ? direction : directionMod4(sqDir); // direction can be 0 /*var furPos = sqPos; if (directionMod4() === 0 && furPos.x > 1) { furPos.x--; } else if (directionMod4() === 1 && furPos.y < board.getColNum()) { furPos.y++; } else if (directionMod4() === 2 && furPos.x < board.getRowNum()) { furPos.x++; } else if (directionMod4() === 3 && furPos.y > 1) { furPos.y--; } else { throw new Error("抵达边界,无法前进 XO"); }*/ var furPos = traDir(dir, pac); if (board.getBoardState()[furPos.x - 1][furPos.y - 1] === 0) { sqPos = furPos; console.log("After, sqPos is ") console.log(sqPos) } else { throw new Error("此方向存在障碍物,无法继续前进 XO"); } moveSqDOM(); }; var turnTo = function(direction) { var curDir = directionMod4(sqDir); // if(curDir === direction) return 0; // Any better way ??? var cwStep = 0, anticwStep = 0; while (true) { if ((curDir + cwStep) % 4 === direction) { break; } cwStep++; } while (true) { if ((curDir - anticwStep + 4) % 4 === direction) { break; } anticwStep++; } var deg = 0; if (cwStep > anticwStep) { deg = -anticwStep * 90; } else { deg = cwStep * 90; } return deg; }; var takeTurn = function(degree) { var deg = degree; sqDir += deg / 90; /* 小方块的旋转 */ squareDOM.style[PROPERTY] = generateInlineStyle(90 * sqDir); }; return { generateSquare: function() { // get square random position and direction sqPos.x = Math.ceil(Math.random() * 10); sqPos.y = Math.ceil(Math.random() * 10); sqDir = Math.floor(Math.random() * 4); // generate dom squareDOM = document.createElement("div"); squareDOM.id = "square"; moveSqDOM(); squareDOM.style[PROPERTY] = generateInlineStyle(90 * sqDir); boardDOM.appendChild(squareDOM); }, go: function() { tryMove(); }, tunlef: function() { takeTurn(-90); }, tunrig: function() { takeTurn(90); }, tunbac: function() { takeTurn(180); }, tratop: function() { tryMove(0); }, trarig: function() { tryMove(1); }, trabot: function() { tryMove(2); }, tralef: function() { tryMove(3); }, movtop: function() { /* newTurnFunc 朝最近的方向转动 */ takeTurn(turnTo(0)); tryMove(); }, movrig: function() { /* newTurnFunc 朝最近的方向转动 */ takeTurn(turnTo(1)); tryMove(); }, movbot: function() { /* newTurnFunc 朝最近的方向转动 */ takeTurn(turnTo(2)); tryMove(); }, movlef: function() { /* newTurnFunc 朝最近的方向转动 */ takeTurn(turnTo(3)); tryMove(); }, }; })(); var getValidDirective = function(rawValue) { var possibleValue = []; for (var key in square) { possibleValue.push(key); } var value = rawValue.trim().replace(/\s/g, '').toLowerCase(); if (possibleValue.indexOf(value) > -1) { return value; } throw new Error("非法指令,请重新尝试 :(\n合法的指令有如下:\n GO\n TUN LEF\n TUN RIG\n TUN BAC\n TRA TOP\n TRA RIG\n TRA BOT\n TRA LEF\n MOV TOP\n MOV RIG\n MOV BOT\n MOV LEF"); }; addEventHandler(dirInputBtnDOM, "click", function() { var rawValue = dirInputDOM.value; try { square[getValidDirective(rawValue)](); } catch (e) { alert(e.message); } }); dirInputDOM.onkeydown = function(event) { var e = event || window.event; switch (e.keyCode) { case 13: dirInputBtnDOM.click(); /* 关于模拟点击事件触发的其他方法(better way???) */ break; } }; board.generateBoard(); square.generateSquare();
<div class="panel"> <div id="board"> <!-- div.grid*100 --> <!-- <div id="square"></div> --> </div> <div class="controller"> <input type="text" id="directives" placeholder="请输入指令.." /> <input type="button" value="执行" /> </div> </div>
body { margin: 0; } .panel { counter-reset: rowIndex; } #board { position: relative; margin: 50px auto; border: 2px solid; width: 398px; height: 398px; counter-reset: colIndex; } .grid { position: relative; float: left; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; border-right: 2px solid #ddd; border-bottom: 2px solid #ddd; width: 40px; height: 40px; background-color: mistyrose; } .grid.clearfix { clear: both; } /* [!!note] 注意 nth-child 里的 n 必须写在最前,否则不会生效 */ /* 添加数字 */ .grid:nth-child(-n + 10):before { position: absolute; top: -24px; left: 8px; display: block; /* counter-reset by #board */ counter-increment: colIndex; content: counter(colIndex); width: 24px; height: 24px; line-height: 24px; text-align: center; } .grid:nth-child(10n + 1):after { position: absolute; top: 8px; left: -24px; display: block; /* counter-reset by .panel */ counter-increment: rowIndex; content: counter(rowIndex); width: 24px; height: 24px; line-height: 24px; text-align: center; } .grid.downmost { border-bottom: none; height: 38px; } .grid.rightmost { border-right: none; width: 38px; } #square { position: absolute; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; border-top: 8px solid salmon; width: 40px; height: 40px; background-color: lightpink; transition: all .5s; } #square:before, #square:after { position: absolute; top: -6px; display: block; content: '\a0'; border-radius: 5px / 15px; width: 10px; height: 30px; background-color: salmon; } #square:before { left: 6px; transform: rotate(5deg); } #square:after { right: 6px; transform: rotate(-5deg); } .controller { overflow: hidden; margin: 0 auto; width: 420px; } .controller input { float: left; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; display: block; margin: 0; border-radius: 0; padding: 0; } .controller input[type="text"] { padding: 0 20px; width: 65%; } .controller input[type="button"] { width: 35%; }