Without further ado, let’s take a look at the effect.

Other tutorial

First of all, most of the other tutorials on the market use images to create this kind of effect, which I think lacks scalability and playability.

The article brief introduction

  1. This article will usejsCreate a thumbs-up effect with particle effect.
  2. The grammatical environment of this paper isvue3.2.

🖖🖖🖖 Let's get started

SVG love image

I chose SVG images here because SVG can modify the content of an image with CSS and JS, such as filling a part of an SVG image with a color.

SVG is a scalable vector image file format that uses xmL-formatted files to describe images. So it can be easily embedded in HTML pages, and we can adjust SVG images with CSS and JS control. Introduction of SVG at THE W3C

First of all, we will add icon font or picture in the front end. Here we can choose to use the commonly used Alibaba icon vector library in China

Steps to download the SVG material

  1. Search for ICONS by keyword

  1. Find the icon you like and click the download button (the download button appears after mouse hover)

  1. Click on theCopying SVG codeThe SVG image is downloaded

  1. Paste the code we copied directly into the code
<template>
    <div id="app">
        <! Here is the SVG code we just copied -->
        <svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="20" height="20">
            <path d="M533.504 268.288q33.792-41.984 71.68-75.776 32.768-27.648 74.24-50.176t86.528-19.456q63.488 5.12 105.984 30.208t67.584 63.488 34.304 87.04 6.144 99.84-17.92 97.792-36.864 87.04-48.64 74.752-53.248 61.952 Q-40.96 41.984-85.504 78.336 T-84.992 62.464 73.728 41.472 51.712 15.36 q - 20.48 1.024-52.224-14.336 t - 69.632-41.472-79.872-61.952-82.944-75.776 q - 26.624-25.6-57.344-59.392 t - 57.856-74.24-46.592-87.552-21 .504-100.352 11.264-99.84 39.936-83.456 65.536-61.952 88.064-35.328q24.576-5.12 49.152-1.536t48.128 12.288 45.056 22.016 40.96 27.648q45.056 33.792 86.016 80.896z" p-id="2432"></path>
        </svg>
    <div>
</template>
Copy the code

Learn how to edit SVG images using CSS

How to use CSS to edit SVG images

<! Add class attribute -->.<svg class="mySvg">.</svg>.Copy the code
// Use the class selector.mySvg{// Fill SVG with red fill: red; // Add border stroke to SVG: $Gray; // Border color stroke-width: 80px; // border size}Copy the code

Create particle diffusion effect

I’m using a lightweight one hereJs graphics animation library.

  1. First we installmo.js
npm install @mojs/core
Copy the code
  1. Introduced in the page
// Introduce the moJS module
import mojs from '@mojs/core';
<script>
export default {
    setup(){
        / / use mojs
        new mojs.Timeline()
    }
}
</script>
Copy the code

The version used for this article is “@mojs/core”: “^1.3.0”

  1. The effect of spreading out the heart here is inmo.jscalledBurstChinese meaning “burst”, according to the official website we can complete the following code.
const heart = ref(null); .new mojs.Burst({
    // Burst range {from size: to size}
    radius: {0: 50},
    // Animate the mounted parent element, if not default mounted to 
    parent: heart.value,
    // Animation delay bezier curve function
    easing:  mojs.easing.bezier(0.1.1.0.3.1),
    // Animation delay time
    duration: 1500.// The waiting time before the animation moves (150ms is generally set here to reduce the possible lag of low-end models)
    delay: 300.// Diffuse particle configuration
    children: {
        duration: 750.// Particle size transform {from size: to size}
        // rand(from, to) the rand function can help us randomly calculate the value of an interval
        radius: {0: 'rand(5, 25)'},
        // Shape selection, here we select "circle"
        shape: 'circle'.// Particle optional fill color
        fill: ['#1abc9c'.'#2ecc71'.'#00cec9'.'#3498db'.'#9b59b6'.'#fdcb6e'.'#f1c40f'.'#e67e22'.'#e74c3c'.'#e84393']},/ / transparency
    opacity: 0.6.// The number of particles generated
    count: 10.onStart(){
        // The hook function before the animation triggers
    },
    onComplete(){
        // The hook function after the animation is complete
    }
}).play();
Copy the code

Note here that the.play() method needs to be called at the end to get the animation moving

Mojs provides a lot of shape animation effects and even controls the playback progress of the animation. We will not introduce them here. If you have any questions, please feel free to discuss them in the comments section.

Make it outside the red starflush

I’ve drawn a hollow circle here

const heart_icon = ref(null); .new mojs.Transit({
    // Animate the mounted parent element, if not default mounted to 
    parent: heart.value,
    // Animation delay time
    duration: 750.// The type of the graph, select circle here
    type: 'circle'.// radius {from large: to large}
    radius: { 0: 20 },
    // Fill with transparent color
    fill: 'transparent'.// Border color
    stroke: '#E05B5B'.// Width of the frame {from thick: to thick}
    strokeWidth: { 20: 0 },
    / / transparency
    opacity: 0.6.// Animation delay bezier curve function
    easing: mojs.easing.bezier(0.1.0.5.1)})Copy the code

Make a like status lock

The lock here is mainly used to prevent the animation from being played frequently, and the animation only needs to be played when the unliked state transitions to the liked state.

<template>.<svg :style="heartStyle" @click="thumbsUp">.</svg>.</template>

<script>
import { ref, computed, onMounted } from 'vue'
import mojs from '@mojs/core';
export default { 
    setup(){
        // Whether to like
        const hearted = ref(false);
        
        / / thumb up
        function thumbsUp(){
            if(! hearted.value){new mojs.Burst({
                    onStart(){
                        // ---------------- send a like request ----------------
                        hearted.value = true
                    },
                }).play();
            }else{
                / / cancel the praise
                hearted.value = false}}// Style of heart
        const heartStyle = computed(() = >{
            return {
                fill: `${hearted.value?'#E05B5B':' '}`.stroke: `${hearted.value?'#E05B5B':' '}`}})return {
            hearted,
            thumbsUp
        }
    }
}
</script>
Copy the code

