Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 17.09.2015, 22:22
Новичок на форуме
Отправить личное сообщение для tomberty Посмотреть профиль Найти все сообщения от tomberty
 
Регистрация: 17.09.2015
Сообщений: 9

Почему после использования 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.


Чего-то я явно не понимаю. Но что-то явно загадочное происходит в следовании друг за другом этих методов setTimeout.
Ответить с цитированием
  #2 (permalink)  
Старый 17.09.2015, 22:43
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,068

tomberty,
потому что когда setTimeout запустит функцию this будет window
Ответить с цитированием
  #3 (permalink)  
Старый 17.09.2015, 23:05
Новичок на форуме
Отправить личное сообщение для tomberty Посмотреть профиль Найти все сообщения от tomberty
 
Регистрация: 17.09.2015
Сообщений: 9

Хорошо, но ведь я же указал контекст для this:
var self = $(this);
{appendCard.call(self, . . . }
Ответить с цитированием
  #4 (permalink)  
Старый 17.09.2015, 23:13
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,068

tomberty,
не очень понятно ... вы что хотите карту в карту вставить?
Ответить с цитированием
  #5 (permalink)  
Старый 18.09.2015, 08:27
Новичок на форуме
Отправить личное сообщение для tomberty Посмотреть профиль Найти все сообщения от tomberty
 
Регистрация: 17.09.2015
Сообщений: 9

карта вставляется в ячейку справа, если это ячейка пустая, от той карты, которую перетащили. Если ячейка занята, то будет вставляться под ней, затем слева или сверху. по наличию свободных мест. Но это я опустил, т.к. там всё одно и тоже везде.
Вправо я её вставляю с задержкой вот так:
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 явно делает не понятные мне вещи....
Ответить с цитированием
  #6 (permalink)  
Старый 18.09.2015, 09:04
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,068

tomberty,
не пишите this
Ответить с цитированием
  #7 (permalink)  
Старый 18.09.2015, 09:20
Новичок на форуме
Отправить личное сообщение для tomberty Посмотреть профиль Найти все сообщения от tomberty
 
Регистрация: 17.09.2015
Сообщений: 9

после вставки карты, даже если я обращусь к конкретной ячейке (заранее понимая куда комп вставит карту ответным ходом), например вот так:
alert($('[data-id='+4+'].ssComp').data('user'));

Всё равно - undefined.
однако, если заполнить игровое поля картами и обратиться допустим к другой ячейке, то всё Ок:
alert($('[data-id='+5+'].ssComp').data('user'));


Рони, спасибо что пытаешься помочь.
Ответить с цитированием
  #8 (permalink)  
Старый 18.09.2015, 09:54
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,068

tomberty,
задержка то зачем нужна?
Ответить с цитированием
  #9 (permalink)  
Старый 18.09.2015, 09:55
Новичок на форуме
Отправить личное сообщение для tomberty Посмотреть профиль Найти все сообщения от tomberty
 
Регистрация: 17.09.2015
Сообщений: 9

Я вот тут экспериментирую, и заметил одну ОЧЕНЬ странную вещь. После которой мне теперь кажется что вся проблема с очерёдностью обработки...
Сейчас, коротко для понимания, объясню принцип игровой логики. У каждой карты есть 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;
      }

Последний раз редактировалось tomberty, 18.09.2015 в 11:07.
Ответить с цитированием
  #10 (permalink)  
Старый 18.09.2015, 09:56
Новичок на форуме
Отправить личное сообщение для tomberty Посмотреть профиль Найти все сообщения от tomberty
 
Регистрация: 17.09.2015
Сообщений: 9

задержка, просто для красоты, а то не успел Юзер ещё свою карту перетащить, как комп сразу же ходит, практически одновременно.
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск