我正在尝试创建一个很棒的微交互,但是遇到了一个小问题。
document.querySelector('button').onclick = function(){
const
items = document.querySelector('nav').children
if (items[0].getBoundingClientRect().top >= document.querySelector('nav').getBoundingClientRect().bottom){
// start showing elements, starting from the left side
for (let i = 0; i < items.length; i++){
setTimeout(function(){
items[i].style.transform = 'translateY(0)'
}, i * 200)
}
} else {
// start hiding elements, starting from the right side
for (let i = 0; i < items.length; i++){
setTimeout(function(){
items[i].style.transform = 'translateY(100%)'
}, (items.length-1 - i) * 200)
}
}
}
button {
width: 100px;
height: 50px;
}
nav {
width: 50vw;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
background: red;
}
nav > a {
width: 100%;
height: 50px;
transition: .5s transform;
transform: translateY(100%);
opacity: 0.5;
background: lime;
}
<button>Toggle</button>
<nav>
<a href=''></a>
<a href=''></a>
<a href=''></a>
<a href=''></a>
</nav>
如果您连续切换得太快,则最终将显示某些项目,而最终会将其隐藏。
这是由于以下事实:在发布新的setTimeouts
组时,还有待执行的setTimeouts
待执行。
显然,解决此问题的方法很多,例如不反转动画的顺序,等到动画完全完成后再允许反转等,但我宁愿不做出这样的妥协。
我尝试在if
和else
块中使用和切换全局布尔值,然后在if/else
块中使用附加的setTimeout
语句,但这没用。
我还尝试在应用新的transition
值之前动态设置transform
延迟,而不是依靠setTimeout
来解决这个问题。
是否有简单的方式来取消或忽略旧的周期中的任何待处理setTimeouts
?
答案 0 :(得分:2)
我将简化您的逻辑,并考虑在transition-delay
中只需要切换一个类。诀窍是,当我们切换类以获得所需的效果时,您的元素会有不同的延迟。
使用此配置,您不会有任何问题,因为自从类被添加到其父元素以来,所有元素都将具有相同的状态。
var nav = document.querySelector('nav');
document.querySelector('button').onclick = function(){
nav.classList.toggle('top');
}
button {
width: 100px;
height: 50px;
}
nav {
width: 50vw;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
background: red;
--d:0.2s;
}
nav > a {
width: 100%;
height: 50px;
transition: .5s transform;
transform: translateY(100%);
opacity: 0.5;
background: lime;
}
nav.top > a {
transform: translateY(0);
}
nav > a:nth-last-child(1) { transition-delay:calc(0 * var(--d));}
nav > a:nth-last-child(2) { transition-delay:calc(1 * var(--d));}
nav > a:nth-last-child(3) { transition-delay:calc(2 * var(--d));}
nav > a:nth-last-child(4) { transition-delay:calc(3 * var(--d));}
nav.top > a:nth-child(1) { transition-delay:calc(0 * var(--d));}
nav.top > a:nth-child(2) { transition-delay:calc(1 * var(--d));}
nav.top > a:nth-child(3) { transition-delay:calc(2 * var(--d));}
nav.top > a:nth-child(4) { transition-delay:calc(3 * var(--d));}
<button>Toggle</button>
<nav>
<a href=''></a>
<a href=''></a>
<a href=''></a>
<a href=''></a>
</nav>
我们可以通过对元素进行相同延迟的分组来简化CSS代码:
var nav = document.querySelector('nav');
document.querySelector('button').onclick = function(){
nav.classList.toggle('top');
}
button {
width: 100px;
height: 50px;
}
nav {
width: 50vw;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
background: red;
--d:0.2s;
}
nav > a {
width: 100%;
height: 50px;
transition: .5s transform;
transform: translateY(100%);
opacity: 0.5;
background: lime;
}
nav.top > a {
transform: translateY(0);
}
nav > a:nth-last-child(1),
nav.top > a:nth-child(1) { transition-delay:calc(0 * var(--d));}
nav > a:nth-last-child(2),
nav.top > a:nth-child(2) { transition-delay:calc(1 * var(--d));}
nav > a:nth-last-child(3),
nav.top > a:nth-child(3){ transition-delay:calc(2 * var(--d));}
nav > a:nth-last-child(4),
nav.top > a:nth-child(4){ transition-delay:calc(3 * var(--d));}
<button>Toggle</button>
<nav>
<a href=''></a>
<a href=''></a>
<a href=''></a>
<a href=''></a>
</nav>
答案 1 :(得分:0)
This anwer显示了清除所有<CustomTabsNavigator isAdmin={true} />
的好方法-只需将其添加到setTimeout
语句的每个部分中即可:
if/else
document.querySelector('button').onclick = function() {
const
items = document.querySelector('nav').children
if (items[0].getBoundingClientRect().top >= document.querySelector('nav').getBoundingClientRect().bottom) {
var id = window.setTimeout(() => {}, 0);
while (id--) {
window.clearTimeout(id);
}
// start showing elements, starting from the beginning
for (let i = 0; i < items.length; i++) {
setTimeout(function() {
items[i].style.transform = 'translateY(0)'
}, i * 200)
}
} else {
var id = window.setTimeout(() => {}, 0);
while (id--) {
window.clearTimeout(id);
}
// start hiding elements, starting from the back
for (let i = 0; i < items.length; i++) {
setTimeout(function() {
items[i].style.transform = 'translateY(100%)'
}, (items.length - 1 - i) * 200)
}
}
}
button {
width: 100px;
height: 50px;
}
nav {
width: 50vw;
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-gap: 10px;
background: red;
}
nav>a {
width: 100%;
height: 50px;
transition: .5s transform;
transform: translateY(100%);
opacity: 0.5;
background: lime;
}