PK creative Spring Festival, I am participating in the “Spring Festival creative submission contest”, please see: Spring Festival creative submission Contest

preface

Today is the ninth day of the first lunar month, which is also the penultimate day of the activity. It has been three days since I returned to work, but I haven’t finished writing three articles about the Spring Festival. This time brings a Spring Festival card page, using the form of card flipping.

implementation

All of the following implementations are written based on Vue2. Stop scolding, I’m going to learn Vue3

Mouse over the selected effect

As you can see from the renderings above, when the mouse moves over a fuka, the fuka will zoom in and the remaining unselected cards will shrink and become blurred. This visual effect is controlled by CSS and JS.

A similar effect can be achieved using ONLY CSS, but the details are not very good. As soon as I move to the wrap area, it becomes blurred. This scheme ignores the gaps between cards and the effect does not fall exactly on a specific card, as SHOWN below. If you have a better CSS only solution, let us know in the comments section below!

// No hover card becomes blurred.wrap:hover .card{
    filter: blur(25px);
    transform: scale(.6); } // hover card zoom.card:hover {
    transform: scale(1.3);
    filter: none;
}
Copy the code

So we need JS to control it together.

Let’s take a quick look at the HTML structure, where I’ve removed some unnecessary code.

<div class="wrap">
    <div class="card cover" v-for="item in cards" :key="item.id"
                    :class="{ 'blur': item.id ! = hoverId && beginHover, }" 
                    @mouseenter="hoverItem(item)" 
                    @mouseout="reset()">
    </div>
</div>
Copy the code

In the code above, @mouseEnter and @mouseout represent mousein and mouseout events, but the event is triggered when the mouse moves into the div, and only once.

Cards memory card data array, hoverId represents the ID of the card selected by the current mouse, beginHover indicates whether the mouse starts to touch the card.

data(){
    return {
        cards: [{id:0.content:'Start the day'.isTurned:false},
            {id:1.content:'Start the day'.isTurned:false},
            {id:2.content:'Start the day'.isTurned:false},
            {id:3.content:'Start the day'.isTurned:false},
            {id:4.content:'Start the day'.isTurned:false}].hoverId: -1.beginHover: false,}},Copy the code

Let’s look at two more functions. The hoverItem function controls mouse movement of selected cards. My setup here is that if the game is over, it no longer has any effect, so you need to determine whether the game is over. If there is no end, modify the current selected card ID and beginHover, indicating that you can start to blur.

hoverItem(item){
    if(!this.gameOver){
        this.hoverId = item.id
        this.beginHover = true}},reset(){
    this.beginHover = false
},
Copy the code
// No hover card becomes blurred.blur {
    filter: blur(25px);
    transform: scale(.6); } // hover card zoom.card:hover {
    transform: scale(1.3);
    filter: none;
}
Copy the code

To recap, when the mouse moves over the card for the first time, the card is zoomed in and no filters are added, while the rest of the card is zoomed in and blurred.

Card flip effect

PS: The front in this article refers to the cover, that is, the one with the word “fu”.

The card flip is controlled by two divs, front and back.

When clicked, the card is rotated by modifying the Transform property, setting perspective and rotateY. After the rotation, if there is no back, we can see the “back of front”, which has no content, so we need to set our own background color on the back to override and write the text. The important thing to note here is that we also need to rotate our back around the Y-axis again, otherwise it will look the other way around.

So how to make the flip effect look more harmonious? My idea here is to control the background color of the back to be consistent with the cover, and set setTimeout function to make the content of the back come out later, so that I can see the text on the back only after I flip the card to a certain Angle. As for how long the delay, this is slowly adjusted ha ha.

.back {
    position: absolute;
    width: 100%;
    height: 100%;
    left: 0;
    background: rgb(168.10.3);
    transform: rotateY(180deg); // Still need to rotatefont-size: 1rem;
    color: #f1c40f;
    border-radius: 10px;
    display: flex;
    justify-content: center;
    align-items: center;
}   
Copy the code

Flip animation I set 1s, the delay used 400ms.

setTimeout(() = > {
    this.back = true
}, 400);
Copy the code

The complete code

<template>
    <div class="the-card">
        <div class="wrap">
            <div class="card cover" v-for="item in cards" :key="item.id"
                            :class="{ 'cardHover': ! gameOver, 'blur': item.id ! = hoverId && beginHover, 'turned': item.isTurned, 'gameOver': ! item.isTurned && gameOver, }" 
                            @mouseenter="hoverItem(item)" 
                            @mouseout="reset()"
                            @click="turnItem(item)">
                <div :class="{'back':back}" v-if="back">
                    <span>{{item.content}}</span>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    data(){
        return {
            cards: [{id:0.content:'Start the day'.isTurned:false},
                {id:1.content:'Start the day'.isTurned:false},
                {id:2.content:'Start the day'.isTurned:false},
                {id:3.content:'Start the day'.isTurned:false},
                {id:4.content:'Start the day'.isTurned:false}].hoverId: -1.beginHover: false.gameOver: false.back: false}},methods: {
        hoverItem(item){
            if(!this.gameOver){
                this.hoverId = item.id
                this.beginHover = true}},reset(){
            this.beginHover = false
        },
        turnItem(item){
            if(this.gameOver) return
            this.cards.map(card= > {
                card.id === item.id ? card.isTurned = true : "";
            })

            setTimeout(() = > {
                this.beginHover = false
                this.gameOver = true
            }, 300);


            setTimeout(() = > {
                this.back = true
            }, 400); }},created(){
        let randomNum = Math.floor(Math.random() * 5)
        this.cards[randomNum].content = 'Congratulations on winning Bingdwen Dwen.'}}</script>

<style lang="less" scoped>
    .the-card {
        height: 100vh;
        background-color: #bdc3c7;
        display: flex;
        justify-content: center;
        align-items: center;
        overflow: hidden;

        .wrap {
            width: 100%;
            display: flex;
            justify-content: center;
            align-items: center;
            
            .card {
                width: 180px;
                height: 300px;
                margin: 0 1rem;
                transition: 1s;
                cursor: pointer;
                border-radius: 10px;
                position: relative; } // Fuka cover.cover {
                background: url(../assets/fu.jpg) center center no-repeat;
                background-size: 100% 100%; // contain an image that contains a different sizediv} // The card without hover becomes blurred.blur {
                filter: blur(25px);
                transform: scale(.6); } // Click to flip the card.turned {
                box-shadow: 0px 0px 20px 10px #f1c40f;
                transform: perspective(900px) rotateY(180deg) scale(1) translateY(-50%); } // hover card to zoom in and expire after the game ends.cardHover:not(.turned):hover {
                transform: scale(1.3);
                filter: none;
            }

            .back {
                position: absolute;
                width: 100%;
                height: 100%;
                left: 0;
                background: rgb(168.10.3);
                transform: rotateY(180deg);
                font-size: 1rem;
                color: #f1c40f;
                border-radius: 10px;
                display: flex;
                justify-content: center;
                align-items: center; } // The game ends, the cards that have not been opened automatically turn down and move.gameOver {
                transform: perspective(900px) rotateY(180deg) scale(1) translateY(50%);
                cursor: default; }}}</style>
Copy the code

conclusion

The above is a page of flipping Fuka, but I found some logic is quite convoluted when I wrote the article. Maybe I set some unnecessary constraints myself.

If you see this has a better idea, welcome to exchange!

Oh, and I even wrote the code myself! There’s a 20% chance you won’t get ice!