【问题标题】:How to restart updated animation after dynamically changing keyframes?动态更改关键帧后如何重新启动更新的动画?
【发布时间】:2018-11-07 09:15:38
【问题描述】:

我正在尝试使用动画text-indent 创建一个选框(是的,我首先对该主题进行了很多搜索)。与我尝试过的其他解决方案相比,我更喜欢这种解决方案,例如使用 100% 翻译,这会导致文本泄漏到我的选框边界之外。

我一直在尝试遵循这个例子:https://www.jonathan-petitcolas.com/2013/05/06/simulate-marquee-tag-in-css-and-javascript.html

...我已经更新了一点,在 TypeScript 中进行,使用 API 更新(appendRule 而不是insertRule)并放弃对旧浏览器支持的担忧。

问题是动画使用旧的关键帧规则重新启动——注释“重新分配动画(使其运行)”所描述的步骤不起作用。

我查看了调试器中发生的情况,发现规则肯定会发生变化——删除了旧规则,添加了新规则。但就好像旧规则被缓存在某个地方,它们并没有被清除。

这是我当前的 CSS:

#marquee {
  position: fixed;
  left: 0;
  right: 170px;
  bottom: 0;
  background-color: midnightblue;
  font-size: 14px;
  padding: 2px 1em;
  overflow: hidden;
  white-space: nowrap;
  animation: none;
}

#marquee:hover {
  animation-play-state: paused;
}

@keyframes marquee-0 {
  0% {
    text-indent: 450px;
  }

  100% {
    text-indent: -500px;
  }
}

还有我的 TypeScript 的相关部分:

function updateMarqueeAnimation() {
  const marqueeRule = getKeyframesRule('marquee-0');

  if (!marqueeRule)
    return;

  marquee.css('animation', 'unset');

  const element = marquee[0];
  const textWidth = getTextWidth(marquee.text(), element);
  const padding = Number(window.getComputedStyle(element).getPropertyValue('padding-left').replace('px', '')) +
                  Number(window.getComputedStyle(element).getPropertyValue('padding-right').replace('px', ''));
  const offsetWidth = element.offsetWidth;

  if (textWidth + padding <= offsetWidth)
    return;

  marqueeRule.deleteRule('0%');
  marqueeRule.deleteRule('100%');
  marqueeRule.appendRule('0% { text-indent: ' + offsetWidth + 'px; }');
  marqueeRule.appendRule('100% { text-indent: -' + textWidth + 'px; }');

  setTimeout(() => marquee.css('animation', 'marquee-0 15s linear infinite'));
}

到目前为止,我已经尝试了很多技巧来解决这个问题,包括克隆选框元素并用自己的克隆替换它,但这些都没有帮助 - 动画继续运行,就好像原始样式表值生效,因此选取框的滚动不适应不同宽度的文本。

接下来我可能会尝试动态创建新的关键帧对象,而不是编辑现有关键帧对象中的规则,但如果有人有更好的解决方案,我宁愿避免这种混乱的解决方案。

【问题讨论】:

    标签: javascript jquery css typescript animation


    【解决方案1】:

    我找到了一种让我的选取框工作的方法,它确实涉及从样式表中动态添加和删除关键帧规则,但这并不像我想象的那样痛苦或丑陋。

    let animationStyleSheet: CSSStyleSheet;
    let keyframesIndex = 0;
    let lastMarqueeText = '';
    
    function updateMarqueeAnimation(event?: Event) {
      const newText = marquee.text();
    
      if (event === null && lastMarqueeText === newText)
        return;
    
      lastMarqueeText = newText;
      marquee.css('animation', 'none');
    
      const element = marquee[0];
      const textWidth = getTextWidth(newText, element);
      const padding = Number(window.getComputedStyle(element).getPropertyValue('padding-left').replace('px', '')) +
                      Number(window.getComputedStyle(element).getPropertyValue('padding-right').replace('px', ''));
      const offsetWidth = element.offsetWidth;
    
      if (textWidth + padding <= offsetWidth)
        return;
    
      if (!animationStyleSheet) {
        $('head').append('<style id="marquee-animations" type="text/css"></style>');
        animationStyleSheet = ($('#marquee-animations').get(0) as HTMLStyleElement).sheet as CSSStyleSheet;
      }
    
      if (animationStyleSheet.cssRules.length > 0)
        animationStyleSheet.deleteRule(0);
    
      const keyframesName = 'marquee-' + keyframesIndex++;
      const keyframesRule = `@keyframes ${keyframesName} { 0% { text-indent: ${offsetWidth}px } 100% { text-indent: -${textWidth}px; } }`;
      const seconds = (textWidth + offsetWidth) / 100;
    
      animationStyleSheet.insertRule(keyframesRule, 0);
      marquee.css('animation', `${keyframesName} ${seconds}s linear infinite`);
    }
    

    这里还有其他东西,一般解决方案不需要。一件事是调用此方法有两个原因:正在调整窗口大小,或者已对选取框文本进行了更新。我总是想在调整窗口大小时更新,但如果文本没有改变,我不想更新动画,否则当有人试图阅读它时它可能会不必要地重置。

    另一件事是,如果文本恰好适合而不滚动,我根本不希望文本滚动。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 2021-03-31
      • 1970-01-01
      • 2017-05-10
      • 2021-12-18
      • 2020-06-15
      • 1970-01-01
      相关资源
      最近更新 更多