在 `visibilitychange` 事件上暂停 CSS 动画。

huangapple go评论58阅读模式
英文:

Pausing css animation on visibilitychange

问题

目标是在用户导航到其他标签页时冻结CSS动画,以便在用户返回时,动画处于与其离开时相同的状态。在可见性更改时设置animationPlayState不起作用,因为动画进度仍在继续,只有在页面再次可见时动画才停止。是否有一种方法可以在不使用不直观的方法或在JavaScript中进行所有动画的情况下实现这一点?

<!DOCTYPE html>
<html>
<head>
    <style>
        .progress-container {
            width: 100%;
            height: 30px;
            background-color: #f3f3f3;
        }

        .progress-bar {
            height: 100%;
            width: 0;
            background-color: #4CAF50;
            animation: progress 30s linear;
        }

        @keyframes progress {
            from { width: 0; }
            to { width: 100%; }
        }
    </style>
</head>
<body>
<div class="progress-container">
    <div class="progress-bar" id="progressBar"></div>
</div>
<script>
    document.addEventListener('visibilitychange', function() {
        let progressBar = document.getElementById('progressBar');

        if (document.hidden) {
            progressBar.style.animationPlayState = 'paused';
        }
    });

    window.onload = function() {
        let progressBar = document.getElementById('progressBar');
        progressBar.style.animationPlayState = 'running';
    };
</script>
</body>
</html>
英文:

the goal is to freeze css animation when user navigates to other tab, so when he navigates back, animation is at the same state as when he left. Setting animationPlayState when visibility changes doesn't work, as the animation progress still continues and animation stops only when page is visible again. Is there a way to do this without using unintuitive hacks or animating everything in js?

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;style&gt;
        .progress-container {
            width: 100%;
            height: 30px;
            background-color: #f3f3f3;
        }

        .progress-bar {
            height: 100%;
            width: 0;
            background-color: #4CAF50;
            animation: progress 30s linear;
        }

        @keyframes progress {
            from { width: 0; }
            to { width: 100%; }
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div class=&quot;progress-container&quot;&gt;
    &lt;div class=&quot;progress-bar&quot; id=&quot;progressBar&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;
    document.addEventListener(&#39;visibilitychange&#39;, function() {
        let progressBar = document.getElementById(&#39;progressBar&#39;);

        if (document.hidden) {
            progressBar.style.animationPlayState = &#39;paused&#39;;
        }
    });

    window.onload = function() {
        let progressBar = document.getElementById(&#39;progressBar&#39;);
        progressBar.style.animationPlayState = &#39;running&#39;;
    };
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;

<!-- end snippet -->

答案1

得分: 1

以下是已翻译的内容:

一种方法如下,代码中包含解释性注释:

<!-- 开始代码片段:js 隐藏:false 控制台:true Babel:false -->

<!-- 语言:lang-js -->
// 简单的实用函数,以减少编写和努力;
// 缓存文档:
const D = document,
  // 实际上是 document.createElement() 的别名,允许我们创建元素并分配属性:
  create = (tag, props) => Object.assign(D.createElement(tag), props),
  // document.querySelector() / element.querySelector() 的别名('context' 变量可以是 document(默认)或元素:
  get = (selector, context = D) => context.querySelector(selector),
  // 仅用于演示的目的,检索用于日志记录的 <ol> 元素:
  log = get('.log'),
  // 检索 .progress-bar 元素:
  progressBar = get('.progress-bar');

// 使用 EventTarget.addEventListener() 将匿名箭头函数绑定为 'visibilitychange' 事件的事件处理程序:
D.addEventListener('visibilitychange', () => {
  // 使用三元运算符设置进度条的 animationPlayState,如果当前可见性(事件后)为隐藏,则返回 "paused",否则返回 "running":
  progressBar.style.animationPlayState = document.visibilityState === 'hidden' ? 'paused' : 'running';

  // 这仅用于演示,不是必需的;在这里,我们创建一个 <li> 元素,并传递 textContent 属性,以记录当前可见性状态和当前宽度(使用 window.getComputedStyle() 检索);创建的 <li> 被传递给 Element.append(),该方法将该 <li> 添加到 'log' 元素中:
  log.append(create('li', {
    textContent: `${document.visibilityState}, at width: ${window.getComputedStyle(progressBar,null).width}`
  }));
});

<!-- 语言:lang-css -->
.progress-container {
  width: 100%;
  height: 30px;
  background-color: #f3f3f3;
}

.progress-bar {
  height: 100%;
  width: 0;
  background-color: #4CAF50;
  animation: progress 30s linear;
}

@keyframes progress {
  from {
    width: 0;
  }
  to {
    width: 100%;
  }
}

<!-- 语言:lang-html -->
<div class="progress-container">
  <div class="progress-bar" id="progressBar"></div>
</div>
<!-- 这只是为了说明演示,不在生产中需要: -->
<ol class="log">
</ol>

<!-- 结束代码片段 -->

JS Fiddle 演示

参考文献:

英文:

One approach is below, with explanatory comments in the code:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

// simple utility functions, to minimise writing/effort;
// caching the document:
const D = document,
  // effectively an alias for document.creatElement(), that allos us
  // to create the element and assign properties:
  create = (tag, props) =&gt; Object.assign(D.createElement(tag), props),
  // alias for document.querySelector()/element.querySelector() (the
  // &#39;context&#39; variable can be either document (default), or an element:
  get = (selector, context = D) =&gt; context.querySelector(selector),
  // this is just for the demo, and retrieves the &lt;ol&gt; element for logging:
  log = get(&#39;.log&#39;),
  // retrieves the .progress-bar element:
  progressBar = get(&#39;.progress-bar&#39;);

// using EventTarget.addEventListener() to bind the anonymous Arrow function
// as the event-handler for the &#39;visibilitychange&#39; event:
D.addEventListener(&#39;visibilitychange&#39;, () =&gt; {
  // setting the progress-bar&#39;s animationPlayState, using a ternary operator,
  // if the current visibility (after the event) is hidden, we return &quot;paused&quot;,
  // otherwise we return &quot;runnning&quot;:
  progressBar.style.animationPlayState = document.visibilityState === &#39;hidden&#39; ? &#39;paused&#39; : &#39;running&#39;;
  
  // this is purely for the demo, and not otherwise required; here we
  // create an &lt;li&gt; element, and pass in the textContent property, to
  // log the current visibilityState, and the current width (retrieved
  // with window.getComputedStyle()); the created &lt;li&gt; is passed to
  // Element.append(), which appends that &lt;li&gt; to the &#39;log&#39; element:
  log.append(create(&#39;li&#39;, {
    textContent: `${document.visibilityState}, at width: ${window.getComputedStyle(progressBar,null).width}`
  }));
});

<!-- language: lang-css -->

.progress-container {
  width: 100%;
  height: 30px;
  background-color: #f3f3f3;
}

.progress-bar {
  height: 100%;
  width: 0;
  background-color: #4CAF50;
  animation: progress 30s linear;
}

@keyframes progress {
  from {
    width: 0;
  }
  to {
    width: 100%;
  }
}

<!-- language: lang-html -->

&lt;div class=&quot;progress-container&quot;&gt;
  &lt;div class=&quot;progress-bar&quot; id=&quot;progressBar&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;!-- this is just to illustrate the demo, and not required in production: --&gt;
&lt;ol class=&quot;log&quot;&gt;
&lt;/ol&gt;

<!-- end snippet -->

JS Fiddle demo.

References:

huangapple
  • 本文由 发表于 2023年5月10日 16:31:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76216392.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定