How to make a hover effect on a particular card and stops hovering on remaining cards?

Viewed 481

if i hover on a card one it displays the icons of every card but i want to display icons on a particular hovering card (ouput of my card-image).These cards are automatically generated by using v-for and fetch the data from axios package,DisplayNotes.vue file responsibility is to show the notes to the user in the cards ,please help me to fix this issue.`

[DisplayNotes.vue]

<template>
<div class="main-section">
    <div v-for="note in notes" :key="note.data" class="container">
        <div class="card-content">
            <h5>{{note.title}}</h5>
            <p><i>{{note.body}}</i></p>
        </div>
        <div @mouseover="hover=true" @mouseleave="hover=false" class="import-icons">
            <icons v-if="hover" />
            <button type="button" @click="handlesubmit()">close</button>
        </div>
    </div>
</div>
</template>
<script>
import service from '../service/User'
import icons from './icons'
export default {
    components: {
        icons
    },
    data() {
        return {
            hover: false,
            notes: [{
                id: 1,
                title: 'Fundoo',
                body: 'unlimited Notes...'
            }, ],
        }
    },
    methods: {
        async handlesubmit() {
           const response = await axios.get('/displayNotes', {});
            localStorage.getItem('token', response.data.token);
           this.notes.push(response.data);
        },
    }
}
</script>
<style lang="scss">

.card-content {
    input {
        border: none;
    }
    textarea {
        border: none;
        outline: none;
    }
}
/* dividing the width percentage */
.container {
    height: 200px;
    width: 25%;
    float:left;
    margin: -2.98%; 
    margin-left:20%;
    margin-top: 5%;
    border-style: ridge;
}
.import-icons {
    display: block;
    margin-left: -2%;
    padding-top: 25%;

    button {
        border: none;
        background: none;
        float: right;
        font-weight: 600;
        font-family: Arial, Helvetica, sans-serif;
        margin-top: -2%;
        padding-left: 400px;
    }
}

</style>

[icons.vue]

<template>
<div class="used-icons">
    <i id="first-icon" class="fas fa-bell"></i>
    <i id="second-icon" class="fas fa-user"></i>
    <i id="third-icon" class="fas fa-palette"></i>
    <i id="forth-icon" class="fas fa-archive"></i>
    <!-- <i id="fifth-icon" class="fas fa-ellipsis-v"></i> -->
</div>
</template>

<style scoped>
#first-icon {
    opacity: 0.9;
}

#second-icon {
    padding-left: 30px;
    padding-right: 30px;
    opacity: 0.9;
}

#third-icon {
    opacity: 0.9;
}

#forth-icon {
    padding-left: 30px;
    padding-right: 30px;
    opacity: 0.9;
}

#fifth-icon {
    padding-right: 195px;
    opacity: 0.9;
}
</style>

3 Answers

All the items are conditionally rendered on the same hover property, so whenever that property is true (when an item is hovered), all items are shown instead of only the hovered one.

One way to fix this is to add hover to each notes[] array element, and use that to conditionally render them:

<div v-for="note in notes">
  <div @mouseover="note.hover=true" @mouseleave="note.hover=false">
    <icons v-if="note.hover" />
  </div>
</div>
export default {
  data() {
    return {
      // hover: false, // remove this
      notes: [
        {
          id: 1,
          title: 'Fundoo',
          body: 'unlimited Notes...',
          hover: false, // add this
        },
        {
          id: 2,
          title: 'Fundoo',
          body: 'unlimited Notes...'
          hover: false, // add this
        },
      ],
    }
  },
}

To add hover property to new notes[] array elements in handlesubmit():

export default {
  methods: {
    async handlesubmit() {
      //...
      this.notes.push({
        ...response.data,
        hover: false,
      })
    }
  }
}

According to your implementation I consider you add 'hover' property to each card and then manipulate it in event handlers.

<template>
  <div class="main-section">
    <div v-for="(note, index) in notes" :key="note.data" class="container">
        <div class="card-content">
            <h5>{{note.title}}</h5>
            <p><i>{{note.body}}</i></p>
        </div>
        <div @mouseover="note[index].hover=true" @mouseleave="note[index].hover = false" class="import-icons">
            <icons v-if="hover" />
            <button type="button" @click="handlesubmit()">close</button>
        </div>
    </div>
  </div>
</template>
<script>

export default {
    data() {
        return {
            hover: false,
            notes: [{
                id: 1,
                title: 'Fundoo',
                body: 'unlimited Notes...',
                hover: false
            }, ],
        }
    },
    methods: {
        async handlesubmit() {
           const response = await axios.get('/displayNotes', {});
            localStorage.getItem('token', response.data.token);
           this.notes.push(response.data);
        },
    }
}
</script>

You can do this with only CSS, no JavaScript required.

Add a note class to the note container and note-icons to the icons element.

Then with some simple css we can conditionally show the note-icons on hover.

.note-icons {
  visibility: hidden;
}

.note:hover .note-icons
  visibility: visible;
}

Full Snippet

<template>
<div class="main-section">
    <div v-for="note in notes" :key="note.data" class="container note"> <!-- ⭐️ -->
        <div class="card-content">
            <h5>{{note.title}}</h5>
            <p><i>{{note.body}}</i></p>
        </div>
        <div class="import-icons">
            <icons class="note-icons"/> <!-- ⭐️ -->
            <button type="button" @click="handlesubmit()">close</button>
        </div>
    </div>
</div>
</template>
<script>
import service from '../service/User'
import icons from './icons'
export default {
    components: {
        icons
    },
    data() {
        return {
            hover: false,
            notes: [{
                id: 1,
                title: 'Fundoo',
                body: 'unlimited Notes...'
            }, ],
        }
    },
    methods: {
        async handlesubmit() {
           const response = await axios.get('/displayNotes', {});
            localStorage.getItem('token', response.data.token);
           this.notes.push(response.data);
        },
    }
}
</script>
<style lang="scss">

.card-content {
    input {
        border: none;
    }
    textarea {
        border: none;
        outline: none;
    }
}
/* dividing the width percentage */
.container {
    height: 200px;
    width: 25%;
    float:left;
    margin: -2.98%; 
    margin-left:20%;
    margin-top: 5%;
    border-style: ridge;
}
.import-icons {
    display: block;
    margin-left: -2%;
    padding-top: 25%;

    button {
        border: none;
        background: none;
        float: right;
        font-weight: 600;
        font-family: Arial, Helvetica, sans-serif;
        margin-top: -2%;
        padding-left: 400px;
    }
}

.note-icons { /* ⭐️ */
  visibility: hidden;
}

.note:hover .note-icons { /* ⭐️ */
  visibility: visible;
}
</style>
Related