数独是很好玩的游戏,之前我用jQuery做了一个数独游戏,因为用javaScript来实现drag和drap非常麻烦,jQuery的UI提供了一套非常不错的drag和drap(以后就简称DnD算了),方便我们开发。现在HTML5支持原生的DnD了,那我们来学习下,并且将原先的数独游戏迁移到HTML5的DnD应用来。
先简单的了解下HTML5的DnD事件模型,事件发生在源元素(被拖动的元素)和目标元素(被进入的元素)上,为了简单的描述,我们将源元素称为src,目标元素叫des。
drag:src[拖动中] | dragstart:src[开始拖动] |
dragenter:des[进入目标] | |
dragover:des[在目标移动] | |
dragleave:des[离开目标] | |
drop:des[释放拖动] | |
dragend:src[拖动完成] |
e.dataTransfer.effectAllowed,只能在dragstart事件设置,值为以下之一:"none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all", and "uninitialized"
e.dataTransfer.dropEffect,返回拖来的行为,对应上面的effectAllowed,值是:"none", "copy", "link", and "move"
e.target,可以得到当前事件的dom对象,比如你可以得到e.target.innerHTML,或者设置e.target.classList.add,或者e.target.classList.remove
e.dataTransfer.setData(foramt,value),为拖动赋值,foramt的值是为了描述值的类型,一般有text/plain 和 text/uri-list
e.dataTransfer.getData(foramt),获取被拖来的元素通过setData存储的值
e.stopPropagation,阻止事件冒泡,这样可以防止子元素的拖动处理被带到父元素事件中(触发父元素事件),在IE中可以用e.cancelBubble = true
e.preventDefault,阻止默认事件发生,也可以简单的写return false,在IE中可以用e.returnValue = false
有了上面的基本概念,我们先做一个小小的模型,来测试几个技术要点:监视拖放事件,改变元素在拖放中的样式,传递值和检查值什么的
在body里面,我们声明了10个div元素,并且都标记允许拖放
<body> <div style="width: 50px; height: 50px; background-color: Red;" draggable="true">
1
</div>
<div style="width: 50px; height: 50px; background-color: Yellow;" draggable="true">
2
</div>
<div style="width: 50px; height: 50px; background-color: Blue;" draggable="true">
3
</div>
<div style="width: 50px; height: 50px; background-color: Lime;" draggable="true">
4
</div>
<div style="width: 50px; height: 50px; background-color: Maroon;" draggable="true">
5
</div>
<div style="width: 50px; height: 50px; background-color: Black;" draggable="true">
6
</div>
<div style="width: 50px; height: 50px; background-color: Orange;" draggable="true">
7
</div>
<div style="width: 50px; height: 50px; background-color: Olive;" draggable="true">
8
</div>
<div style="width: 50px; height: 50px; background-color: Teal;" draggable="true">
9
</div>
<div style="width: 50px; height: 50px; background-color: Green;" draggable="true">
10
</div>
</body>
首选我们做一个用于输出调式的小工具代码
$.log = function(msg) { console.log(msg);}
第一步,编写dragStart事件函数
function handleDragStart(e) { this.style.opacity = "0.5"; e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/plain", this.innerHTML); //$.log(this.innerHTML); //$.log(e.target.innerHTML); //$.log(e.srcElement.innerHTML); [ ].forEach.call(document.querySelectorAll("div"), function(item) { var a = parseInt(e.target.innerHTML); var b = parseInt(item.innerHTML); if (a % b != 0 && b % a != 0) { item.style.opacity = "0.1"; } });}
1 对事件来讲this、e.target和e.srcElement都是同一对象
2 在forEach中,this是指item,所以forEach中,我们要用e.target来引用
但是一测试我们就发现虽然元素可以拖拉,但并没有事件激活,那是应为我们没有为元素绑定事件,所以现在我们用addEventListener来将元素和事件绑定
$(function() { [ ].forEach.call(document.querySelectorAll("div"),function(item) { item.addEventListener("dragstart", handleDragStart, false); });});
第二步,当我们拖放完成后,所有div恢复原先颜色,那自然是编写handleDragEnd
function handleDragEnd(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } [ ].forEach.call(document.querySelectorAll("div"), function(item) { item.style.opacity = "1"; } );}
$(function() { [ ].forEach.call(document.querySelectorAll("div"),function(item) { item.addEventListener("dragstart", handleDragStart, false); item.addEventListener("dragend", handleDragEnd, false); });});
我们先需要为目标元素定义些事件函数
function handleDragEnter(e) { $.log(e);}function handleDragOver(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } $.log(e); return false;}function handleDragLeave(e) { $.log(e);}function handleDrop(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } console.log(e); return false;}
注意我们使用了preventDefault和stopPropagation消除了浏览器默认的一些动作。
显然这些事件不是所有的元素都有的,只有互为倍数才有,所以我们要去修改handleDragStart函数了
修改后的代码大致如下
function handleDragStart(e) { this.style.opacity = "0.5"; e.dataTransfer.effectAllowed = "move"; e.dataTransfer.setData("text/plain", this.innerHTML); //$.log(this.innerHTML); //$.log(e.target.innerHTML); //$.log(e.srcElement.innerHTML); //$.log(this.innerHTML); [ ].forEach.call(document.querySelectorAll("div"), function(item) { var a = parseInt(e.target.innerHTML); var b = parseInt(item.innerHTML); if (a % b != 0 && b % a != 0) { item.style.opacity = "0.1"; } else { item.addEventListener("dragover", handleDragOver, false); item.addEventListener("dragenter", handleDragEnter, false); item.addEventListener("dragleave", handleDragLeave, false); item.addEventListener("drop", handleDrop, false); } });}
function handleDragEnd(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } [ ].forEach.call(document.querySelectorAll("div"), function(item) { item.style.opacity = "1"; item.removeEventListener("dragover", handleDragOver, false); item.removeEventListener("dragenter", handleDragEnter, false); item.removeEventListener("dragleave", handleDragLeave, false); item.removeEventListener("drop", handleDrop, false); } );}
function handleDrop(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } this.innerHTML = parseInt(this.innerHTML)+parseInt(e.dataTransfer.getData("text/plain")) console.log(e); return false;}
最后,我感觉黑色的字不好看,我们修改下初始化的函数
$(function() { [ ].forEach.call(document.querySelectorAll("div"),function(item) { item.addEventListener("dragstart", handleDragStart, false); item.addEventListener("dragend", handleDragEnd, false); item.style.color = "White";});});
好了,现在这个无聊的拖动作品,至少可以打发下你的时间,对不,欣赏下自己的作品吧,接下来,我们开始做正式做数独游戏了。
第一步,我们先生成一个1-9的数字对象矩形,这个矩形可以拖动。
先设计htmltag
<ol id="numberBox" style="list-style-type: none; width: 90px; height: 90px;"></ol>
#numberBox > li{ width: 30px; height: 25px; text-align: center; font-size: 20px; padding-top: 5px; float: left; color: White;}
$(function() { [{ number: 1, bgcolor: "#C71585" }, { number: 2, bgcolor: "#800080" }, { number: 3, bgcolor: "#B8860B" }, { number: 4, bgcolor: "rgb(0,0,128)" }, { number: 5, bgcolor: "rgb(30,144,255)" }, { number: 6, bgcolor: "rgb(255,165,0)" }, { number: 7, bgcolor: "hsl(0,75%,50%)" }, { number: 8, bgcolor: "hsl(30,50%,50%)" }, { number: 9, bgcolor: "hsl(120,75%,38%)"}].forEach( function(key, index) { $.log(key); var li = $("<li>").html(key.number).css("backgroundColor", key.bgcolor).attr("draggable","true"); $.log(li); li[0].addEventListener("dragstart", function() { }, false); $("#numberBox").append(li); } );});
好,然后你运行下页面,可以看到一个九宫格,并且每一个格子都可以拖动。
第二步,我们要类似的创建我们填数字得的区域了。
首先还是htmlTag
<ol id="player" style="list-style-type: none; width: 450px; height: 450px;"></ol>
#player .default{ float: left; width: 48px; height: 33px; border: solid 1px rgb(0,0,0); font-size: 20px; padding-top: 15px; text-align: center; background-color: #B8860B;}#player .fix{ float: left; width: 48px; height: 33px; border: solid 1px rgb(0,0,0); font-size: 20px; padding-top: 15px; text-align: center; background-color: #FFFABC;}#player .ation{ float: left; width: 48px; height: 33px; border: solid 1px rgb(0,0,0); font-size: 20px; padding-top: 15px; text-align: center; background-color: #FFA07A;}
$(function() { "500000300090500400004000700051037289302080604008052137035000900609000823080023006".split("").forEach( function(item, index) { $.log(item); var li = $("<li>") if (item != "0") { li.addClass("fix"); li[0].innerHTML = item; } else { li[0].classList.add("default"); li[0].addEventListener("dragenter", function(e) { $.log(e); }, false); li[0].addEventListener("dragover", function(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } $.log(e); return false; }, false); li[0].addEventListener("dragleave", function(e) { }, false); li[0].addEventListener("drop", function(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } }, false); } $("#player").append(li); } );});
第三步:我们拖动数字之后,希望可以填数字的区域有明显的颜色变化并给出提示,同时固定区域不可以拖进去,其他区域可以拖进去,并且拖动的时候要send值。
有了前面的知识,我们马上知道去哪里改事件控制了:dragstart事件
$(function() { [{ number: 1, bgcolor: "#C71585" }, { number: 2, bgcolor: "#800080" }, { number: 3, bgcolor: "#B8860B" }, { number: 4, bgcolor: "rgb(0,0,128)" }, { number: 5, bgcolor: "rgb(30,144,255)" }, { number: 6, bgcolor: "rgb(255,165,0)" }, { number: 7, bgcolor: "hsl(0,75%,50%)" }, { number: 8, bgcolor: "hsl(30,50%,50%)" }, { number: 9, bgcolor: "hsl(120,75%,38%)"}].forEach( function(key, index) { //$.log(key); var li = $("<li>").html(key.number).css("backgroundColor", key.bgcolor).attr("draggable", "true"); //$.log(li); li[0].addEventListener("dragstart", function(e) { e.dataTransfer.effectAllowed = "copyMove"; e.dataTransfer.setData("text/plain", this.innerHTML); $.log(this.innerHTML); [ ].forEach.call(document.querySelectorAll("#player .default"), function(item) { //$.log(item); item.classList.remove("default"); item.classList.add("ation"); }); }, false); li[0].addEventListener("dragend", function() { [ ].forEach.call(document.querySelectorAll("#player .ation"), function(item) { item.classList.remove("ation"); item.classList.add("default"); }); }, false); $("#numberBox").append(li); } );});
第四步,我们接受值,并且判断这个值是否存在行列冲突,如果冲突就提示,否则改写
$(function() { "500000300090500400004000700051037289302080604008052137035000900609000823080023006".split("").forEach( function(item, index) { $.log(item); var li = $("<li>") if (item != "0") { li.addClass("fix"); li[0].innerHTML = item; } else { li[0].classList.add("default"); li[0].addEventListener("dragenter", function(e) { $.log(e); }, false); li[0].addEventListener("dragover", function(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } $.log(e); return false; }, false); li[0].addEventListener("dragleave", function(e) { }, false); li[0].addEventListener("drop", function(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } var sendData = e.dataTransfer.getData("text/plain"); //获得#player>li矩阵数组 var matrix = Array.prototype.slice.call(document.querySelectorAll("#player>li")); var currIndex = matrix.indexOf(this); //获得当前元素的位置 var rowIndex = currIndex - currIndex % 9; //行开始的位置 var colIndex = currIndex % 9//列开始的位置 for (var i = rowIndex; i < rowIndex + 9; i++) { if (i != currIndex && matrix[i].innerHTML == sendData) { alert("对不起行上有数据重复,请小心哦!亲"); return; } } for (var i = colIndex; i < 81; i = i + 9) { if (i != currIndex && matrix[i].innerHTML == sendData) { alert("对不起列上有数据重复,请小心哦!亲"); return; } } this.innerHTML = sendData; }, false); } $("#player").append(li); } );});
下面是完整的代码,你要懒的话,就直接copy吧
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head> <title></title> <script src="js/jquery-1.7.1.min.js" type="text/javascript"></script> <script type="text/javascript"> $.log = function(msg) { console.log(msg); } $( function() { [{ number: 1, bgcolor: "#C71585" }, { number: 2, bgcolor: "#800080" }, { number: 3, bgcolor: "#B8860B" }, { number: 4, bgcolor: "rgb(0,0,128)" }, { number: 5, bgcolor: "rgb(30,144,255)" }, { number: 6, bgcolor: "rgb(255,165,0)" }, { number: 7, bgcolor: "hsl(0,75%,50%)" }, { number: 8, bgcolor: "hsl(30,50%,50%)" }, { number: 9, bgcolor: "hsl(120,75%,38%)"}].forEach( function(key, index) { //$.log(key); var li = $("<li>").html(key.number).css("backgroundColor", key.bgcolor).attr("draggable", "true"); //$.log(li); li[0].addEventListener("dragstart", function(e) { e.dataTransfer.effectAllowed = "copyMove"; e.dataTransfer.setData("text/plain", this.innerHTML); $.log(this.innerHTML); [ ].forEach.call(document.querySelectorAll("#player .default"), function(item) { //$.log(item); item.classList.remove("default"); item.classList.add("ation"); }); }, false); li[0].addEventListener("dragend", function() { [ ].forEach.call(document.querySelectorAll("#player .ation"), function(item) { item.classList.remove("ation"); item.classList.add("default"); }); }, false); $("#numberBox").append(li); } ); } ); $( function() { "500000300090500400004000700051037289302080604008052137035000900609000823080023006".split("").forEach( function(item, index) { $.log(item); var li = $("<li>") if (item != "0") { li.addClass("fix"); li[0].innerHTML = item; } else { li[0].classList.add("default"); li[0].addEventListener("dragenter", function(e) { $.log(e); }, false); li[0].addEventListener("dragover", function(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } $.log(e); return false; }, false); li[0].addEventListener("dragleave", function(e) { }, false); li[0].addEventListener("drop", function(e) { if (e.preventDefault) { e.preventDefault(); //不要执行与事件关联的默认动作 } if (e.stopPropagation) { e.stopPropagation(); //停止事件的传播 } var sendData = e.dataTransfer.getData("text/plain"); //获得#player>li矩阵数组 var matrix = Array.prototype.slice.call(document.querySelectorAll("#player>li")); var currIndex = matrix.indexOf(this); //获得当前元素的位置 var rowIndex = currIndex - currIndex % 9; //行开始的位置 var colIndex = currIndex % 9//列开始的位置 for (var i = rowIndex; i < rowIndex + 9; i++) { if (i != currIndex && matrix[i].innerHTML == sendData) { alert("对不起行上有数据重复,请小心哦!亲"); return; } } for (var i = colIndex; i < 81; i = i + 9) { if (i != currIndex && matrix[i].innerHTML == sendData) { alert("对不起列上有数据重复,请小心哦!亲"); return; } } this.innerHTML = sendData; }, false); } $("#player").append(li); } ); } ); </script> <style type="text/css"> #numberBox > li { width: 30px; height: 25px; text-align: center; font-size: 20px; padding-top: 5px; float: left; color: White; } #player .default { float: left; width: 48px; height: 33px; border: solid 1px rgb(0,0,0); font-size: 20px; padding-top: 15px; text-align: center; background-color: #B8860B; } #player .fix { float: left; width: 48px; height: 33px; border: solid 1px rgb(0,0,0); font-size: 20px; padding-top: 15px; text-align: center; background-color: #FFFABC; } #player .ation { float: left; width: 48px; height: 33px; border: solid 1px rgb(0,0,0); font-size: 20px; padding-top: 15px; text-align: center; background-color: #FFA07A; } </style></head><body> <ol id="numberBox" style="list-style-type: none; width: 90px; height: 90px;"> </ol> <ol id="player" style="list-style-type: none; width: 450px; height: 450px;"> </ol></body></html>
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。