3

Currently I am storing the window.innerWidth value to a vuex getter called screenWidth and using it in all of my components. But the problem is every time I want to use it I have to 1) import { mapGetters } from 'vuex' 2) call ...mapGetters() inside the computed property. To get rid of this problem I thought prototype injection might be a good idea. So I did this:

Vue.prototype.$screenWidth = window.innerWidth;
window.addEventListener('resize', () => {
    Vue.prototype.$screenWidth = window.innerWidth;
});

But that doesn't work. How can I more easily access the screen width in my component without going through all the import/map stuff?

Tanmay
  • 3,009
  • 9
  • 53
  • 83

1 Answers1

6

The way you're already doing it with Vuex sounds fine to me.

If you're using this in a lot of components then perhaps an alternative might be to use an observable object on the prototype, as in the example below. By using an object we can retain the reactivity.

Vue.prototype.$screen = Vue.observable({
    width: window.innerWidth,
    height: window.innerHeight
});

window.addEventListener('resize', () => {
    Vue.prototype.$screen.width = window.innerWidth;
    Vue.prototype.$screen.height = window.innerHeight;
});

new Vue({
    el: '#app'
});
<script src="https://unpkg.com/vue@2.6.10/dist/vue.js"></script>
<div id="app">
  <p>Width: {{ $screen.width }}</p>
  <p>Height: {{ $screen.height }}</p>
</div>

This relies on Vue.observable, which needs Vue 2.6.0. In earlier versions of Vue you could do something similar by creating a temporary Vue instance and assigning the object to the data of that instance:

Vue.prototype.$screen = new Vue({
    data: {
        screen: {
            width: window.innerWidth,
            height: window.innerHeight
        }
    }
}).screen;

window.addEventListener('resize', () => {
    Vue.prototype.$screen.width = window.innerWidth;
    Vue.prototype.$screen.height = window.innerHeight;
});

new Vue({
    el: '#app'
});
<script src="https://unpkg.com/vue@2.5.22/dist/vue.js"></script>
<div id="app">
  <p>Width: {{ $screen.width }}</p>
  <p>Height: {{ $screen.height }}</p>
</div>

It looks horrific but that's why Vue.observable was introduced.

Note that SO wraps these snippets in an iframe so you may not see the numbers update when you resize the browser window. For me I either had to make the window quite narrow or click the Expand snippet link to see it working.

skirtle
  • 27,868
  • 4
  • 42
  • 57
  • Thanks. The second method didn't work though. Could you confirm that the second method is reactive from your end? Just to be sure I haven't done anything wrong. – Tanmay Jun 14 '19 at 10:56
  • By `second method` I mean < Vue 2.6.0 approach – Tanmay Jun 14 '19 at 10:57
  • 1
    @Tanmay I've updated my answer to include a working demo of the second approach using Vue 2.5.22. – skirtle Jun 14 '19 at 11:19