Почему после использования data атрибута в setTimeout, он перестаёт быть доступным ?
Добрый день.
Есть загвоздка, и я не могу понять до конца, из-за чего она возникает, поэтому попробую описать проблему, по возможности, сжато но подробно. я новичок, поэтому не судите строго за возможный каламбур... Вообщем, я делаю карточную игруху(посередине игровое поле из 9 ячеек. 3 по горизонту 3 по вертикали. От игрового поля слева находятся ваши карты, а справа карты компа. У каждой карты есть 4 цифры слева, справа, сверху и снизу. По этим цифрам происходит сравнение между картами.) Ход игрока реализован при помощи jquery, draggable и droppable. Ход компа осуществляется в droppable свойстве drop: при помощи append. Вся логика написана и всё работает. И собственно теперь к проблеме, сейчас хочу сделать чтобы действие append после перетаскивания происходило с 2 сек задержкой. Написал код, и append работает как задумывалось, НО потом вся логика рушиться, т.к. элемент, который я передаю append в дальнейшем везде перестаёт быть доступным (выдаёт undefined). Код выглядит вот так:
// перемешиваю колоду. //
var arr = [0,1,2,3,4];
function shuffle(o){
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
}
shuffle(arr);
var cards = new Array();
for (var i=0; i<5; i++) {
cards[i] = $('.ssComp:eq('+(arr[i])+')');
}
// ------------------------------------- //
$('.game-field').droppable({
activeClass: 'active-th',
hoverClass: 'hover-th',
drop: function(event, ui) {
$card = $(ui.draggable);
$(this).prepend($card);
var self = $(this);
var appendCard = function(arg) {
var y = $(arg).append(cards.shift()).find('img').css({
'border': '10px solid #FF0000',
'width': '150px',
'height': '150px'
}).animate({
'width': '100%',
'height': '100%'
});
var q = $(arg).droppable('disable');
return y, q;
}
setTimeout(function(){appendCard.call(self, '[data-id='+(self.data('id')+1)+']')}, 2000);
У всех ячеек игрового поля есть data-id. По дата атрибуту собственно и происходит везде обращение. Функция appendCard вставляет карту компа справа от той ячейки, в которую user перетащил свою карту. (логику проверок на вставку в поле я тут опустил, т.к. это не важно сейчас). В дальнейшем по игровой логике, вставленную компом карту, нужно будет сравнивать с соседними картами по всем сторонам (справа, снизу, слева, сверху). Обращение к этим ячейкам выглядит вот так:
var insertComp = $('[data-id='+($(this).data('id')+1)+'] .ssComp');
var topSs = $('[data-id='+($(this).data('id')-2)+'] .ss')
var topComp = $('[data-id='+($(this).data('id')-2)+'] .ssComp');
var bottomComp = $('[data-id='+($(this).data('id')+4)+'] .ssComp');
var bottomSs = $('[data-id='+($(this).data('id')+4)+'] .ss');
var rightSs = $('[data-id='+($(this).data('id')+2)+'] .ss');
var rightComp = $('[data-id='+($(this).data('id')+2)+'] .ssComp');
var leftSs = $('[data-id='+($(this).data('id')+0)+'] .ss');
var leftComp = $('[data-id='+($(this).data('id')+0)+'] .ssComp');
ss - класс колоды юзера, ssComp - колоды компа. (разметку страницы если нужно могу выложить) у них так же есть data-user=1 для .ss и data-user=2 для .ssComp Дальше сравниваю карту:
setTimeout(function(){leftInsert()}, 500); // с той, что СЛЕВА от неё //
setTimeout(function(){topInsert()}, 500); // с той, что СВЕРХУ над ней //
setTimeout(function(){rightInsert()}, 500); // с той, что СПРАВА от неё //
setTimeout(function(){bottomInsert()}, 500); // с той, что СНИЗУ под ней //
приведу пример одной из функций, т.к. они все подобны.
// функция сравнение ответной карты с той, что снизу под ней //
function bottomInsert () {
var x;
if (insertComp.data('user') != bottomComp.data('user') || insertComp.data('user') != bottomSs.data('user')) {
if (insertComp.data('bottom') > bottomComp.data('top') || insertComp.data('bottom') > bottomSs.data('top')) {
bottomComp.data('user', 2);
bottomSs.data('user', 2);undefined
if (bottomSs.data('user') === 1) {
x = green(bottomSs);
u2++;
} else if (bottomSs.data('user') === 2) {
x = red(bottomSs);
u2 +=2;
u1--;
}
if (bottomComp.data('user') === 1) {
x = green(bottomComp);
u2++;
} else if (bottomComp.data('user') === 2) {
x = red(bottomComp);
u2 +=2;
u1--;
}
}
}
return x, u1, u2;
}
Извиняюсь, что кучу всего приплёл, но теперь ПЕРЕХОДИМ К САМОМУ ИНТЕРЕСНОМУ. В принципе сама проблема представлена ниже, а всё что выше, для понимания из-за чего это может возникать. И так, если я пишу вот так:
appendCard('[data-id='+($(this).data('id')+1)+']');
То всё прекрасно работает. Крата вставляется справа от перетаскиваемой, производятся все логические проверки на сравнения с другими картами и т.д. Правда, конечно, за исключением того, что карта вставляется сразу же без задержки. Если тут вызвать:
alert($('[data-id='+($(this).data('id')+1)+'] .ssComp').data('user')); // возвращает 2. как и положено
Ну а мне как раз нужно сделать паузу в этом моменте. Поэтому я пишу так:
setTimeout(function(){appendCard.call(self, '[data-id='+(self.data('id')+1)+']')}, 1000);
Здесь карта вставляется куда нужно, но логика проверок отваливается. Если вызвать:
alert($('[data-id='+($(this).data('id')+1)+'] .ssComp').data('user')); // возвращает undefined.
хотя если наполнить игровые поля картами и например тут вызвать так:
alert($('[data-id='+($(this).data('id')+4)+'] .ssComp').data('user')); // вернёт 2 как и положено (или 1 в зависимости от карты и какой класс указать ss или ssComp).
Главное что this работает корректно.
alert($('[data-id='+($(this).data('id')+1)+']').data('id')); // так же возвращает верное значение. ( в зависимости куда перту перетащить)
хотя с таймером:
setTimeout(function(){alert($('[data-id='+($(this).data('id')+1)+']').data('id'))}, 1500); // возвращает undefined.
:blink: Чего-то я явно не понимаю. Но что-то явно загадочное происходит в следовании друг за другом этих методов setTimeout. |
tomberty,
потому что когда setTimeout запустит функцию this будет window |
Хорошо, но ведь я же указал контекст для this:
var self = $(this); {appendCard.call(self, . . . } |
tomberty,
не очень понятно ... вы что хотите карту в карту вставить? |
карта вставляется в ячейку справа, если это ячейка пустая, от той карты, которую перетащили. Если ячейка занята, то будет вставляться под ней, затем слева или сверху. по наличию свободных мест. Но это я опустил, т.к. там всё одно и тоже везде.
Вправо я её вставляю с задержкой вот так:
setTimeout(function(){appendCard.call(self, '[data-id='+(self.data('id')+1)+']')}, 2000);
на данном этапе сама вставка работает правильно, но теперь:
alert($('[data-id='+($(this).data('id')+1)+'] .ssComp').data('user')); // возвращает undefined.
у этой карты (ssComp), есть ещё другие дата атрибуты помимо юзера и ко всем не достучаться. как будто он не видет в ней карту (ssComp). Хотя если смотреть через firebug, то видно что элемент ssComp там точно находиться. Например если просто сейчас просто обратиться к ячейке по data-id то всё Ок:
alert($('[data-id='+($(this).data('id')+1)+']').data('id'));
Но именно карты он не видит. И ещё раз подчеркну, что если писать вставку без таймаута:
appendCard.call(self, '[data-id='+(self.data('id')+1)+']');
То:
alert($('[data-id='+($(this).data('id')+1)+'] .ssComp').data('user'));
работает корректно. Что-то этот setTimeout явно делает не понятные мне вещи.... |
tomberty,
не пишите this |
после вставки карты, даже если я обращусь к конкретной ячейке (заранее понимая куда комп вставит карту ответным ходом), например вот так:
alert($('[data-id='+4+'].ssComp').data('user'));
Всё равно - undefined. однако, если заполнить игровое поля картами и обратиться допустим к другой ячейке, то всё Ок:
alert($('[data-id='+5+'].ssComp').data('user'));
Рони, спасибо что пытаешься помочь. |
tomberty,
задержка то зачем нужна? |
Я вот тут экспериментирую, и заметил одну ОЧЕНЬ странную вещь. После которой мне теперь кажется что вся проблема с очерёдностью обработки...
Сейчас, коротко для понимания, объясню принцип игровой логики. У каждой карты есть 4 цифры (от 1 до 10 ) по бокам (сверху снизу справа слева). Когда карта вставляется, она сравнивает 4 карты вокруг себя. То есть, например, вы поставили в игровое поле карту, у которой СПРАВА число 8, соответственно, она побьёт карту СПРАВА от себя, если у той число СЛЕВА будет меньше 8 (от 1 до 7 ). и так для всех сторон. Так вот, тут комп вставляет карту и потом она сравнивается по сторонам. В этом примере приведу только сравнение с левой картой (то есть с той, что перетащил юзер):
setTimeout(function(){appendCard.call(self, '[data-id='+(self.data('id')+1)+']')}, 2000); // комп вставляет карту справа
var leftSs = $('[data-id='+$(this).data('id')+'] .ss'); // карта слева от вставляемой
setTimeout(function(){leftInsert()}, 1000); // функция leftInsert сравнивает левую цифру вставляемой карты, с правой цифрой карты, слева от вставляемой (нде .... =)) )
сейчас пример не работает, но стоит добавить alert, и Главное нажать на всплывающем окне ОК в промежутке после 2000мс но не более 3000мс, то проверка leftInsert СРАБАТЫВАЕТ, и если условия соответствующие (то есть левая цифра больше правой), то карта слева от вставляемой бьётся:
setTimeout(function(){appendCard.call(self, '[data-id='+(self.data('id')+1)+']')}, 2000); // комп вставляет карту справа
alert($('[data-id='+(self.data('id')+1)+'] .ssComp').data('user'));
var leftSs = $('[data-id='+$(this).data('id')+'] .ss'); // карта слева от вставляемой
setTimeout(function(){leftInsert()}, 1000); // функция leftInsert сравнивает левую цифру вставляемой карты, с правой цифрой карты, слева от вставляемой (нде .... =)) )
И да, если это будет любой другой alert, например такой: alert('dfgdsfghs'); то эта штука уже не прокатывает... Короче полтергейст какой-то блин!!! Вот сама функция leftInsert:
var insertComp = $('[data-id='+($(this).data('id')+1)+'] .ssComp');
function leftInsert () {
var x;
if (insertComp != 0 || insertComp != 3 || insertComp != 6) {
if (insertComp.data('user') != leftComp.data('user') || insertComp.data('user') != leftSs.data('user')) {
if (insertComp.data('left') > leftComp.data('right') || insertComp.data('left') > leftSs.data('right')) {
leftComp.data('user', 2);
leftSs.data('user', 2);
if (leftSs.data('user') === 1) {
x = green(leftSs);
u2++;
} else if (leftSs.data('user') === 2) {
x = red(leftSs);
u2 +=2;
u1--;
}
if (leftComp.data('user') === 1) {
x = green(leftComp);
u2++;
} else if (leftComp.data('user') === 2) {
x = red(leftComp);
u2 +=2;
u1--;
}
} else { return u2++; }
}
}
return x, u1, u2;
}
|
задержка, просто для красоты, а то не успел Юзер ещё свою карту перетащить, как комп сразу же ходит, практически одновременно.
|
| Часовой пояс GMT +3, время: 14:35. |