5

So I want to have an action only if the user has the mouse on the div for at least 1 second. Inside template:

<div @mouseover="trigger"></div>

Inside script:

data() {
    return {
        hovered: false
    }
}

methods: {
    trigger() {
        setTimeout(function(){ this.hovered = true }, 1000)
    }
}

My problem is that I don't understand the scope of Vue. Because this.hovered is inside another function, it does not find the actual hovered data variable. What's the solution to this?

Hillcow
  • 890
  • 3
  • 19
  • 48
  • `this` is refered to the setTimeout function. `var self = this;` before setTimeout will give access to vue inside the nested function via the `self` variable – Harrie Kiezebrink Aug 02 '17 at 13:42
  • 3
    Note that this won't fix your overall problem. The setTimout will alway execute when the user hovers over the div. You need to measure the time spent on the button and cancel when a onmouseout event occurs. – Harrie Kiezebrink Aug 02 '17 at 13:51
  • 1
    Possible duplicate of [How to access the correct \`this\` inside a callback?](https://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-inside-a-callback) – Bert Aug 02 '17 at 14:29
  • Yes, thank you @Bert! – Hillcow Aug 02 '17 at 21:58

5 Answers5

4

Have you tried using an arrow function in your setTimeout? It will maintain this.

data() {
    return {
        hovered: false
    }
}

methods: {
    trigger() {
        setTimeout(() => { this.hovered = true }, 1000)
    }
}
Michael Giovanni Pumo
  • 14,338
  • 18
  • 91
  • 140
2
<div @mouseover="activarOver" @mouseleave="resetOver "> eventos </div>



data: () => {
    return {
      countMouseOver: 0
    }
  },
methods: {
    activarOver () {
      this.countMouseOver++
      if (this.countMouseOver < 2) {
        this.setMostrarPopup()
      }
      console.log(this.countMouseOver)
    },
    resetOver () {
      this.countMouseOver = 0
      console.log('reset')
    },
}
2

Implementation to show when hovered over for 1 second, then disappear when no longer hovered.

<span @mouseover="hover" @mouseleave="unhover">Hover over me!</span>
<div v-if="show">...</div>

data() {
   return {
      show: false;
      hovering: false,
   };
},
methods: {
    hover() {
       this.hovering = true;
       setTimeout(() => this.show = this.hovering, 1000);
    },
    unhover() {
       this.hovering = false;
       this.show = false;
    },
}
djeastm
  • 158
  • 2
  • 8
1

I have been solving this problem for selecting items in a list only if the user hovers for some time (to prevent menu flickering)

Template (pug):

.div(
    @mouseover="select(identifier)"
    @mouseout="clear()"
) {{content}}

Data:

hovered: false
selectedId: ""

and the methods

select(identifier) {
    this.selectedId = identifier
    setTimeout(() => {
        if(this.selectedId === identifier )
            this.hovered = true
        },
        1000
    )
},
clear() {
    this.selectedId = ''
}

the approach is to check if whatever user is hovering on is the same as they were hovering on a second ago.

Rince
  • 2,195
  • 3
  • 21
  • 35
0

If you want to use old syntax, bind 'this' to the setTimeout function

data() {
    return {
        hovered: false
    }
}

methods: {
    trigger() {
        setTimeout(function(){ this.hovered = true }.bind(this), 1000)
    }
}
BritishSam
  • 1,070
  • 8
  • 24