How can I use window size in Vue? (How do I detect the soft keyboard?)

vue.js

vue.js Problem Overview


In my mobile web app with Vue, I want to hide my footer when the soft keyboard pops. So I have a little function to test the ratio of window height to window width...

showFooter(){
    return h / w > 1.2 || h > 560;
}

...and I declare window.innerHeight/window.innerWidth in my data.

    data: { h: window.innerHeight, w: window.innerWidth }

Trouble is, when window.innerHeight changes, my h property doesn't get the new value. How can I watch window.innerHeight ?

vue.js Solutions


Solution 1 - vue.js

I am sure there are better ways to do this, but this one will work for you until I come up with something:

Basically you will need just one data prop and one watcher to do this.

new Vue({
    el: '#app',
    data() {
        return {
            windowHeight: window.innerHeight,
            txt: ''
        }
    },

    watch: {
        windowHeight(newHeight, oldHeight) {
            this.txt = `it changed to ${newHeight} from ${oldHeight}`;
        }
    },

    mounted() {
        this.$nextTick(() => {
            window.addEventListener('resize', this.onResize);
        })
    },

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

    methods: {  
        onResize() {
            this.windowHeight = window.innerHeight
        }
    }
});

And this would output the changes

<div id="app">
    <br> Window height: {{ windowHeight }} <br/>
    {{ txt }}
</div>

Solution 2 - vue.js

VUE 3

In Vue 3, you can create a function that can return a reactive width and breakpoint name values. You can easily reuse the function across multiple components.

import { computed, onMounted, onUnmounted, ref } from "vue"

export default function () {
  let windowWidth = ref(window.innerWidth)

  const onWidthChange = () => windowWidth.value = window.innerWidth
  onMounted(() => window.addEventListener('resize', onWidthChange))
  onUnmounted(() => window.removeEventListener('resize', onWidthChange))
  
  const type = computed(() => {
    if (windowWidth.value < 550) return 'xs'
    if (windowWidth.value >= 550 && windowWidth.value < 1200) return 'md'
    if (windowWidth.value >= 1200) return 'lg'
    return null; // This is an unreachable line, simply to keep eslint happy.
  })

  const width = computed(() => windowWidth.value)

  return { width, type }
}

You can use this in the setup method of your vue 3 component as follows.

const { width, type } = useBreakpoints()

Quick tip: Even though document event listeners are the most optimized things in the planet, this is best used only once in an app for performance reasons. Make a tiny plugin and add the value to the Vue instance, just like Vuetify does. Or to be simpler, commit them to vuex and read from there.

Solution 3 - vue.js

The above answer didn't work for me. Instead, I used:

mounted() {
  window.addEventListener('resize', () => {
    this.windowHeight = window.innerHeight
  })
}

Solution 4 - vue.js

For those already using Vuetify, you can just watch this.$vuetify.breakpoint.width or this.$vuetify.breakpoint.height for changes in the viewport's dimensions.

Vuetify breakpoint docs

Solution 5 - vue.js

This is probably really too late but if you want a much more simpler approach you can do npm installation https://www.npmjs.com/package/vue-window-size and import windowWidth from 'vue-window-size';

Or this with composition api

    setup() {
        const windowSize = ref(window.innerWidth)
        onMounted(() => {
            window.addEventListener('resize', () => {windowSize.value = window.innerWidth} )
        })
        onUnmounted(() => {
            window.removeEventListener('resize', () => {windowSize.value = window.innerWidth})
        })
        return { 
            windowSize
        }
    }

Solution 6 - vue.js

My answer might be late but none of the above worked for me so here is what I found on this topic ! :)

https://codepen.io/sethdavis512/pen/EvNKWw

HTML :

<div id="app">
    <section class="section has-text-centered">
        <h1 class="title is-1">
            Your Window
        </h1>
        <h3 class="title is-3">
            Width: {{ window.width }} px<br/>
            Height: {{ window.height }} px
        </h3>
        <p class="has-text-white">
            &uarr;<br/>
            &larr; resize window &rarr;<br/>
            &darr;
        </p>
    </section>
</div>

CSS:

$top-color: yellow;
$bottom-color: tomato;

html, body, #app, section.section {
  height: 100%;
}

body {
    background: -webkit-linear-gradient($top-color, $bottom-color);
    background: -o-linear-gradient($top-color, $bottom-color);
    background: -moz-linear-gradient($top-color, $bottom-color);
    background: linear-gradient($top-color, $bottom-color);
}

section.section {
  display: flex;
  flex-flow: column;
  justify-content: center;
  align-items: center;
}

.title {
    color: white;
}

JS:

new Vue({
    el: '#app',
    data: {
        window: {
            width: 0,
            height: 0
        }
    },
    created() {
        window.addEventListener('resize', this.handleResize);
        this.handleResize();
    },
    destroyed() {
        window.removeEventListener('resize', this.handleResize);
    },
    methods: {
        handleResize() {
            this.window.width = window.innerWidth;
            this.window.height = window.innerHeight;
        }
    }
});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbbsimonbbView Question on Stackoverflow
Solution 1 - vue.jssamayoView Answer on Stackoverflow
Solution 2 - vue.jskshksdrtView Answer on Stackoverflow
Solution 3 - vue.jscub33View Answer on Stackoverflow
Solution 4 - vue.jsCato MinorView Answer on Stackoverflow
Solution 5 - vue.jsShulzView Answer on Stackoverflow
Solution 6 - vue.jsKaloyan NikolovView Answer on Stackoverflow