水波纹效果,多功能-vue组件
2022-02-03 本文已影响0人
littlesunn
1643746641656202222437161.gif
<template>
<div class="water-ripples-container" ref="water-ripples-container" @[trigger]="onActive">
<div ref="ripples" :class="{'out-ripples': isOut, 'inset-ripples': type == 'inset',
'animate-always--out': isActive && trigger == 'always' && type == 'out',
'animate-once--out': isActive && (trigger == 'mouseenter' || trigger == 'click') && type == 'out',
'animate-always--inset': isActive && trigger == 'always' && type == 'inset',
'animate-once--inset': isActive && (trigger == 'mouseenter' || trigger == 'click') && type == 'inset',
}" :style="{
borderRadius: isOut ? borderRadius : '50%',
'--ripple-color': color,
'--spread-width': spreadWidth,
'--spread-size': mySpreadSize,
}"></div>
<slot />
</div>
</template>
<script>
export default {
props: {
type: {
type: String,
default: "out" // out/inset
},
color: {
type: String,
default: "#337ab7"
},
borderRadius: {
type: String,
default: "0"
},
spreadWidth: {
type: String,
default: "8px"
},
trigger: {
type: String,
default: "always" // always/mouseenter/click/focus
},
spreadSize: {
type: String,
default: null
}
},
data() {
return {
isActive: false,
mySpreadSize: '0px'
}
},
computed: {
isOut() {
return this.type == "out"
}
},
mounted() {
this.initWidth();
},
watch: {
trigger: {
handler(val) {
this.isActive = (val == "always")
},
immediate: true
}
},
methods: {
onActive() {
this.isActive = true
},
initWidth() {
let container = this.$refs['water-ripples-container']
let ripples = this.$refs['ripples']
if (this.type == "out") {
this.$refs['ripples'].style.width = container.clientWidth + "px";
} else {
container.style.overflow = "hidden";
if (!this.spreadSize) {
this.mySpreadSize = container.clientWidth * 1.1 + "px"
}else {
this.mySpreadSize = this.spreadSize
}
console.log(this.spreadSize, "this.spreadSize");
}
ripples.addEventListener('animationend', () => {
this.isActive = false
}, false);
}
}
}
</script>
<style scoped lang="scss">
.water-ripples-container {
position: relative;
display: inline-block;
.slot-container {
position: relative;
z-index: 2;
}
.out-ripples {
position: absolute;
left: 0;
top: 0;
height: 100%;
opacity: 1;
z-index: 1;
pointer-events: none;
}
.animate-once--out {
animation: ripple-effect 1s forwards;
}
.animate-always--out {
animation: ripple-effect 1s infinite;
}
@keyframes ripple-effect {
0% {
box-shadow: 0 0 0 0px var(--ripple-color);
opacity: 1;
}
100% {
box-shadow: 0 0 0 var(--spread-width) var(--ripple-color);
opacity: 0;
}
}
.inset-ripples {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
opacity: 1;
width: 0px;
height: 0px;
background: red;
pointer-events: none;
}
@keyframes size-effect {
0% {
width: 0px;
height: 0px;
opacity: 0.8;
}
100% {
width: var(--spread-size);
height: var(--spread-size);
opacity: 0;
}
}
.animate-once--inset {
animation: size-effect 1s forwards;
}
.animate-always--inset {
animation: size-effect 1s infinite;
}
}
</style>