首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >避免JS中的连续动画回调地狱

避免JS中的连续动画回调地狱
EN

Stack Overflow用户
提问于 2018-05-20 03:26:57
回答 3查看 223关注 0票数 2

我有一个网络项目,我想要动画的不透明的五个彩色div导致他们“眨眼”的顺序,然后用户会按相同的顺序(如西蒙说)。演示序列从用户单击按钮时开始,该按钮也会消失,因此只能单击一次。我的代码如下(仅用于演示动画,目前不涉及用户响应):

代码语言:javascript
运行
复制
function circleBlink(elem, callback) {
  elem.animate({'opacity':'0'}, function() {
    elem.animate({'opacity':'1'}, function() {
      if (callback && typeof callback === 'function') {
        callback();
      }
    });
  });
}

function runThrough() {
  circleBlink($('.sequence-options > .red-orange'), function() {
    circleBlink($('.sequence-options > .blue'), function() {
      circleBlink($('.sequence-options > .yellow'), function() {
        circleBlink($('.sequence-options > .green'), function() {
          circleBlink($('.sequence-options > .purple'));
        });
      });
    });
  });
}

$('.start-btn').click(function() {
  $that = $(this);
  $that.animate({'opacity': '0'}, function() {
    $that.addClass('hidden');
  });
  runThrough();
  setTimeout(runThrough, 5000);

});

代码工作正常,但我想知道是否有一种较少的、更多的性能/最佳实践方法来重构它。我正在使用jQuery,但不想为这个特定的项目引入任何其他动画库或插件

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2018-05-20 03:34:48

递归地:

代码语言:javascript
运行
复制
function runThrough(colors, index) {
    if(index < colors.length){return;}
    circleBlink($('.sequence-options > .'+colors[index]), function() {
        runThrough(colors, index+1);
    });
}

//don't forget the init index! my bad!
runThrough(['red-orange', 'blue', 'yellow', 'purple', 'etc', 'etc'], 0)
票数 1
EN

Stack Overflow用户

发布于 2018-05-20 03:34:18

您可以为animate创建一个包装器函数,该函数返回承诺,还可以将circleBlink转换为返回承诺的函数。您还可以使用箭头函数来避免that = this的丑陋。

代码语言:javascript
运行
复制
const animateWithOpacity = (jqElm, opacity) => new Promise(resolve => {
  jqElm.animate({ opacity }, resolve);
});
async function circleBlink(elem) {
  await animateWithOpacity(elem, '0');
  await animateWithOpacity(elem, '1');
  // async function will automatically return promise that resolves when end is reached
}

async function runThrough() {
  const classes = ['red-orange', 'blue', 'yellow', 'green', 'purple'];
  for (const className of classes) {
    await circleBlink($('.sequence-options > .' + className));
  }
}

$('.start-btn').click(function() {
  animateWithOpacity($(this), 0)
    .then(() => $(this).addClass('hidden'));
  runThrough();
  setTimeout(runThrough, 5000);
  // might also be able to `runThrough().then(runThrough)` if the timing is right
});
票数 3
EN

Stack Overflow用户

发布于 2018-05-20 04:07:49

使用$.Deferred() (jQuery的原生Promise对象的版本),您可以很好地链接它们,而无需嵌套回调或递归:

代码语言:javascript
运行
复制
$.fn.blink = function () {
  return this
    .animate({ opacity: 0 })
    .animate({ opacity: 1 })
    .promise()
}

function sequence () {
  return $.Deferred().resolve().then(function () {
    return $('.sequence-options > .red-orange').blink()
  }).then(function () {
    return $('.sequence-options > .blue').blink()
  }).then(function () {
    return $('.sequence-options > .yellow').blink()
  }).then(function () {
    return $('.sequence-options > .green').blink()
  }).then(function () {
    return $('.sequence-options > .purple').blink()
  })
}

$('.start-btn').click(function() {
  $(this)
    .animate({ opacity: 0 })
    .addClass('hidden')
    .promise()
    .then(sequence)
    .then(sequence)
});
代码语言:javascript
运行
复制
.circle {
  width: 1em;
  height: 1em;
  border-radius: 50%;
}

.red-orange {
  background-color: orangered;
}

.blue {
  background-color: blue;
}

.yellow {
  background-color: yellow;
}

.green {
  background-color: green;
}

.purple {
  background-color: purple;
}
代码语言:javascript
运行
复制
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="start-btn">Start</button>
<div class="sequence-options">
  <div class="circle red-orange"></div>
  <div class="circle blue"></div>
  <div class="circle yellow"></div>
  <div class="circle green"></div>
  <div class="circle purple"></div>
</div>

进一步缩小这个范围,您可以预先计算一些基本的引用,并从它们各自的类选择器生成每个.then()函数:

代码语言:javascript
运行
复制
$.fn.blink = function () {
  return this
    .animate({ opacity: 0 })
    .animate({ opacity: 1 })
    .promise()
}

var $options = $('.sequence-options')
var selectors = ['.red-orange', '.blue', '.yellow', '.green', '.purple']
var circles = selectors.map(function (selector) {
  return $options.children(selector)
})
var animations = circles.map(function ($circle) {
  return function () {
    return $circle.blink()
  }
})

function sequence () {
  return animations.reduce(function (deferred, animation) {
    return deferred.then(animation)
  }, $.Deferred().resolve())
}

$('.start-btn').click(function() {
  $(this)
    .animate({ opacity: 0 })
    .addClass('hidden')
    .promise()
    .then(sequence)
    .then(sequence)
});
代码语言:javascript
运行
复制
.circle {
  width: 1em;
  height: 1em;
  border-radius: 50%;
}

.red-orange {
  background-color: orangered;
}

.blue {
  background-color: blue;
}

.yellow {
  background-color: yellow;
}

.green {
  background-color: green;
}

.purple {
  background-color: purple;
}
代码语言:javascript
运行
复制
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="start-btn">Start</button>
<div class="sequence-options">
  <div class="circle red-orange"></div>
  <div class="circle blue"></div>
  <div class="circle yellow"></div>
  <div class="circle green"></div>
  <div class="circle purple"></div>
</div>

最后,使用ES2017语法,您可以利用在jQuery 3.0中现在实现许诺/A+规格这一事实,并使用async / await使其非常简洁:

代码语言:javascript
运行
复制
$.fn.blink = function () {
  return this
    .animate({ opacity: 0 })
    .animate({ opacity: 1 })
    .promise()
}

const $options = $('.sequence-options')
const selectors = ['.red-orange', '.blue', '.yellow', '.green', '.purple']
const circles = selectors.map(selector => $options.children(selector))
const animations = circles.map($circle => () => $circle.blink())

async function sequence () {
  for (const animation of animations) {
    await animation()
  }
}

$('.start-btn').click(async function () {
  const $this = $(this)

  await $.when($this.animate({ opacity: 0 }))
  $this.addClass('hidden')
  await sequence()
  await sequence()
})
代码语言:javascript
运行
复制
.circle {
  width: 1em;
  height: 1em;
  border-radius: 50%;
}

.red-orange {
  background-color: orangered;
}

.blue {
  background-color: blue;
}

.yellow {
  background-color: yellow;
}

.green {
  background-color: green;
}

.purple {
  background-color: purple;
}
代码语言:javascript
运行
复制
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<button class="start-btn">Start</button>
<div class="sequence-options">
  <div class="circle red-orange"></div>
  <div class="circle blue"></div>
  <div class="circle yellow"></div>
  <div class="circle green"></div>
  <div class="circle purple"></div>
</div>

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50431389

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档