Results show
Thinking points
- Vue V-for dynamically updates waves to generate water ripple data by inserting water ripple data into the waves push operation of the array
- The water ripple uses fixed positioning to map the top and left attributes of the DOM of the water ripple by clicking the clientX and clientY attributes of the event
- Scale amplification is used as the diffusion effect for water ripples, which increases exponentially from inside to outside to simulate the effect of bigger and bigger ripples. The effect of attenuation is realized using opacity property
- Define initial state of each circle of water ripple, and overall transition to scale(1), opacity: 0; And maintain this final state;
- As the number of clicks increases, the DOM grows, periodically checking for clicks and empties the waves array if there are none
- Random generation of ripple size data, rich ripple effect
use
Just reference it in app.vue
The following code
//waves.vue
<template>
<div data-tname="WaveItem">
<div class="main-container">
<div class="waves">
<div class="wave" v-for="(item, key) in waves" :key="key" :style="item">
<div
v-for="n in wavesConfig.total"
:key="n"
class="wave-item"
:style="{transform: 'scale(${0.1 * math.sqrt (n-1)})', // makes the ripple size increase index: 0.3 * (1 / n), // Because the opacity of the overlapping ripples will be superimposed on each other, the smaller the ripples need to be the lower opacity, so as not to overload the center color. AnimationDuration: ${(n-1) * 0.12}s', // The larger the ripple, the later the ripple, to show the effect of gradually spread animationDuration: ${0.6 + n * 0.3 + parseInt(item.width) * 0.002}s', // The animation time of the ripple is gradually increased, showing the effect of the ripple spreading out slowly, the larger the ripple size, the longer the animation time. backgroundColor: wavesConfig.waveColor }"
></div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "WaveItem".data() {
return {
waves: [].wavesConfig: {
maxSize: 300.// the maximum size of the ripple
minSize: 100.// px, minimum size of ripple
zIndexCount: 999.// The z-index value of the wavy parent element
waveColor: "#3E8CE3".// Wave base color
total: 5 // The number of circles
},
clear: {
delay: 5000.timeoutId: null}}; },mounted() {
document.getElementById("app").onclick = e= > {
this.createWave(e);
this.intervalClearWave();
};
},
methods: {
createWave(e) {
// Make the newly generated ripple always overlay on top of the previous ripple
if (this.wavesConfig.zIndexCount > 99999) {
this.wavesConfig.zIndexCount = 999;
} else {
this.wavesConfig.zIndexCount++;
}
// Generate a random ripple size within a certain range
const waveSize = parseInt(
Math.random() * (this.wavesConfig.maxSize - this.wavesConfig.minSize) +
this.wavesConfig.minSize
);
// Add new ripple data
this.waves.push({
left: `${e.clientX - waveSize / 2}px`.top: `${e.clientY - waveSize / 2}px`.zIndex: this.wavesConfig.zIndexCount,
width: `${waveSize}px`.height: `${waveSize}px`
});
},
intervalClearWave() {
clearTimeout(this.clear.timeoutId);
this.clear.timeoutId = setTimeout(() = > {
this.waves = [];
}, this.clear.delay); }}};</script>
<style lang="scss" scoped>
.waves {
.wave {
position: fixed;
pointer-events: none; // Click event penetration, so that mouse click can penetrate ripples, compatible with IE11 and above@keyframes wave {
to{// The ripple becomes larger and more transparenttransform: scale(1);
opacity: 0; }}.wave-item {
width: 100%;
height: 100%;
position: absolute;
border-radius: 100%;
animation: { name: wave; fill-mode: forwards; // Keep the state of the last frame after the animation ends. Timing -function: ease-out; // Ripples spread out gradually}}}}</style>
Copy the code