即使放入错误的 droppable,如何禁用 draggable
how to disable a draggable even if dropped into wrong droppable
我知道如何在将对象拖入正确的可放置项时禁用可拖动项,如下所示,但在放入错误的可放置项时则不然。
我希望即使答案不正确,用户也无法再次拖动,这意味着只能尝试一次。
我使用 edge animate,它使用与普通 JavaScript 不同的语法来获取元素,但其余部分相同。
下面是我的代码和注释。
for(j=0;j<35;j++){
sym.$(answers1[j]).addClass('drag'+j);
sym.$('.drag'+j).draggable({
//revert: "invalid" // I do not want revert in any case
stop: function(){
$(this).draggable('disabled'); // will disable when dropped anywhere
//I want only when into the wrong droppable -
//so almost good but not quite right.
}
});
sym.$(droppables[j]).droppable({
accept: ".drag"+j,
drop: function(event,ui){
ui.draggable.draggable( 'destroy' ); // the correct answer is disabled
//I could have used 'disabled' here since it does the same as 'destroy'.
}
});
基本上您的问题是,通过同时使用 accept
和 drop
选项,您使 drop
仅对接受的元素执行。
为了实现您想要的效果,您必须使用其他方式来定义 draggable
与其 "correct" droppable
.
之间的关系
例如您可以向每个 droppable
添加一个数据属性,其中包含接受的 draggable
(比如 data-accept="drag1"
)的 class。
然后你可以从你的 droppables
中删除 accept
选项,并在他们的 drop
处理程序中手动检查 classes 是否匹配,比如
drop: function( event, ui ) {
if (ui.draggable.hasClass( $(this).data('accept') )) {
// correct match
}
// anyway disable the draggable
ui.draggable.draggable('disable');
}
这是一个演示:JSFiddle
在得到一些说明后,我提供了这个替代解决方案。有多个答案和放置它们的地方,当 1 个答案被放置时,它应该不再接受答案,用户应该不能进一步移动那个答案。
工作示例:https://jsfiddle.net/Twisty/crdxcg90/3/
HTML
<div>
<h4>Put the family members in order of youngest to oldest.</h4>
<p class="drag answer" id="1">Homer</p>
<p class="drag answer" id="2">Marge</p>
<p class="drag answer" id="3">Bart</p>
<p class="drag answer" id="4">Lisa</p>
<p class="drag answer" id="5">Maggie</p>
</div>
<div class="dropzone drop1" id="drop-1">Youngest</div>
<div class="dropzone drop2" id="drop-2">2</div>
<div class="dropzone drop3" id="drop-3">3</div>
<div class="dropzone drop4" id="drop-4">4</div>
<div class="dropzone drop5" id="drop-5">Oldest</div>
CSS
.drag {
background: #ccc;
padding: 3px;
width: 60px;
text-align: center;
margin: 2px;
}
.dropzone {
width: 100px;
height: 50px;
background: #0f0;
float: left;
text-align: center;
margin: 2px;
}
.answered {
background: #cfc;
}
JQuery
$(function() {
$(".answer").draggable({
revert: "invalid"
});
$(".dropzone").droppable({
drop: function(e, ui) {
$(e.target).addClass("answered");
ui.draggable.draggable("destroy");
$(this).droppable("option", "accept", function() {
return false;
});
}
});
});
您需要调整回您的特定作业,但如果答案的数量经常变化,这可能会让您更轻松并且更灵活。
已更新
看了你的样本后,我更清楚你想要什么。希望这会对你有所帮助:
https://jsfiddle.net/Twisty/crdxcg90/6/
var answers1 = [1, 3, 5];
var coins = 0;
$(function() {
$(".answer").draggable({
revert: "invalid"
});
$(".dropzone").droppable({
drop: function(e, ui) {
$(e.target).addClass("answered");
var t = parseInt($(e.target).attr("id").substring(5));
var a = parseInt(ui.draggable.attr("id"));
if (answers1[t] === a) {
$(e.target).addClass("correct");
coins++;
}
ui.draggable.draggable("destroy");
$(this).droppable("option", "accept", false);
$("#coins").html(coins);
},
tolerance: "fit"
});
});
当对象被丢弃时,它会检查 answers1
中的位置,如果掉落与答案匹配,我们将其标记为正确并奖励一枚硬币。
这是在 Edge Animate 中完成的最终正确方法。
在 Edge Animate 中使用 data() 的方式与普通的 javascript 和 html 略有不同。我们使用它是为了能够将数据值与变量 ID 的值进行比较。我们还为 draggables 使用了一个 class,并在 UI 中添加了 class 用于没有 droppable(干扰项)的 draggables,因此它们仍然可以被拖动并放置在 droppable 中并充当所有其他可拖动对象。然后我们在 dropEvent 函数中添加了条件。
//'level1-D','level1-E','level1-F' added the drag class in the UI for distractors.
var answers1 = [
'level1-A','level1-B','level1-C',
'level2-A','level2-B','level2-C',
'level3-A','level3-B','level3-C',
'level4-A','level4-B',
'level5-A','level5-B','level5-C',
'level6-A','level6-B','level6-C',
'level7-A','level7-B','level7-C','level7-D',
'level8-A','level8-B','level8-C','level8-D','level8-E',
'level9-A','level9-B','level9-C',
'level10-A','level10-B','level10-C',
];
var droppables = [
'dp0' ,'dp1' ,'dp2' ,'dp3' ,'dp4' ,'dp5' ,'dp8','dp6','dp7','dp9',
'dp10','dp13','dp11','dp12','dp15','dp16','dp14','dp19','dp17','dp20',
'dp18','dp23','dp22','dp21','dp25','dp24','dp27','dp26','dp28','dp29','dp30','dp31'
];
for(j=0;j<32;j++){
// draggables
sym.$(answers1[j]).addClass('drag');
// droppables
sym.$(droppables[j]).droppable({
accept:'.drag',
drop: dropEvent
}).data('answer', answers1[j]); // use data to be able to compare gives the same name as the draggables
}// end for loop
sym.$('.drag').draggable({
revert : "invalid"
});
k=0;
function dropEvent(event, ui){
ui.draggable.draggable('option', 'revert' , false );
ui.draggable.draggable('option','disabled', true );
ui.draggable.position( { of: $(this), my: 'center', at: 'middle' } );
ID = ui.draggable.attr("id").replace('Stage_','');
if(ID == $(this).data('answer')){ // retrieve the data info and compare to ID
k++;
sym.getSymbol("meter").play();
sym.getSymbol("coinAnimation").play(0);
sym.$(ID + '-result').css({'opacity':1.0});
sym.$("boxScore").html(k);
sym.$("score").html(k+'/32');
if (music.paused ) {
correct.pause();
} else {
correct.currentTime = 0;
correct.play();
}
}// end if
}
我知道如何在将对象拖入正确的可放置项时禁用可拖动项,如下所示,但在放入错误的可放置项时则不然。 我希望即使答案不正确,用户也无法再次拖动,这意味着只能尝试一次。 我使用 edge animate,它使用与普通 JavaScript 不同的语法来获取元素,但其余部分相同。 下面是我的代码和注释。
for(j=0;j<35;j++){
sym.$(answers1[j]).addClass('drag'+j);
sym.$('.drag'+j).draggable({
//revert: "invalid" // I do not want revert in any case
stop: function(){
$(this).draggable('disabled'); // will disable when dropped anywhere
//I want only when into the wrong droppable -
//so almost good but not quite right.
}
});
sym.$(droppables[j]).droppable({
accept: ".drag"+j,
drop: function(event,ui){
ui.draggable.draggable( 'destroy' ); // the correct answer is disabled
//I could have used 'disabled' here since it does the same as 'destroy'.
}
});
基本上您的问题是,通过同时使用 accept
和 drop
选项,您使 drop
仅对接受的元素执行。
为了实现您想要的效果,您必须使用其他方式来定义 draggable
与其 "correct" droppable
.
例如您可以向每个 droppable
添加一个数据属性,其中包含接受的 draggable
(比如 data-accept="drag1"
)的 class。
然后你可以从你的 droppables
中删除 accept
选项,并在他们的 drop
处理程序中手动检查 classes 是否匹配,比如
drop: function( event, ui ) {
if (ui.draggable.hasClass( $(this).data('accept') )) {
// correct match
}
// anyway disable the draggable
ui.draggable.draggable('disable');
}
这是一个演示:JSFiddle
在得到一些说明后,我提供了这个替代解决方案。有多个答案和放置它们的地方,当 1 个答案被放置时,它应该不再接受答案,用户应该不能进一步移动那个答案。
工作示例:https://jsfiddle.net/Twisty/crdxcg90/3/
HTML
<div>
<h4>Put the family members in order of youngest to oldest.</h4>
<p class="drag answer" id="1">Homer</p>
<p class="drag answer" id="2">Marge</p>
<p class="drag answer" id="3">Bart</p>
<p class="drag answer" id="4">Lisa</p>
<p class="drag answer" id="5">Maggie</p>
</div>
<div class="dropzone drop1" id="drop-1">Youngest</div>
<div class="dropzone drop2" id="drop-2">2</div>
<div class="dropzone drop3" id="drop-3">3</div>
<div class="dropzone drop4" id="drop-4">4</div>
<div class="dropzone drop5" id="drop-5">Oldest</div>
CSS
.drag {
background: #ccc;
padding: 3px;
width: 60px;
text-align: center;
margin: 2px;
}
.dropzone {
width: 100px;
height: 50px;
background: #0f0;
float: left;
text-align: center;
margin: 2px;
}
.answered {
background: #cfc;
}
JQuery
$(function() {
$(".answer").draggable({
revert: "invalid"
});
$(".dropzone").droppable({
drop: function(e, ui) {
$(e.target).addClass("answered");
ui.draggable.draggable("destroy");
$(this).droppable("option", "accept", function() {
return false;
});
}
});
});
您需要调整回您的特定作业,但如果答案的数量经常变化,这可能会让您更轻松并且更灵活。
已更新
看了你的样本后,我更清楚你想要什么。希望这会对你有所帮助:
https://jsfiddle.net/Twisty/crdxcg90/6/
var answers1 = [1, 3, 5];
var coins = 0;
$(function() {
$(".answer").draggable({
revert: "invalid"
});
$(".dropzone").droppable({
drop: function(e, ui) {
$(e.target).addClass("answered");
var t = parseInt($(e.target).attr("id").substring(5));
var a = parseInt(ui.draggable.attr("id"));
if (answers1[t] === a) {
$(e.target).addClass("correct");
coins++;
}
ui.draggable.draggable("destroy");
$(this).droppable("option", "accept", false);
$("#coins").html(coins);
},
tolerance: "fit"
});
});
当对象被丢弃时,它会检查 answers1
中的位置,如果掉落与答案匹配,我们将其标记为正确并奖励一枚硬币。
这是在 Edge Animate 中完成的最终正确方法。 在 Edge Animate 中使用 data() 的方式与普通的 javascript 和 html 略有不同。我们使用它是为了能够将数据值与变量 ID 的值进行比较。我们还为 draggables 使用了一个 class,并在 UI 中添加了 class 用于没有 droppable(干扰项)的 draggables,因此它们仍然可以被拖动并放置在 droppable 中并充当所有其他可拖动对象。然后我们在 dropEvent 函数中添加了条件。
//'level1-D','level1-E','level1-F' added the drag class in the UI for distractors.
var answers1 = [
'level1-A','level1-B','level1-C',
'level2-A','level2-B','level2-C',
'level3-A','level3-B','level3-C',
'level4-A','level4-B',
'level5-A','level5-B','level5-C',
'level6-A','level6-B','level6-C',
'level7-A','level7-B','level7-C','level7-D',
'level8-A','level8-B','level8-C','level8-D','level8-E',
'level9-A','level9-B','level9-C',
'level10-A','level10-B','level10-C',
];
var droppables = [
'dp0' ,'dp1' ,'dp2' ,'dp3' ,'dp4' ,'dp5' ,'dp8','dp6','dp7','dp9',
'dp10','dp13','dp11','dp12','dp15','dp16','dp14','dp19','dp17','dp20',
'dp18','dp23','dp22','dp21','dp25','dp24','dp27','dp26','dp28','dp29','dp30','dp31'
];
for(j=0;j<32;j++){
// draggables
sym.$(answers1[j]).addClass('drag');
// droppables
sym.$(droppables[j]).droppable({
accept:'.drag',
drop: dropEvent
}).data('answer', answers1[j]); // use data to be able to compare gives the same name as the draggables
}// end for loop
sym.$('.drag').draggable({
revert : "invalid"
});
k=0;
function dropEvent(event, ui){
ui.draggable.draggable('option', 'revert' , false );
ui.draggable.draggable('option','disabled', true );
ui.draggable.position( { of: $(this), my: 'center', at: 'middle' } );
ID = ui.draggable.attr("id").replace('Stage_','');
if(ID == $(this).data('answer')){ // retrieve the data info and compare to ID
k++;
sym.getSymbol("meter").play();
sym.getSymbol("coinAnimation").play(0);
sym.$(ID + '-result').css({'opacity':1.0});
sym.$("boxScore").html(k);
sym.$("score").html(k+'/32');
if (music.paused ) {
correct.pause();
} else {
correct.currentTime = 0;
correct.play();
}
}// end if
}