javascript - Ordering jQuery functions or rotating an element at different speeds in the same program
问题描述
I am trying to write a flashcards program. The user should have the ability to go to the next/previous card using the arrow keys and flip the card (by clicking or pressing the spacebar). The flip animation is done by css styling the card with:
transition: transform 0.8s;
Then, the flip animation is performed as follows:
if (flipped) {
$('.card').css('transform', 'none');
} else {
$('.card').css('transform', 'rotateY(180deg)');
}
The issue is that if the user is on the back of the card and presses the arrow key to go to the next card, I would like the user to see the FRONT of the next card. Essentially, if the card is flipped, I would like the card to flip over in zero seconds instead of 0.8s and then go to the next card.
So far I have tried something like:
function next_card() {
if(flipped) {
$('.card').css('transition', 'transform 0s')
.css('transform', 'none')
.css('transition', 'transform 0.8s');
}
// Go to next card
}
However, the program executes css('transition', 'transform 0.8s') before css('transform', 'none') making the code useless. I have tried to look into deferreds and promises as a way to ensure that the functions execute in the correct order but I am not a very experienced programmer and got confused about how to apply them to my situation.
Edit: make a jsfiddle here: https://jsfiddle.net/bjfy3tmc/28/ to illustrate the issue. The problem is that when the user is on the back of a card and then goes to the next or previous card, the card should shown the FRONT of the next card and not see a flip animation at all.
解决方案
You should allow the paint cycle to execute with the first CSS changes, so you will only reset the CSS to the 0.8 sec transformation after that has happened.
You can use requestAnimationFrame
for that. The callback you pass will be executed just before the next repaint, which is still too early. But if you call requestAnimationFrame
again within that callback, and pass it yet another callback, that callback will be scheduled to execute after the current repaint, and before the next, which is what you want.
So:
$('.card-inner').css('transition', 'transform 0s')
.css('transform', 'none');
requestAnimationFrame(function () {
requestAnimationFrame(function () {
$('.card-inner').css('transition', 'transform 0.8s');
})
});
This still means that there is one frame where the next card is shown (with the back side). To also prevent that, put the rest of the code (which sets the front/end content) in an else
block, and call iter
a second time when it is sure that the new CSS is in effect:
function iter(x) {
if($('.card-inner').css('transform') != 'none') {
$('.card-inner').css('transition', 'transform 0s')
.css('transform', 'none');
requestAnimationFrame(function () {
requestAnimationFrame(function () {
iter(x);
$('.card-inner').css('transition', 'transform 0.8s');
})
})
} else if(index+x < front_cards.length && index+x >= 0) {
$('.front').html(front_cards[index+x]);
$('.back').html(back_cards[index+x]);
index += x;
}
}
Or, alternatively, always use the callback system to go to the next/prev card:
function iter(x) {
if($('.card-inner').css('transform') != 'none') {
$('.card-inner').css('transition', 'transform 0s')
.css('transform', 'none');
}
requestAnimationFrame(function () {
requestAnimationFrame(function () {
if(index+x < front_cards.length && index+x >= 0) {
$('.front').html(front_cards[index+x]);
$('.back').html(back_cards[index+x]);
index += x;
}
$('.card-inner').css('transition', 'transform 0.8s');
})
});
}
推荐阅读
- node.js - Docker- 基于 Node.js 的图像的父图像
- react-native - 如何在react -native中更改/更新redux中存储的值
- python-3.x - 如何使用 git clone 代码解决语法错误?
- c# - 使用 TestCaseSource 时无法在 VS2019 测试资源管理器的列表中看到单个测试结果
- prometheus - 所有可用指标的 Prometheus 端点
- angular - 监听 HTTPEvent 时未定义 Angular 事件
- node.js - 如何增加 mongoDB 中多个文档的持续时间?
- javascript - React将ajax数据传递给孩子
- awk - 根据bash中的另一个文件删除文件的特定部分
- c++ - 为什么 operator!= 在 C++20 中为许多标准库类型删除?