Wave组件为antd中许多元素提供了点击扩散特效的支持,例如Button、Checkbox和Radio等。



特点
Wave本身是一个组件,将需要实现点击特效的元素通过props.children传入。无侵入,使用伪元素执行特效,不会破坏原有的Dom层次结构。- 扩散特效颜色跟随被点击元素边框
自动改变。
主要实现
1. bindAnimationEvent
在componentDidMount后会首先调用该方法。1
2
3
4
5
6
7
8
9
10
11
12// dom点击的时候触发该方法
const onClick = (e: MouseEvent) => {
// ...
};
// 给dom添加点击事件
node.addEventListener('click', onClick, true);
// instance 有cancel方法,用于Unmount取消事件绑定
return {
cancel: () => {
node.removeEventListener('click', onClick, true);
},
};
在componentDidMount中通过findDOMNode获取到children所对应的DOM,将函数内定义的onClick(不同于Wave实例的onClick方法)绑定为node点击事件,最后返回一个包含cancel方法的对象,供componenWillUnmount移除事件绑定。
2. node.onClick
Wave会存在两个onClick方法, 一个是实例的onClick方法,另一个是实际绑定在node上的事件方法,也就是这个方法。1
2
3
4
5
6
7
8
9// 恢复状态
this.resetEffect(node);
// 根据边框颜色确定 wave 颜色
const waveColor =
getComputedStyle(node).getPropertyValue('border-top-color') || // Firefox Compatible
getComputedStyle(node).getPropertyValue('border-color') ||
getComputedStyle(node).getPropertyValue('background-color');
// 下一次runloop执行this.onClick 触发动画
this.clickWaveTimeoutId = window.setTimeout(() => this.onClick(node, waveColor), 0);
- 当node点击后,会将
状态清空一次,以防特效动画未结束二次触发。 - 其次会获取node的
边框颜色,为扩散特效提供支持。 - 最后会在下一个
runloop执行实例的onClick方法,真正开始执行特效代码。
3. 执行特效的onClick
1 | const attributeName = 'ant-click-animating-without-extra-node' |
其实wave的特效主要是用css来实现的,onClick方法主要做了三件事:
- 为node添加
attribute,触发node伪元素的css animation来执行特效。 - 动态
向body添加style,设置node伪元素border-color来实现动态切换颜色。 - 借助css-animation库来
监听css-animation结束清除attribute
onClick设置颜色前会检查当前元素的颜色是否为
灰色、白色或者透明,如果满足条件则不会添加style设置,而是直接采用css设定好的primary-color
4. CSS
1 | [ant-click-animating-without-extra-node='true'] { |
最后
Wave组件的精髓在于没有破坏原有Dom结构的情况下,使用CSS伪元素的方法实现特效。这种方式对于我们在编写组件或开源库的时候有借鉴意义。
另外如果我们要将Wave组件用到自己项目的时候,需要注意目前antd的wave只能同时显示一种特效颜色,也就是如果你特效时间设定的比较长,用户有机会让多个特效同时出现的时候,这些特效的颜色永远会显示最后一次特效的颜色。原因是因为动态添加的style标签中的attribute-name都是设定的同一个。可以考虑为attribute-name加入id来解决这个问题。

