// 解决 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 square = (function() { var sqPos = [5, 5]; var sqDir = 0; // var DIRECTION = ["faceNorth", "faceEast", "faceSouth", "faceWest"]; var PROPERTY = getProperName("transform"); console.log("当前浏览器支持的是 " + PROPERTY); var directionMod4 = function() { /* sqDir % 4 === 0,1,2,3 */ // 为了解决当 sqDir 为负数时,sqDir % 4 的值不在 0,1,2,3 之间的问题 /* 法1. 能否借助 Math 的某未知方法??? */ // Q: Math 有没有方法能取模只返回正数? // A: JS 当下不存在这样的函数。 // Q: 能否通过比如说 Math.abs 实现(特别是还要能避免使用 if)? // A: 至少用 Math.abs 只会帮倒忙。。 /* 法2. 本想借助 substr 方法支持末尾计数法和一个静态字符串来实现。。。 */ // A: 但是当被模数的绝对值大于模数时,存在问题。比如 >4 的时候会反回 NaN 。 // 实质上,String 的末尾计数法(substr/slice)的计算方式并不能很好地和真正的取模运算相映射 Orz // var DIRECTION = ["faceNorth", "faceEast", "faceSouth", "faceWest"]; // return parseInt(DSTRING.substr(sqDir,1)); /* 法3. 如下,已经是我能想到的比较简单的方法了 www */ return (sqDir % 4 + 4) % 4; // Any better way ??? }; var moveSqDOM = function() { squareDOM.style.top = sqPos[1] * 40 + "px"; squareDOM.style.left = sqPos[0] * 40 + "px"; }; var tryMove = function(direction, pace) { var pace = pace || 1; console.log(direction) console.log(sqPos) if (directionMod4() === 0 && sqPos[1] > 1) { sqPos[1]--; } else if (directionMod4() === 1 && sqPos[0] < 10) { sqPos[0]++; } else if (directionMod4() === 2 && sqPos[1] < 10) { sqPos[1]++; } else if (directionMod4() === 3 && sqPos[0] > 1) { sqPos[0]--; } else { throw new Error("抵达边界无法前进 XO"); } moveSqDOM(); }; var takeTurn = function(clockwise, degree) { var degree = degree || 90; if (degree === 90) { if (clockwise) { sqDir++; } else { sqDir--; } } else if (degree === 180) { console.log("turn 180 deg !!") sqDir += 2; } /* 小方块的旋转 */ /* 法1. 一开始想用 class 实现,但是变化不连续 :( */ // squareDOM.className = DIRECTION[directionMod4()]; /* 法2. js + inline-css */ squareDOM.style[PROPERTY] = generateInlineStyle(90 * sqDir); }; return { go: function() { tryMove(sqDir); }, tunlef: function() { console.log("square should turn left..") takeTurn(false); }, tunrig: function() { console.log("square should turn right..") takeTurn(true); }, tunbac: function() { console.log("square should turn back..") takeTurn(true, 180); } }; })(); var board = (function() { var bd = []; return { }; })(); var getValidDirective = function(rawValue) { var possibleValue = []; for (var key in square) { possibleValue.push(key); } var value = rawValue.trim().replace(/\s/, '').toLowerCase(); if (possibleValue.indexOf(value) > -1) { return value; } throw new Error("非法指令,请重新尝试 :("); }; addEventHandler(dirInputBtnDOM, "click", function() { var rawValue = dirInputDOM.value; try { square[getValidDirective(rawValue)](); } catch (e) { alert(e.message); } });
<div class="panel"> <div id="board"> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div class="grid"></div> <div id="square"></div> </div> <div class="controller"> <input type="text" id="directives" placeholder="请输入指令.." /> <input type="button" value="执行" /> </div> </div>
body { margin: 0; } .panel { padding: 1px; } #board { position: relative; overflow: hidden; margin: 0 auto; /*border: 2px solid;*/ padding: 39px; width: 402px; height: 402px; } .grid { float: left; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; border: 1px solid #ddd; width: 40px; height: 40px; } /* [!!note] 注意 nth-child 里的 n 必须写在最前,否则不会生效 */ .grid:nth-child(-n + 10) { position: relative; border-top-color: #000; border-top-width: 2px; height: 41px; } /* 添加数字 */ .grid:nth-child(-n + 10):before { position: absolute; top: -24px; left: 8px; display: block; /*content: '1';*/ width: 24px; height: 24px; line-height: 24px; text-align: center; } .grid:nth-child(1):before { content: '1'; } .grid:nth-child(2):before { content: '2'; } .grid:nth-child(3):before { content: '3'; } .grid:nth-child(4):before { content: '4'; } .grid:nth-child(5):before { content: '5'; } .grid:nth-child(6):before { content: '6'; } .grid:nth-child(7):before { content: '7'; } .grid:nth-child(8):before { content: '8'; } .grid:nth-child(9):before { content: '9'; } .grid:nth-child(10):before { content: '10'; } .grid:nth-child(10n + 1) { position: relative; border-left-color: #000; border-left-width: 2px; width: 41px; } .grid:nth-child(10n + 1):after { position: absolute; top: 8px; left: -24px; display: block; /*content: '1';*/ width: 24px; height: 24px; line-height: 24px; text-align: center; } .grid:nth-child(1):after { content: '1'; } .grid:nth-child(11):after { content: '2'; } .grid:nth-child(21):after { content: '3'; } .grid:nth-child(31):after { content: '4'; } .grid:nth-child(41):after { content: '5'; } .grid:nth-child(51):after { content: '6'; } .grid:nth-child(61):after { content: '7'; } .grid:nth-child(71):after { content: '8'; } .grid:nth-child(81):after { content: '9'; } .grid:nth-child(91):after { content: '10'; } .grid:nth-child(n + 91) { border-bottom-color: #000; border-bottom-width: 2px; height: 41px; } .grid:nth-child(10n) { border-right-color: #000; border-right-width: 2px; width: 41px; } #square { position: absolute; top: 200px; left: 200px; -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.faceNorth { transform: rotate(0deg); } #square.faceEast { transform: rotate(90deg); } #square.faceWest { transform: rotate(-90deg); } #square.faceSouth { transform: rotate(180deg); }*/ #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; padding: 24px 20%; } .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%; }