循环多次覆盖元素的样式?

时间:2019-11-15 08:05:02

标签: javascript jquery css css-grid

我有一个简单的菜单,当前正在使用要动画的CSS Grid。但是,grid-template-columns不能流畅地设置动画。我现在正在做的菜单完全不同,但是在寻找解决方案时,遇到了一些我不太想知道的事情。我的第一个想法虽然可能根本不是个好主意,并且可能不是关键帧动画的合适替代方案,但我的想法是在while循环中更新样式以动画化不断增加的项目大小。它不起作用。

相关的JS:

    $('#select-oak').hover(function () {
            let start = new Date().getTime();
            let elapsed = 0;

            while (elapsed <= 1000) {
                elapsed = new Date().getTime() - start;
                let val = elapsed / 1000;

                if (elapsed % 100 === 0) {
                    $('.selector-block').css('grid-template-columns', `${1.0 + val}fr 1fr 1fr 1fr`);
                    console.log(1 + val);
                    console.log(elapsed);
                }
            }
        }

CSS:

.selector-block {
    position: relative;
    overflow: hidden;
    top: -32.5vh;
    background-color: white;
    gap: 5px;
    width: 100vw;
    height: 90vh;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr 1fr;
    clip-path: polygon(0 36%, 100% 0, 100% 60%, 0% 100%);
    z-index: 3;
}

#select-oak {
    position: relative;
    overflow: hidden;
    text-align: center;
    background-color: rgb(94, 80, 21);
    top: 21.5%;
    width: 100%;
    height: 200%;
}

#select-oak img {
    position: relative;
    left: -10vw;
    transform: scale(1.06);
    filter: blur(5px);
}

#select-oak img:hover {
    filter: none;
    transform: scale(1.1);
    transition: ease-in-out 0.5s;
}

这似乎是一种非常规的方法,所以我并不惊讶它没有起作用,但是由于我对CSS,JS和JQuery还是比较陌生,所以我对阻止这种方法起作用只是出于好奇我对使用JQuery和CSS的理解。这是结果。如您所见,即使打印出正确的值,它也不会更新直到循环的最后一遍。

Example

所以我有两个问题:

  1. 这是我的代码有问题还是只是您无法做到的事情?
  2. 如果可以更新这样的样式,这是一种不好的做法,为什么?

2 个答案:

答案 0 :(得分:1)

while循环阻止了渲染过程,因为它是同步的。

我想出了一种使用CSS过渡的方法,可以确定子元素的数量。 它还可以处理鼠标离开甚至从一个菜单项移动到另一个菜单项的问题。

$('.selector-block > *').hover(function() {
  let frValues = Array($(this).siblings().length+1).fill('1fr');
  frValues[$(this).prevAll().length] = '2fr';
  $('.selector-block').css({
    'grid-template-columns': frValues.join(' ')
  });
}, function() {
  let frValues = Array($(this).siblings().length+1).fill('1fr');
  $('.selector-block').css({
    'grid-template-columns': frValues.join(' ')
  });
});
.selector-block {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  transition: all 1s ease-in-out;
}

.selector-block > * {
  border: solid red 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="selector-block"><div id="select-oak">select-oak</div><div>foobar</div><div>baz</div><div>bat</div></div>

如果子元素的数量是固定的,则只能通过:nth-child()选择器和:hover()使用CSS,而不能使用JavaScript,但是通过这种方式,您可以动态地实际上,您不能这样做,因为您需要从孩子的悬停处触发父母的属性动画,这是不可能的。

旧答案:

您正在寻找window.requestAnimationFrame()。这是如何工作的基本演示。您必须调整值以实现更平滑的过渡,并顺理成章地使鼠标离开元素。

let start;
let elapsed = 0;
let rafHandle;

function hoverAnimation() {
  if (elapsed <= 1000) {
    elapsed = new Date().getTime() - start;
    let val = elapsed / 1000;

    $('.selector-block').css('grid-template-columns', `${1.0 + val}fr 1fr 1fr 1fr`);
    //console.log(1 + val);
    //console.log(elapsed);
    window.setTimeout(function() {
      rafHandle = window.requestAnimationFrame(hoverAnimation);
    }, 1000/60); // about 60 FPS
  }
}

$('#select-oak').hover(function() {
  start = new Date().getTime();
  elapsed = 0;
  rafHandle = window.requestAnimationFrame(hoverAnimation);
}, function() {
  // handle mouse leave animation here instead
  window.cancelAnimationFrame(rafHandle);
  elapsed = Infinity;
  $('.selector-block').css('grid-template-columns', `1fr 1fr 1fr 1fr`);
});
.selector-block {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="selector-block"><div id="select-oak">select-oak</div><div>foobar</div><div>baz</div><div>bat</div></div>

答案 1 :(得分:0)

执行JavaScript会阻止呈现页面,只有在代码执行返回事件循环后才会发生。

尽管更改样式属性可能会更新DOM并影响元素位置和大小的动态计算,但更新屏幕的时间会一直推迟到脚本完成为止。这就是为什么您只看到最后一次更新的结果。

A1 :您不会影响同步JavaScript循环内的页面显示。

A2 :这不是不好的做法,因为它不能完成:-)