我有一个网络项目,我希望动画五个彩色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但不想为此特定项目引入任何其他动画库或插件
答案 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)