KingKongFrog
KingKongFrog

Reputation: 14419

How to trigger an event when element is resized in Vue.js?

Currently I trigger an event to take the same height of the current element when the component is mounted, however this doesn't always work since it is sent once and if the element is resized it won't get sent again. Also I need to put a timeout since sometimes the chart in the componenet change sthe height after the ajax call.

How do I send this event ANYTIME the height of the current element is changed?

This is what I am currently doing:

    mounted: function() {
        setTimeout(function() {
            this.$emit('resize', this.$el.offsetHeight);
        },1000);
    }

Upvotes: 22

Views: 25937

Answers (4)

dotNET
dotNET

Reputation: 35400

In Vuetify 3, there is v-resize directive (See docs) that can be used to monitor window resize events. This directive can be applied on any element, like this:

<v-row v-resize="onResize">
</v-row>

and in the handler, you can read new width and height of the window (or any other element for that matter), like this:

onResize () {
  // window.innerWidth
  // window.innerHeight 
}

Upvotes: 0

NiKO
NiKO

Reputation: 2873

There is more Vue style solution based on ResizeObserver, but not supported in all browsers - yet

DOC: https://caniuse.com/#feat=resizeobserver

Examplum

data () {
  return {
    ro: null,
  }
},

methods: {
  onResize () {
    this.$emit('resize', this.$refs.myElement.offsetHeight)
  },
},

mounted () {
  this.ro = new ResizeObserver(this.onResize)
  this.ro.observe(this.$refs.myElement)
},

beforeDestroy () {
  this.ro.unobserve(this.$refs.myElement)
}

Upvotes: 28

Robin Macharg
Robin Macharg

Reputation: 1848

I've had some issues getting ResizeObserver to work in a Vue2 TypeScript project. Two approaches worked with (AFAICT) identical results:

  • Using the resize-observer-polyfill (which essentially wraps MutationObserver). This required an import ResizeObserver from 'resize-observer-polyfill' in my component.

  • Installing the @types/resize-observer-browser npm package, based on this answer, and adding an entry to my tsconfig.json:

    {
      "compilerOptions": {
        ...
        "types": [
          ...
          "resize-observer-browser"
        ]
      }
    }
    

    This second approach didn't require any additional import and is the solution I'm favouring.

Both approaches offer the same ResizeObserver API, e.g.

this.resizeObserver = new ResizeObserver((entries, observer) => {
    log("Resize called", entries, observer)
})
this.resizeObserver.observe(this.$refs.canvas as Element)

(note: only tested in Chrome 88, Feb 2021)

Upvotes: 1

sam-m
sam-m

Reputation: 166

Until ResizeObserver becomes standard, you can use MutationObserver to keep track of the element's size. Codepen link

new Vue({
  el: "#app",
  data() {
    return {
      width: null,
      height: null,
      observer: null
    };
  },

  mounted() {
    //get initial dimensions. Mutation observer will observe mutations only
    const box = this.$refs.box,
      boxSize = box.getBoundingClientRect();

    this.width = Math.trunc(boxSize.width) + "px";
    this.height = Math.trunc(boxSize.height) + "px";
    // initialize the observer on mount
    this.initObserver();
  },

  //disconnect the observer before destroy
  beforeDestroy() {
    if (this.observer) this.observer.disconnect();
  },

  methods: {
    initObserver() {
      const box = this.$refs.box,
        vm = this,
        config = {
          attributes: true
        };
      // create the observer
      const observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
          // check if the mutation is attributes and update the width and height data if it is.
          if (mutation.type === "attributes") {
            let {
              width,
              height
            } = box.style;

            vm.width = width;
            vm.height = height;
          }
        });
      });

      // observe element's specified mutations
      observer.observe(box, config);
      // add the observer to data so we can disconnect it later
      this.observer = observer;
    }
  }
});
.box {
  text-align: center;
  font-family: Arial;
  box-sizing: border-box;
  width: 150px;
  height: 150px;
  border: 2px solid red;
  padding: 10px;
  margin: 0 auto;
  resize: both;
  overflow: auto;
}

.size {
  color: #2a9966;
  font-weight: 600;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <!-- more info on refs: https://vuejs.org/v2/api/#ref -->
  <div class=" box" ref="box">
    <h4>Resize Me</h4>
    <p>
      <span>width: </span><span class="size">{{ width }}</span>
    </p>
    <p>
      <span>height: </span><span class="size">{{ height }}</span>
    </p>
  </div>
</div>

Upvotes: 6

Related Questions