javascript – jQuery – 嵌套与未通过的转换和动画事件处理程序/侦听器

我目前正在处理一组代码,每次发生某个ajax调用时都会运行.

要做到这一点,我使用下面的代码片段(它错误,因为我认为没有HTML或CSS,但这是好的,因为我只是试图显示我的代码):

$(document).ajaxStart(function() {
  if ($('.spinner').length < 1) { //as there is no ajaxStop, this makes sure there is not already a spinner
    $('body').prepend('<div class="spinner" title="Spinner stuck? Click to remove!"></div>');
  }
  $('body div').not('.spinner').css('opacity', '0.5'); //this is potentially unnecessary
});

//the rest of the ajax call is not included - just the .done()
.done(function(xhr) {
  $('body div').not('.spinner').css('opacity', '0');
  $('body').one('transitionend', function(e) {
    $('body div').not('.spinner').remove();
    $('body').append(xhr);
    $('body div').not('.spinner').css('opacity', '0.1');
    $('body').one('transitionend', function(e) {
      $('body div').css('opacity', '1');
      $('.spinner').remove();
    });
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>

正如你所看到的,我嵌套.one(‘transitionend’)s,我试图找出它是否正确(作为注释:该代码用于处理登录和注销ajax调用响应它大部分时间用于我的登录ajax调用,但目前不能用于注销ajax调用 – 我不认为它正在注册结束$(‘body div’).not(‘.spinner’).css( ‘不透明’,’0.1′);过渡,因为它就是冻结的地方).

我已经把this jsfiddle抛在了一起.它只是测试嵌套与未通过的事件处理程序.

它们(嵌套和未嵌套)似乎工作原理相同(如果你点击其中一个太多次就会冻结它们 – 它发生在嵌套和unnested上 – 但在我添加日志位之后似乎已经修复了 – $(‘#log span’).text($(‘#div1’).text());等).

这是一个片段中的jsfiddle:

var newCss = {
  backgroundColor: 'blue',
  width: '25%',
  color: 'white'
};
var disabled = false;
$(document).on('click', '#div1', function(e) {
  if (disabled) return;
  notNested($(this));
});

$(document).on('click', '#div8', function(e) {
  if (disabled) return;
  nested($(this));
});

function notNested($this) {
  disabled = true;
  $this.css(newCss);
  $('#log span').text($('#div1').text());
  $('#div1').one('transitionend', function() {
    $('#div2').css(newCss);
    $('#log span').text($('#div2').text());
  });
  $('#div2').one('transitionend', function() {
    $('#div3').css(newCss);
    $('#log span').text($('#div3').text());
  });
  $('#div3').one('transitionend', function() {
    $('#div4').css(newCss);
    $('#log span').text($('#div4').text());
  });
  $('#div4').one('transitionend', function() {
    $('#div5').css(newCss);
    $('#log span').text($('#div5').text());
  });
  $('#div5').one('transitionend', function() {
    $('#div6').css(newCss);
    $('#log span').text($('#div6').text());
  });
  $('#div6').one('transitionend', function() {
    $('#div7').css(newCss);
    $('#log span').text($('#div7').text());
  });
  $('#div7').one('transitionend', function() {
    $('div').removeAttr('style');
    $('#log span').text('');
    disabled = false;
  });
}

function nested($this) {
  disabled = true;
  $this.css(newCss);
  $('#log span').text($('#div8').text());
  $('#div8').one('transitionend', function() {
    $('#div9').css(newCss);
    $('#log span').text($('#div9').text());
    $('#div9').one('transitionend', function() {
      $('#div10').css(newCss);
      $('#log span').text($('#div10').text());
      $('#div10').one('transitionend', function() {
        $('#div11').css(newCss);
        $('#log span').text($('#div11').text());
        $('#div11').one('transitionend', function() {
          $('#div12').css(newCss);
          $('#log span').text($('#div12').text());
          $('#div12').one('transitionend', function() {
            $('#div13').css(newCss);
            $('#log span').text($('#div13').text());
            $('#div13').one('transitionend', function() {
              $('#div14').css(newCss);
              $('#log span').text($('#div14').text());
              $('#div14').one('transitionend', function() {
                $('#log span').text('');
                $('div').removeAttr('style');
                disabled = false;
              });
            });
          });
        });
      });
    });
  });
}
body {
  display: flex;
  align-items: flex-start;
  /* Can't remember if flex-start is default anyways*/
}
div {
  display: inline-block;
  width: 25%;
}
div > div {
  border: 4px dotted red;
  transition: .25s;
  display: block;
  width: 10%;
  padding: 4px 8px;
  margin: 16px 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<div>
  <div id="div1">1</div>
  <div id="div2">2</div>
  <div id="div3">3</div>
  <div id="div4">4</div>
  <div id="div5">5</div>
  <div id="div6">6</div>
  <div id="div7">7</div>
</div>
<div id="log">We got to: <span></span>
</div>
<div>
  <div id="div8">8</div>
  <div id="div9">9</div>
  <div id="div10">10</div>
  <div id="div11">11</div>
  <div id="div12">12</div>
  <div id="div13">13</div>
  <div id="div14">14</div>
</div>

So thus, I am trying to figure out, which one is the better to use? Which causes less problems for the code/browser? etc. Is there a better way to control code which depends on transitions (or animations for that matter) to be in a certain state? (Looking for a matter of fact answer, not opinions, 07001)

我已经尝试过研究jQuery的.queue.delay,但是无法在我的场景中工作(可能我使用它们错了).也许这是另一种可能性?我也知道setTimeout()是一种可能性,但为了保持同步,你需要在它之后嵌套元素(并且.one(‘transitionend’)似乎在大多数情况下都适用于你是否嵌套…)

更新:

基于此问题留下的以下评论:

Some minor pointers on your code, don’t do css in Jquery but append/prepend classes with the opacity value. Use variables instead of going through the DOM with every selector. – 07004

我更新了jsfiddle以更改类而不是直接更改CSS. Here是链接(同样,上面的jsfiddle链接已更新).

虽然,我不重复的意思是:

Use variables instead of going through the DOM with every selector.

如果这可能是我的问题的答案,也许有人明白他的意思可以在下面阐述?

最佳答案 你可以使用.queue(),$.map(); .one(“transitionend”)附加到当前转换元素,其中处理程序设置为next,当前元素转换完成时调用队列中的下一个函数;每个元素列的单个事件处理程序,利用.slice()将元素id以“div”开头的所有元素拆分为数组的两个或多个元素;将数组作为event.data传递给事件处理程序;使用$.grep(),.filil();过滤特定列;将元素.data(/ * name * /)的集合设置为true或false,以防止当转换正在进行时,当元素当前正在队列中转换时,转换效果的默认操作; .promise(),. then()在当前队列完成时执行任务

var newCss = {
  backgroundColor: "blue",
  width: "25%",
  color: "white"
}
// define `log` variable as `"#log span"`
, log = $("#log span")
// define `divs` variable as all elements where `id` begins with`` "div"
, divs = $("[id^=div]")
// define `col1` variable as `divs` at indexes `0` through `7`
, col1 = divs.slice(0, 7)
// define `col2` variable as `divs` at indexes `7` through `div.length`
, col2 = divs.slice(7, divs.length);

function queueColumn(col, name) {
  // set current collection of elements `.data("active")` to `true`
  return col.data("active", true)
    // set a queue name with `name`, call `$.map()` on current collection
    .queue(name, $.map(col, function(div) {
     // return a function at queue `name` for each element in collection
      return function(next) {
        // set `log` text
        log.text(
          // pass reference of `next` function in queue `name`
          // as handler for `transitionend` event of current element;
          // call `next` function in queue `name`
          // at `transitionend` event of element
          $(div).one("transitionend", next).css(newCss).text()
        )
      }
    // call first function in queue;
    // when all function in queue `name` complete,
    // return queue `name` jQuery promise object
    })).dequeue(name).promise(name)
}
// handle `click` event at `#div1`, `#div8` elements
function handleQueue(e) {
  // define `curr` variable;
  // filter array containing `col1`, `col2` collections
  // to match collection containing `#div1` or `#div8`     
  var curr = $.grep(e.data, function(col) {
    return col.filter(e.target).length
  }).pop();
  // create `name` for queue
  var name = `col${$.inArray(curr, e.data) + 1}-${$.now()}`;
  // check if `curr` `.data("active")` is `undefined` 
  // at first click of element, if true, 
  // set `curr` `.data("active")` to `false` 
  if (curr.data("active") === undefined) {
    curr.data("active", false);
  }
  if (curr.data("name") === undefined) {
    curr.data("name", name);
  }
  console.log(`queue ${curr.data("name")} is active:`
             , `${!curr.queue(name).length 
                  || curr.data("active")}`);
  // define `inprogress` as `curr.data().active`
  var inprogress = curr.data().active;
  // check if `inprogress` is `false`, if true, call call `queueColumn`
  // with `curr`, `name` as parameters
  // if `#div1` or `#div8` element are clicked during 
  // during queue, while `inprogress` is `true`,
  // return `false` from event handler to prevent
  // multiple queues to be set at `curr` at same time
  return !inprogress
         ? queueColumn(curr, name)
           // do stuff when current queue `name` completes
           // calling all functions in queue array
           .then(function() {
             console.log(`${this.data("name")} queue complete`);
             // remove element `style`, reset `.data()`
             this.removeAttr("style")
             .data({"active": false, "name": void 0});        
            }) 
           // else return `false` 
         : inprogress
}
// at `click` of `#div1`, `#div8`, call `handleQueue`,
// pass array containing `col1`, `col2` as `event.data`
$("#div1, #div8").click([col1, col2], handleQueue);
body {
  display: flex;
  align-items: flex-start;
  /* Can't remember if flex-start is default anyways*/
}
div {
  display: inline-block;
  width: 25%;
}
div > div {
  border: 4px dotted red;
  transition: .25s;
  display: block;
  width: 10%;
  padding: 4px 8px;
  margin: 16px 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js">
</script>
<div>
  <div id="div1">1</div>
  <div id="div2">2</div>
  <div id="div3">3</div>
  <div id="div4">4</div>
  <div id="div5">5</div>
  <div id="div6">6</div>
  <div id="div7">7</div>
</div>
<div id="log">We got to: <span></span>
</div>
<div>
  <div id="div8">8</div>
  <div id="div9">9</div>
  <div id="div10">10</div>
  <div id="div11">11</div>
  <div id="div12">12</div>
  <div id="div13">13</div>
  <div id="div14">14</div>
</div>
点赞