Fan
Fan

Reputation: 1180

How to get the element width and height immediately when it resizing in Vue.js

How to get the element width and height immediately when it resizing in Vue.js? Here is my code pen illustration please help me to change it till work,thanks!

Codepen

let app = new Vue({
  el: '#app',
  data: {
    boxs: [{
        width: 100,
        height: 100
      },
      {
        width: 100,
        height: 100
      }
    ]
  }

});
#app {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
}

.resize {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 5px;
  width: 100px;
  height: 100px;
  overflow: hidden;
  resize: both;
  background-color: #C3E2CE;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.js"></script>
<div id="app">
  <div v-for="box,key in boxs" class="resize">
    {{ box.width }} x {{ box.height }}
  </div>
</div>

Upvotes: 3

Views: 19663

Answers (3)

nonNumericalFloat
nonNumericalFloat

Reputation: 1787

Easy way would be plain JS eventListener to change a local variable

window.addEventListener('resize', this.getWindowWidth);

data() {
  return {
    windowWidth:0
  }
},
mounted () {
  this.$nextTick(function() {
    window.addEventListener('resize', this.getWindowWidth);
    this.getWindowWidth()
  })
},
methods: {
getWindowWidth() {
  this.windowWidth = document.documentElement.clientWidth
}
}

and don't forget to remove the eventListener on component destroy

beforeDestroy() {
  window.removeEventListener('resize', this.getWindowWidth);
}

Upvotes: 4

zero298
zero298

Reputation: 26877

To get immediate feedback that responds to the actual resize action, you might want to try using a MutationObserver. You can attach it to a ref point of your component and listen for mutations there.

You can attach the MutationObserver in the mounted function. Be sure to also do any cleanup that you need in the destroyed function.

const Resizable = {
  template: "<div ref='main' @resize='onResize' class='resize'>{{dims.width}} | {{dims.height}}</div>",
  data() {
    return {
      dims: {
        width: null,
        height: null
      }
    };
  },
  mounted() {
    const {
      width,
      height
    } = this.$refs.main.getBoundingClientRect();

    this.dims.width = width;
    this.dims.height = height;

    const mutationHandler = mutationList => {
      for (let mutation of mutationList) {
        if (mutation.type === "attributes") {
          const {
            width,
            height
          } = mutation.target.getBoundingClientRect();

          this.dims.width = width;
          this.dims.height = height;
        }
      }
    };
    const mo = new MutationObserver(mutationHandler);

    mo.observe(this.$refs.main, {
      attributes: true,
      childList: true,
      subtree: true
    });

  },
  methods: {
    onResize() {
      console.log("Resized");
    }
  }
};

const app = new Vue({
  el: "#app",
  components: {
    "resizable": Resizable
  },
  data() {
    return {
      items: [
        "foo",
        "bar",
        "fizz"
      ]
    }
  }
});
body {
  background-color: #414141;
}

.container {
  display: flex;
  align-items: center;
  justify-content: center;
}

.resize {
  resize: both;
  margin: 5px;
  width: 100px;
  height: 100px;
  color: black;
  overflow: scroll;
  background-color: white;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.js"></script>

<div id="app">
  <div class="container">
    <resizable v-for="item in items" :key="item" class="resize"></resizable>
  </div>
</div>

Upvotes: 8

sampoh
sampoh

Reputation: 3065

Forgive me, but I'm still learning Vue as well. I'd suggest you do more modular approach and extract the boxes, then just loop how many you want. Please note that this is not best-practice, as the box w/h should probably be coming from props and data being loaded from the root element.

const box = Vue.component("box", {
  template: '<div class="resize">{{ boxWidth }} x {{ boxHeight}}</div>',
  data() {
    return {
      boxWidth: 100,
      boxHeight: 100,
    };
  },
  mounted: function() { 
    this.$el.addEventListener("mouseup", this.move);
  },
  methods: {
    move(e) {
      if (e.target == this.$el) {
        this.boxWidth = parseInt(this.$el.style.width);
        this.boxHeight = parseInt(this.$el.style.height);
      }
    }
  }
});

let app = new Vue({
  el: "#app",
  components: { box: box },
});
#app {
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
}

.resize {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 5px;
  width: 100px;
  height: 100px;
  overflow: hidden;
  resize: both;
  background-color: #C3E2CE;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.js"></script>
<div id="app">
    <div v-for="b in [0,1]">
      <box></box>
    </div>
</div>

Upvotes: 0

Related Questions