demo地址
CSS3的filter
CCS3中增加了关于filater相关的一些方法。我们看看MDN上兼容性
除了IE基本全支持了。
下面的是指如果直接使用SVG的filter的支持程度,目前只有火狐支持,不过我们不使用直接使用svg来实现滤镜。
SVG
mdn上的介绍
SVG的标签与HTML的很相似,基本上可以直接使用。
在前端中主要使用它来制作一些小的图标和小动画,因为相对于栅格图形而言,矢量图内存大小更大,也不好制作。
并且由于CSS3的强大性能,很多动画直接使用CSS3就可以完成很好了。
2者的碰撞
这个demo主要使用到的CSS3中的filter
属性与SVG中相关的filter
标签
-
安装JS动画库
gsap
npm install -S gsap
-
编辑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; }
-
在对应的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'); }
-
添加鼠标点击事件
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;
}
};
};