Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for a v-on:resize event #1915

Closed
scottfriebel opened this issue Nov 24, 2015 · 23 comments
Closed

Add support for a v-on:resize event #1915

scottfriebel opened this issue Nov 24, 2015 · 23 comments

Comments

@scottfriebel
Copy link

It would be nice if there was a built in way to handle resizing.
Ex:

<div class="example" v-on:resize="handleResize($event)">
</div>
@yyx990803
Copy link
Member

resize is a window event. You cannot listen to it on normal elements.

Do it in lifecycle hooks of your components:

ready: function () {
  window.addEventListener('resize', this.handleResize)
},
beforeDestroy: function () {
  window.removeEventListener('resize', this.handleResize)
}

@riliwanrabo
Copy link

@yyx990803 Sir I have this:

_// template_
<div class="wrapper__Row" :style="{ height: fullHeight+'px' }" />

_// in my script_
data() {
 return {
   fullHeight: document.documentElement.clientHeight
  }
}

However if i resize the browser the height remains same

@itsMapleLeaf
Copy link
Contributor

@riliwanrabo

You need to use an event handler on the window to listen to the resize event, as he's shown above. The code there sets the value fullHeight once in your data, then does nothing else.

This is what you'll want to do instead:

  // initialize data
  data() {
   return {
     fullHeight: document.documentElement.clientHeight
    }
  },

  // bind event handlers to the `handleResize` method (defined below)
  ready: function () {
    window.addEventListener('resize', this.handleResize)
  },
  beforeDestroy: function () {
    window.removeEventListener('resize', this.handleResize)
  },

  methods: {
    // whenever the document is resized, re-set the 'fullHeight' variable
    handleResize (event) {
      this.fullHeight = document.documentElement.clientHeight
    }
  }

In your case, though... it seems like this style will work just as well, without needing to use the resize event at all.

<div class="wrapper__Row" style="height: 100vh"></div>

If you have any more questions, feel free to ask on the VueJS forums or on Gitter.

@JordanDelcros
Copy link

What about store the target boundingClientRect (or anything else) and use a common resize event on window that loop through all request resize and compare current size and stored size, then do callback if needed... ?

@eybarta
Copy link

eybarta commented Feb 12, 2017

I thought a $forceUpdate would recalculate all computed properties within my component...
So I was listening to window resize event and $forceUpdate in the callback, thinking my computed
property that uses the window width would recalculate accordingly and update the template,

Is this supposed to work, or am I thinking of this the wrong way?

thx

@pablohpsilva
Copy link

pablohpsilva commented Feb 15, 2017

@eybarta I think you're doing it wrong. $forceUpdate can cost a lot. Why not use the event and a variable?

export default {
  data() {
    return { windowWidth: window.innerWidth };
  },
  methods: {
    handleWindowResize(event) { this.windowWidth = event.currentTarget.innerWidth; },
  },
  beforeDestroy: function () {
    window.removeEventListener('resize', this. handleWindowResize)
  },
  mounted() {
    window.addEventListener('resize', this.handleWindowResize);
  },
}

@Akryum
Copy link
Member

Akryum commented Feb 15, 2017

Did you try vue-resize?

@wbswjc
Copy link

wbswjc commented Nov 15, 2017

Use mounted instead of ready in Vue 2, see https://vuejs.org/v2/guide/migration.html#ready-replaced

@blackandred
Copy link

blackandred commented Nov 18, 2017

@pablohpsilva Thanks for that, simple and works really cool.

@AdsonCicilioti
Copy link

Hey @pablohpsilva .. How ro listen width from a child component and pass to parent component element?

@kidBrazil
Copy link

Has anyone found a good way to debounce these types of events? Would really rather not have 15 events firing when a user resizes the screen. A little bit of debounce would go a long way

@pablohpsilva
Copy link

@AdsonCicilioti
hello!

What you could do is make your child component listen to its on resize event (you should take care of those events, remembering to remove them once your component is destroyed) and when the event is triggered, it $emits an event so the parent component can hear it and so something about it.

@eybarta
Copy link

eybarta commented Jul 18, 2018

@kidBrazil I'm using lodash.. but you can just find a stand-alone debounce, I use it like this
to recompute computed props on resize:

    data() {
        return {
            resizeTrig:-1
        }
    },
    mounted() {
        $(window).on('resize.mycomp', this.triggerResize)
        // or addEventListener...
    },
    destroy() {
        $(window).off('resize.mycomp');
    },
    methods: {
        triggerResize: _.debounce(function() {
            this.resizeTrig = new Date().getTime()
        }, 500)
    },
    computed: {
        dependentOnResize() {
            let trig = this.resizeTrig;
            return DoMyThing;
        }
    }

