Juliane Blier
Juliane Blier

Reputation: 627

Get element height with Vuejs

I want to get the height of a div in order to make the height of another div matching it. I used the method clientHeight, but It doesn't return me the good value (smaller value). Actually, It seems to return a height before all elements are charged. After some research online, I tried to put a window.load() to delay until everything is charged but it doesn't work as well. Some ideas ?

mounted () {
  this.matchHeight()
},
matchHeight () {
  let height = document.getElementById('info-box').clientHeight
}
<div class="columns">
  <div class="left-column" id="context">
  <p>Some text</p>
  </div>
  <div class="right-column" id="info-box">
    <img />
    <ul>
      some list
    </ul>
  </div>
</div>

Upvotes: 55

Views: 186340

Answers (6)

Erin
Erin

Reputation: 5825

Update for Vue >= 2.7

Using the Composition API, you can get a reactive height with getElementSize from VueUse, as mentioned in the vuejs.org docs

import { ref } from 'vue'
import { useElementSize } from '@vueuse/core'

export default {
  setup() {
    const el = ref(null)
    const { height } = useElementSize(el)

    return {
      height,
    }
  }
}

or

<script setup>
import { ref } from 'vue'
import { useElementSize } from '@vueuse/core'

const el = ref(null)
const { height } = useElementSize(el)
</script>

Upvotes: 0

Prakash Rajotiya
Prakash Rajotiya

Reputation: 1033

In my Case it found clientHeight as per below path

this.$refs.infoBox.$el.nextElementSibling.clientHeight

Upvotes: 0

RonC
RonC

Reputation: 33771

The way you are doing it is fine. But there is another vue specific way via a ref attribute.

 mounted () {
   this.matchHeight()
 },
 matchHeight () {
   let height = this.$refs.infoBox.clientHeight;
 }

    <div class="columns">
        <div class="left-column" id="context">
            <p>Some text</p>
        </div>
        <div class="right-column" id="info-box" ref="infoBox"></>
            <img />
            <ul>
                some list
            </ul>
        </div>
    </div>

In this case, since you are just getting the value it really doesn't matter whether you use your original getElementById approach or the vue specific ref approach. However if you were setting the value on the element then it's much better to use the ref approach so that vue understands that the value has changed and won't possibly overwrite the value with the original value if it needs to update that node in the DOM.

You can learn more here: https://v2.vuejs.org/v2/api/#vm-refs

Update

A few people had left comments that the above solution didn't work for them. That solution provided the concepts but not full working code as example, so I have augmented my answer with the code below which demonstrates the concepts.

var app = new Vue({
    el: '#app',
    data: function () {
        return {
            leftColStyles: { },
            lines: ['one', 'two','three']
        }
    },
    methods: {
        matchHeight() {
            var heightString = this.$refs.infoBox.clientHeight + 'px';
            Vue.set(this.leftColStyles, 'height', heightString); 
        }
    },
    mounted() {
        this.matchHeight();
    }

});
.columns{width:300px}
.left-column {float:left; width:200px; border:solid 1px black}
.right-column {float:right; border:solid 1px blue; }
<div id="app">
    <div class="columns">
        <div class="left-column" id="context" v-bind:style="leftColStyles">
            <p>Some text</p>
        </div>
        <div class="right-column" id="info-box" ref="infoBox"> 
            <img />
            <ul>
                <li v-for="line in lines" v-text="line"></li>
            </ul>
        </div>
    </div>

</div>

 <script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
 

Here is a screenshot of the results in the browser:

enter image description here

Note:
My answer assumes that you are loading vue.js from a cdn or locally into the browser and executing it there. If instead you are running your code via the cli and my answer is not working for you, please see @mayank1513's answer instead.

Upvotes: 73

John Harrington
John Harrington

Reputation: 1

FYI - had the issue accessing $el as well (had undefined). With vue/typescript - the following worked ok:

console.log('scriptPanel: mounted: sizes: ', (this.$refs.scriptSheet! as any).$el.clientHeight)

Upvotes: 0

Mayank Kumar Chaudhari
Mayank Kumar Chaudhari

Reputation: 18538

Took a lot of time ⌚ resolving the issue. Initially I tried to follow answer by Ron C. Trying to get this.$refs.infoBox.clientHeight; just didn't work - it gave undefined.

Then I explored the this.$refs.infoBox object.

Wow!!! I don't know how the code he wrote works for him and all others, but there wasn't any property called clientHeight. Finally got it inside $el.

so we need to replace this.$refs.infoBox.clientHeight; with this.$refs.infoBox.$el.clientHeight;

This just worked well for me.

Update

While using nuxt this.$refs.infoBox.$el.clientHeight; didn't work. but Ron C's answer works for this case. this.$refs.infoBox.$el.clientHeight; seems to work while using @vue/cli

Upvotes: 23

drimbo
drimbo

Reputation: 59

I would use flexbox to achieve equal height columns https://css-tricks.com/snippets/css/a-guide-to-flexbox/

.container {
   display: flex;
}
.column {
   border: 1px solid;
   padding: 20px;
   width: 150px;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <div class="container">
        <div class="column">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ac dui sed erat venenatis fermentum. Nulla tempus, magna
            sit amet ornare fringilla, ligula quam faucibus urna
        </div>
        <div class="column">
            Lorem ipsum dolor sit amet, consectetur adipiscing elit.
        </div>
    </div>
</body>
</html>

Upvotes: 5

Related Questions