Timeline in MOJS

The Timeline object in MOJS is primarily used to handle animations that need to be played at the same time.

/ / glow
let aperture = newmojs.Transit({... })// Particle diffusion
let burst = newmojs.Burst({... })// Heart bounce effect
let bounce = newmojs.Tween({... })// Add animations to the same timeline
new mojs.Timeline().add(burst, aperture, bounce).play();
Copy the code

Add a billion details and you’re done

All the source code

<template>
    <div class="oper-item" @click="thumbsUp">
        <div class="heart" ref="heart">
            <svg ref="heart_icon" :style="heartStyle" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="20" height="20"><path d="M533.504 268.288q33.792-41.984 71.68-75.776 32.768-27.648 74.24-50.176t86.528-19.456q63.488 5.12 105.984 30.208t67.584 63.488 34.304 87.04 6.144 99.84-17.92 97.792-36.864 87.04-48.64 74.752-53.248 61.952 Q-40.96 41.984-85.504 78.336 T-84.992 62.464 73.728 41.472 51.712 15.36 q - 20.48 1.024-52.224-14.336 t - 69.632-41.472-79.872-61.952-82.944-75.776 q - 26.624-25.6-57.344-59.392 t - 57.856-74.24-46.592-87.552-21 .504-100.352 11.264-99.84 39.936-83.456 65.536-61.952 88.064-35.328q24.576-5.12 49.152-1.536t48.128 12.288 45.056 22.016 40.96 27.648q45.056 33.792 86.016 80.896z" p-id="2432"></path></svg>
        </div>
        <span class="oper-text">120 like</span>
    </div>
</template>

<script>
import { ref, computed, onMounted } from 'vue'
import mojs from '@mojs/core';
export default {
    name: 'ZcCardArticle'.setup(){
        // Whether to like
        const hearted = ref(false);
        // Click the like button
        const heart = ref(null);
        const heartP = ref(1);
        const heartStyle = computed(() = >{
            return {
                fill: `${hearted.value?'#E05B5B':' '}`.stroke: `${hearted.value?'#E05B5B':' '}`.transform: `scale3d(${heartP.value}.${heartP.value}`, 1)}})// The body of the heart
        const heart_icon = ref(null);
        / / diffusion
        let burst
        // Red aperture
        let aperture
        / / bounce
        let bounce
        onMounted(() = >{
            aperture = new mojs.Transit({
                parent: heart.value,
                duration: 750.type: 'circle'.radius: { 0: 20 },
                fill: 'transparent'.stroke: '#E05B5B'.strokeWidth: { 20: 0 },
                opacity: 0.6.isRunLess: true.easing: mojs.easing.bezier(0.1.0.5.1)
            })

            burst = new mojs.Burst({
                    radius: {0: 50},
                    parent: heart.value,
                    easing:  mojs.easing.bezier(0.1.1.0.3.1),
                    // duration: 1500,
                    delay: 300.children: {
                        duration: 750.radius: {0: 'rand(5, 25)'},
                        shape: ['circle'.'rect'.'polygon'].fill: ['#1abc9c'.'#2ecc71'.'#00cec9'.'#3498db'.'#9b59b6'.'#fdcb6e'.'#f1c40f'.'#e67e22'.'#e74c3c'.'#e84393'].degreeShift: 'rand(-90, 90)'.delay: 'stagger(0, 40)',},opacity: 0.6.count: 10.onStart(){
                        // Send a like request
                        hearted.value = true
                       
                    },
                    onComplete(){}}); bounce =new mojs.Tween({
                    duration: 1200.onUpdate: function(progress) {
                        if (progress > 0.3) {
                        heartP.value = mojs.easing.elastic.out(1.43 * progress - 0.43);
                        // heart_icon.value.style.transform = 'scale3d(' + elasticOutProgress + ',' + elasticOutProgress + ',1)';
                    } else {
                        heartP.value = 0
                        / / heart_icon. Value. Style. Transform = 'scale3d (0, 1)';}}})})/ / thumb up
        function thumbsUp(){
            if(! hearted.value){new mojs.Timeline().add(burst, aperture, bounce).play();
            }else{
                / / cancel the praise
                hearted.value = false}}return {
            hearted,
            heart,
            heartStyle,
            heart_icon,
            burst,
            thumbsUp,
            aperture,
            bounce,
            heartP
        }
    }
}
</script>

<style lang="scss" scoped>
.oper-item{
    display: flex;
    align-items: center;
    justify-content: center;
    width: 33%;
    height: 24px;
    border-right: 1px solid rgba(#9A9DAA.3);
    cursor: pointer;
}
.oper-item:last-child{
    border: none;
}
.oper-item i{
    color: #9A9DAA;
    font-size: 18px;
}
.oper-item .heart{
    height: 20px;
    position: relative;
    display: inline-block;
}
.oper-item .heart svg{
    transition: fill .3s, stroke .3s;
    stroke: #9A9DAA;
    stroke-width: 80px;
    fill: transparent;
}
.oper-item:hover .heart svg{
    stroke: #E05B5B;
}
.oper-text{
    margin-left: 12px;
    font-size: 13px;
    user-select: none;
}
</style>
Copy the code

Possible problems (continuously updated)

1. MakerefPositioning element configurationparent: heart.valueMay come upundefinedIn theonMountedCreate an animation in.

Your thumbs up is the biggest motivation for me to write more, the more thumbs up there will be more motivation to update 🤣🤣🤣.