利用css
的 过渡和动画效果,点击时给目标元素追加span
标签,通过改变span
的opacity
和scale
即可实现类似水波扩散的效果
我们可以将其封装为自定义指令便于调用。
- 创建 src/directives/waves文件夹
- directives目录下创建index.js。waves文件夹下创建 index.js和waves.css
具体代码如下:
// directives/index.js
export * from './waves'
// waves/index.js
import './waves.css'
export const waves = {
bind(el, binding) {
el.addEventListener('click', e => {
const customOpts = Object.assign({}, binding.value)
const opts = Object.assign({
ele: el, // 波纹作用元素
type: 'hit', // hit 点击位置扩散 center中心点扩展
color: 'rgba(255,255,255,0.3)' // 波纹颜色
}, customOpts)
const target: HTMLElement = opts.ele
if (target) {
target.style.position = 'relative'
target.style.overflow = 'hidden'
// 返回的结果是包含完整元素的最小矩形,并且拥有left, top, right, bottom, x, y, width, 和 height
const rect = target.getBoundingClientRect()
console.log('rect: ', rect);
let ripple = target.querySelector('.waves-ripple') as HTMLElement
if (!ripple) {
ripple = document.createElement('span')
ripple.className = 'waves-ripple'
ripple.style.height = ripple.style.width = Math.max(rect.width, rect.height) + 'px'
target.appendChild(ripple)
} else {
ripple.className = 'waves-ripple'
}
switch (opts.type) {
case 'center':
ripple.style.top = rect.height / 2 - ripple.offsetHeight / 2 + 'px'
ripple.style.left = rect.width / 2 - ripple.offsetWidth / 2 + 'px'
break
default:
ripple.style.top =
(e.pageY - rect.top - ripple.offsetHeight / 2 - document.documentElement.scrollTop ||
document.body.scrollTop) + 'px'
ripple.style.left =
(e.pageX - rect.left - ripple.offsetWidth / 2 - document.documentElement.scrollLeft ||
document.body.scrollLeft) + 'px'
}
ripple.style.backgroundColor = opts.color
ripple.className = 'waves-ripple z-active'
return false
}
}, false)
}
}
// waves/waves.css
.waves-ripple {
position: absolute;
border-radius: 100%;
background-color: rgba(255, 255, 255, 0.3);
background-clip: padding-box;
pointer-events: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transform: scale(0);
-ms-transform: scale(0);
transform: scale(0);
opacity: 1;
z-index: 999;
}
.waves-ripple.z-active {
opacity: 0;
-webkit-transform: scale(2);
-ms-transform: scale(2);
transform: scale(2);
-webkit-transition: opacity 1.2s ease-out, -webkit-transform .3s ease-out;
transition: opacity .6s ease-out, -webkit-transform .3s ease-out;
transition: opacity .6s ease-out, transform .3s ease-out;
transition: opacity .6s ease-out, transform .3s ease-out, -webkit-transform .3s ease-out;
}
// main.js 注册自定义指令
import * as directives from './directives'
Object.keys(directives).forEach(key => {
Vue.directive(key, (directives as { [key: string ]: DirectiveOptions })[key])
})
指令可以接收两个参数
- color:波纹颜色
- type: 扩散位置,center表示从元素中心开始往四周扩散。hit为从点击位置开始扩散
<el-button type="primary" v-waves>查 询</el-button>
<el-button type="primary" v-waves="{color:'rgba(0,0,0,.3)'}">查 询</el-button>
<el-button type="primary" v-waves="{type:'hit'}">查 询</el-button>