在视口上为 SVG 元素设置动画

Posted

技术标签:

【中文标题】在视口上为 SVG 元素设置动画【英文标题】:Animating SVG element on viewport 【发布时间】:2014-10-13 06:30:10 【问题描述】:

我的问题和我之前的问题Triggering css animate class on scroll有关

我试图弄清楚如何在内部 SVG 元素类上触发视口 javascript。 您可以在此处查看示例:http://codepen.io/anon/pen/Afqza

<div style="height: 400px;"></div>
<svg version="1.1" id="lock" xmlns="http://www.w3.org/2000/svg"   viewBox="0 0 103 103" ><g><g><g><g><circle style="fill:#E84849;" cx="51.5" cy="51.501" r="51.125"/></g></g></g></g><g><g><g class="shackle"><path style="fill:#CFC7BE;" d="M78.345,46.518c0-14.869-11.813-28.387-26.386-28.387c-14.573,0-26.386,13.518-26.386,28.387h6.829c0-11.021,8.756-21.419,19.557-21.419s19.557,10.398,19.557,21.419H78.345z"/><path style="fill:#E8E7E7;" d="M61.385,20.101v7.816c3.039,1.927,5.583,4.717,7.362,7.975V24.879C66.562,22.886,64.076,21.26,61.385,20.101z"/></g><g><path style="fill:#F4E028;" d="M78.358,79.801c0,3.116-2.579,5.642-5.765,5.642H31.281c-3.186,0-5.764-2.525-5.764-5.642V46.419c0-3.116,52.841-3.116,52.841,0V79.801z"/></g><g><path style="fill:#DAC425;" d="M58.047,59.944c0-3.253-2.638-5.89-5.889-5.89c-3.253,0-5.889,2.637-5.889,5.89c0,2.481,1.536,4.599,3.705,5.468v5.431c0,1.151,0.935,2.084,2.085,2.084c1.153,0,2.086-0.933,2.086-2.084v-5.36C56.418,64.666,58.047,62.498,58.047,59.944z"/></g><g><path style="fill:#D0B82B;" d="M46.048,59.944c0-3.253,2.637-5.89,5.891-5.89c0,0-4.105,2.737-4.105,5.99c0,3.312,3.097,5.276,3.097,5.276v5.581c0,1.153,1.104,2.024,1.104,2.024c-1.15,0-2.085-0.933-2.085-2.084v-5.36C47.677,64.666,46.048,62.498,46.048,59.944z"/></g></g><g><polygon style="fill:#F8E349;" points="68.747,85.442 61.385,85.442 61.385,44.219 68.747,44.585 "/></g></g></svg>


    .shackle 

     animation-name: open;
    -webkit-animation-name: open;   
    animation-duration: 0.5s;   
    -webkit-animation-duration: 0.5s;
    transform: rotate(0deg);
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
    -webkit-transform: rotate(0deg);
    transform-origin: bottom left;



@keyframes open 
    0% 
        transform: rotate(0deg);    
    
    50% 
        transform: rotate(-10deg);
    
    100% 
        transform: rotate(0deg);    
                           


@-webkit-keyframes open 
    0% 
        -webkit-transform: rotate(0deg);    
    
    50% 
        -webkit-transform: rotate(-10deg);
    
    100% 
        -webkit-transform: rotate(0deg);    
    



var onAppear = [];

document.addEventListener("DOMContentLoaded", function() 
  onAppear = [].map.call(document.querySelectorAll("#lock"), function(item ) 
    return item;
  );
, false);

window.addEventListener("scroll", function() 
  onAppear.forEach(function(elem) 
    var vwTop = window.pageYOffset;
    var vwBottom = (window.pageYOffset + window.innerHeight);
    var elemTop = elem.offsetTop;
    var elemHeight = elem.offsetHeight;

    if (vwBottom > elemTop && ((vwTop - elemHeight) < elemTop)) 
     elem.classList.add("shackle");
     else 
      elem.classList.remove("shackle");
    
  );
, false);

目前整个挂锁动画,而不是我想要动画的枷锁。 一定很简单,但我想不通。

