3

I'm trying to dynamically set the width of my innermost element equal to the width of the outermost element using Vue:

<div id="banner-container" class="row">
    <div class="col-xs-12">
        <div class="card mb-2">
            <div class="banner banner-tag card-body" :style="getBannerStyle"></div>
        </div>
    </div>
</div>

I have the following code in Javascript and computed property in Vue:

var container = document.getElementById('banner-container').offsetWidth;
...
computed: {
    getBannerStyle () {
        return 'width: ' + container + 'px;';
    }
}
Bargain23
  • 1,863
  • 3
  • 29
  • 50

2 Answers2

5

getBannerStyle is not going to be reactive because you do not access any other reactive properties within it. You need to assign a data property the offsetWidth value and reference that within getBannerStyle. Something like this should work:

mounted () {
  this.offsetWidth = document.getElementById('banner-container').offsetWidth
},
data () {
  return {
    offsetWidth: 0,
  }
},
computed: {
    getBannerStyle () {
        return `width: ${this.offsetWidth}px;`
    }
}
2

Unfortunately, it is next to impossible to do this in pure Vue because the element may not yet have a size during any of the lifecycle hooks. Especially, if the element is not immediately visible on page load. Fortunately, all modern browser have a class that can help: ResizeObserver.

  data: () => ({
    offsetWidth: 0,
    resizeObserver: null
  }),
  mounted() {
    this.resizeObserver = new ResizeObserver(this.onResize)
    this.resizeObserver.observe(document.getElementById('banner-container'))
    this.onResize()
  },
  beforeUnmount() {
    this.resizeObserver.unobserve(document.getElementById('banner-container'))
  },
  methods() {
    onResize() {
      this.offsetWidth = document.getElementById('banner-container').offsetWidth
    }
  }
Stefan Fabian
  • 498
  • 4
  • 21