css3的filter与svg动画的碰撞

demo地址

CSS3的filter

CCS3中增加了关于filater相关的一些方法。我们看看MDN上兼容性
在这里插入图片描述
除了IE基本全支持了。
下面的是指如果直接使用SVG的filter的支持程度,目前只有火狐支持,不过我们不使用直接使用svg来实现滤镜。

SVG

mdn上的介绍
SVG的标签与HTML的很相似,基本上可以直接使用。
在前端中主要使用它来制作一些小的图标和小动画,因为相对于栅格图形而言,矢量图内存大小更大,也不好制作。
并且由于CSS3的强大性能,很多动画直接使用CSS3就可以完成很好了。

2者的碰撞

这个demo主要使用到的CSS3中的filter属性与SVG中相关的filter标签

  1. 安装JS动画库gsap

    npm  install -S gsap 
    
  2. 编辑SVG标签

     <svg xmlns="http://www.w3.org/2000/svg" version="1.1" class="svg-filters">
          <defs>
            <filter id="filter-glitch-3">
            <!-- 波荡 -->
              <feTurbulence type="fractalNoise" baseFrequency="0.0" numOctaves="1" result="warp" ref="turb" />
            </filter>
          </defs>
        </svg>
    
    .svg-filters {
      position: absolute;
      visibility: hidden;
      width: 1px;
      height: 1px;
    }
    
  3. 在对应的DOM元素上添加相应的配置,url的配置就是SVG上的ID。

    <div class='div'></div>
    // css
    .div{
      position: fixed;
      width: 100%;
      height:500px;
      min-width: 1200px;
      cursor: pointer;
      filter: url('#filter-glitch-3');
    }
    
  4. 添加鼠标点击事件

    import { TimelineLite, Power0 } from 'gsap';
    const cardClick = function(e) {
      const svg = document.querySelector('#filter-glitch-3 feTurbulence');
      const turbVal = { val: 0.0 };
      const turbValX = { val: 0.0 };
      const lineLite = new TimelineLite({
        onUpdate() {
          svg.setAttribute('baseFrequency', `${turbVal.val} ${turbValX.val}`);
        },
        onComplete() {
          lineLite.reverse();
        },
        onReverseComplete() {
          lineLite.restart();
        },
      });
      lineLite.to(turbVal, 5, { val: 0.2, ease: Power0.easeNone }, 0);
    };
    

    我们这里简单的分析下这里的一些设置
    主要是一个插值运算的事件,我们设置了初始值与终点值,点击时候就开始变化。

    const turbVal = new TimelineLite({
    	onComplete(){
    		lineLite.reverse();// 往返运动 回复为原来的值
    	},// 完成事件
    	onUpdate(){// 数值变化触发的事件钩子
    		// 变化过程中进行设置 SVG上的属性值 这样CSS才能检测到波荡指数的变化,从而产生动画效果
    		svg.setAttribute('baseFrequency', `${turbVal.val} ${turbValX.val}`);
    	},
    	 onReverseComplete() {// 往返运动完成事件钩子
    	      lineLite.restart();// 重新开始
    	 },
    })
    

    配置好之后就可以开始动画了。

    // 第一个参数我们配置好的TimelineLite实例 
    // 第二个是变化的时间
    // 第三个是我们变化的目标值 ease是变化的效果
    // 第四个是重复的次数
     lineLite.to(turbVal, 5, { val: 0.2, ease: Power0.easeNone }, 0);
    

    初始值为对象模式,是因为闭包决定的,如果直接使用number的话,在update中就无法获取到变化的值。
    gsap提供了很多其它丰富的方法,上手简单,有兴趣的同学可以尝试下。中文文档网址

优化的地方

由于点击事件中如果触发多次就会创建多个TimelineLite的实例,并且同时存在多个事件并行,为了解决这个问题,我们有2个方法,第一种是全局变量,只能存在一个动画事件。第二种是利用闭包,也是同样的原理,目的是为了减少全局变量的命名。
这个是防抖

const cardClick = function(filterId) {
  let oldlineLite;
  return () => {
    const svg = document.querySelector(`#${filterId} feTurbulence`);
    const turbVal = { val: 0.0 };
    const turbValX = { val: 0.0 };
    const newLineLite = new TimelineLite({
      onStart() {
        // 停止上一次的动画
        if (oldlineLite) {
          oldlineLite.kill();
        }
        oldlineLite = newLineLite;
      },
      onUpdate() {
        console.log('更新');
        svg.setAttribute('baseFrequency', `${turbVal.val} ${turbValX.val}`);
      },
      onComplete() {
        console.log('onComplete');
		oldlineLite = null// 释放内存
      },
    });
    newLineLite.to(turbVal, 3, { val: 0.005, ease: Power0.easeNone }, 0);
  };
};

这个是节流

const cardClick = function(filterId) {
  let oldlineLite;
  return () => {
    const svg = document.querySelector(`#filter-${filterId} feTurbulence`);
    const turbVal = { val: 0.0 };
    const turbValX = { val: 0.0 };
    const newLineLite = new TimelineLite({
      onUpdate() {
        svg.setAttribute('baseFrequency', `${turbVal.val} ${turbValX.val}`);
      },
      onComplete() {
        oldlineLite = null;
        newLineLite.reverse();
      },
    });

    if (oldlineLite) {
      newLineLite.kill();
    } else {
      newLineLite.to(turbVal, 1, { val: 0.005, ease: Power0.easeNone }, 0);
      oldlineLite = newLineLite;
    }
  };
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值