【问题讨论】:

您正在将 'shackle' 类添加到 svg,您需要将其添加到类 handlesvg 元素中 对不起,我的错,我的班级名称有误。但是,这并不能解决问题。枷锁元素仍然没有动画。 你能用你更新的代码更新你的codepen吗:) 谢谢,codepen 也更新了=) 【参考方案1】:

问题是您没有将动画类应用于 shackle 元素,而是将其应用于 lock 元素。

因为您正在使用 CSS3 和 SVG,我可以假设您不需要适应 IE7 及以下版本。因此,我们可以假设使用 JS 的 querySelector 方法是安全的。

    首先,我们将更新样式定义以指示该类用于动画定义(并将其与用于选择它的 shackle 元素上的类分开)。

    在 CSS 中将 .shackle 更改为 .animShackle

    其次,我们需要更新滚动事件侦听器以在提供的元素中搜索 .shackle 分类元素,然后将动画类应用于该元素。

    更新 JS

JS

window.addEventListener("scroll", function() 
  onAppear.forEach(function(elem) 
    var vwTop = window.pageYOffset;
    var vwBottom = (window.pageYOffset + window.innerHeight);
    var elemTop = elem.offsetTop;
    var elemHeight = elem.offsetHeight;
    var shackle = elem.querySelector('.shackle');

    if (vwBottom > elemTop && ((vwTop - elemHeight) < elemTop)) 
     shackle.classList.add("animShackle");
     else 
      shackle.classList.remove("animShackle");
    
  );
, false);

更新

为了使代码更易于扩展,以满足具有自己动画的附加元素的需求,我们需要更改一些变量名称,让它们感觉更通用,并更新我们获取和设置动画类的方式。

    为动画 SVG 添加一个通用类,以便我们可以在我们的 onAppear 函数中找到它们

    添加类animatedSVG 更新querySelectorAll 方法以使用新类而不是单个id

    更新 SVG 中动画元素的类名,以便我们可以在滚动 onAppear.forEach 方法中访问它

    html 中将类 .shackle 更新为 .animatedElement 更新elem.querySelector 方法以使用新类而不是非泛型.shackle

    使用 SVG 的 id 属性为动画创建类名

    添加一个名为 animationClass 的新变量,该变量由 SVG id 制成,并带有 'anim' 前缀

HTML 现在需要以下三样东西:

    id SVG 上的属性 class="animatedSVG" 在 SVG 上 class="animatedElement" 在 SVG 中您希望制作动画的元素上

更新的 JS

var onAppear = [];

document.addEventListener("DOMContentLoaded", function() 
  onAppear = [].map.call(document.querySelectorAll(".animatedSVG"), function(item) 
    return item;
  );
, false);

window.addEventListener("scroll", function() 
  onAppear.forEach(function(elem) 
    var vwTop = window.pageYOffset;
    var vwBottom = (window.pageYOffset + window.innerHeight);
    var elemTop = elem.offsetTop;
    var elemHeight = elem.offsetHeight;
    var animatedElem = elem.querySelector('.animatedElement');
    var animationClass = 'anim'+elem.id;

    if (vwBottom > elemTop && ((vwTop - elemHeight) < elemTop)) 
     animatedElem.classList.add(animationClass);
     else 
      animatedElem.classList.remove(animationClass);
    
  );
, false);

DEMO

【讨论】:

谢谢,这行得通!还有一个问题,如果我有几个具有不同动画类的 SVG?我将如何修改 JS 代码。例如。带有类“指针”的 SVG Id“时钟”。

以上是关于在视口上为 SVG 元素设置动画的主要内容,如果未能解决你的问题,请参考以下文章

在 Internet Explorer 中的曲线路径上为 SVG 设置动画

如何在 mouseover/mouseout (SMIL) 上为内联 SVG 的填充属性设置动画

使用 gimp 在大图像上为视屏设置动画

需要帮助清理 SVG 动画

如何在键盘外观上为 Flutter 布局设置动画

在没有 JS 库的情况下在 <canvas> 上为 spritesheet 设置动画 [重复]