@pablohpsilva
Copy link

@kidBrazil what @eybarta said is exactly what I would do. But you have to consider if you really want to debounce the event. Depending on what you're build, the debounce events can give you trouble to compute something needed.

@kidBrazil
Copy link

@pablohpsilva Thanks! I will look into getting loadash added to the app.

Cheers

@makaleks
Copy link

makaleks commented Jul 25, 2018

I`m trying to resize canvas using iframe, because canvas sizes are independent from DOM changes and can be changed only using script. Other elements can scale for more reasons: when window resizes, when neighbours change their sizes (independently from Vue and other frameworks). In current project I want to use canvas to draw an editable grid. The concept example is on JSFiddle.
So, applying to Vue, I wished to track the onresize event of the iframe, which can be called even at window or Vue-independent resize. I didn`t find the reference to window.onresize in Vue source, so I suggest that Vue.$nextTick is not called when window or other element are resized. If Vue had the support of onresize, I would be able to change the canvas sizes using reactive attibutes of Vue component. But what to do now?

Thanks

@scottfriebel
Copy link
Author

@kidBrazil If all you are looking for is a debounce function, adding all of lodash is kind of overkill. Here is the standalone debounce function I use - debounce

@dobeerman7
Copy link

That's cool, guys.
But how to trigger the resize event manualy?

Now I've following code:

  this.$window = $(window)
  // something do
  this.$window.trigger('resize')

It works fine with jQuery.
How to change it to pure js without jQuery? I even tried to make

this.$window.dispatchEvent(new Event('resize'));

But Event is not defined.

@pablohpsilva
Copy link

I might be wrong, but this is not the place @dobeerman7 .
Try asking on stackoverflow :)

@aidangarza
Copy link

aidangarza commented Aug 31, 2018

I know this is a closed issue, but for any future visitors, the MutationObserver api is probably the best way to handle this (https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver). I set it up as a mixin for any components that need to be resized based on the size of their children.

{
  data () {
    return {
      height: 0,
      heightMonitor: null
    }
  },

  mounted () {
    this.$nextTick(() => {
      // Create the height monitor
      this.monitorHeight()
    })
  },

  beforeDestroy () {
    // Disconnect the height monitor
    this.heightMonitor.disconnect()
  },

  methods: {
    monitorHeight () {
      // Create a new mutation observer
      this.heightMonitor = new MutationObserver(this.checkHeight)
      // Start observing $el for an attribute, childlist, or subtree changes
      this.heightMonitor.observe(this.$el, {
        attributes: true,
        childList: true,
        subtree: true
      })
    },
    checkHeight () {
      if (this.$el.clientHeight !== this.height) {
        this.height = this.$el.clientHeight
      }
    }
  }
}

@Justineo
Copy link
Member

Justineo commented Aug 31, 2018

@aidangarza MutationObserver doesn't respond when the element is resized but is not modified itself. Chrome already shipped ResizeObserver which is the best solution for this issue. For older browsers you can use a polyfill or try other solutions like resize-detector.


F.Y.I. For the integration with Vue.js, you can try the VueResize component or you can implement it as a directive. We have implemented a v-resize directive based on resize-detector.

@YanaMiroshkina
Copy link

Has anyone found a good way to debounce these types of events? Would really rather not have 15 events firing when a user resizes the screen. A little bit of debounce would go a long way

In App.vue:

function debounce(func, wait, immediate) {
  let timeout;
  return function() {
    let context = this, args = arguments,
    later = function() {
      timeout = null
      if (!immediate) func.apply(context, args)
    },
    call_now = immediate && !timeout
    clearTimeout(timeout)
    timeout = setTimeout(later, wait)
    if (call_now) func.apply(context, args)
  }
}

export default {
  name: 'app',
  data () {
    return {
      
    }
  },
  methods: {
    on_resize: function() {
      this.$store.commit('change_is_mobile', window.innerWidth < 1000)
    }
  },
  created() {
    this.on_resize()
  },
  mounted: function () {
    window.addEventListener('resize', debounce(this.on_resize, 250))
  },
  beforeDestroy: function () {
    window.removeEventListener('resize', this.on_resize)
  }
}

In Store.js:

state: {
    is_mobile: false
},
mutations: {
    change_is_mobile (state, payload) {
      state.is_mobile = payload
    }
  }

In Component.vue (parameter 'is_mobile' is reactive):

computed: {
    is_mobile() {
      return this.$store.state.is_mobile
    }
  }

@vuejs vuejs locked as resolved and limited conversation to collaborators Apr 29, 2019
@posva
Copy link
Member

posva commented Apr 29, 2019

Locking as this thread is really old and many solutions have been provided to match all tastes 🙂

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests