我有一个网络项目,我想要动画的不透明的五个彩色div导致他们“眨眼”的顺序,然后用户会按相同的顺序(如西蒙说)。演示序列从用户单击按钮时开始,该按钮也会消失,因此只能单击一次。我的代码如下(仅用于演示动画,目前不涉及用户响应):
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,但不想为这个特定的项目引入任何其他动画库或插件
发布于 2018-05-20 03:34:48
递归地:
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)
发布于 2018-05-20 03:34:18
您可以为animate
创建一个包装器函数,该函数返回承诺,还可以将circleBlink
转换为返回承诺的函数。您还可以使用箭头函数来避免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
});
发布于 2018-05-20 04:07:49
使用$.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语法,您可以利用在jQuery 3.0中现在实现许诺/A+规格这一事实,并使用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>
https://stackoverflow.com/questions/50431389
复制相似问题