避免JS

时间:2018-05-20 03:26:57

标签: javascript jquery

我有一个网络项目,我希望动画五个彩色div的不透明度,使他们“眨眼”#34;按顺序,然后用户将以相同的顺序点击它们(如Simon所说)。当用户单击按钮时,演示序列开始,按钮也淡出,因此只能单击一次。我的代码是这样的(仅用于演示动画,不关心用户当前的响应):

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但不想为此特定项目引入任何其他动画库或插件

3 个答案:

答案 0 :(得分:3)

您可以为animate创建一个返回Promise的包装函数,并将circleBlink转换为返回Promise的函数。您还可以使用箭头功能来避免that = this

的丑陋
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
});

答案 1 :(得分:2)

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

$.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)
});
.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;
}
<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()函数:

$.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)
});
.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;
}
<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语法,您可以利用$.Deferred() in jQuery 3.0现在实现Promises/A+ specification的事实,并使用async / await使其非常简洁:

$.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()
})
.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;
}
<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 :(得分:1)

递归:

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)