Computed property with matchMedia function Vue.js

5k Views Asked by At

I have some problem with the matchMedia function that I wrote inside my computed property in Vue. The problem is when I load/refresh page, the function does not work. It only back to work after I resize the screen in Responsive Design Mode at the browser.

Here the code of my app.js

     computed: {
        widthChange() {
            if (matchMedia) {
                    var mqT = window.matchMedia(" (max-width: 850px) and (min-width: 600px) ")

                    function changeWidthT(mqT) {
                    const sectionRight = document.querySelector(".section-right")
                    if (mqT.matches) {
                        sectionRight.classList.remove("col-7")
                    }
                    else {
                        sectionRight.classList.add("col-7")
                    }
                }

                mqT.addListener(changeWidthT)
            }
        }
    },

and I call the computed property inside the parent of the page

<div class="frontpage-parent" :class="widthChange">...
</div>
4

There are 4 best solutions below

12
On BEST ANSWER

Have you tried calling widthChange() in the mounted hook so that it runs on load?

Edit Try placing const tst = this.widthChange; in the mousnted hook

0
On

A year later, but with a small tweak I made it work in Vuejs for a mobile/desktop purposes:

computed: {
...
...
      widthChange() {
        if (matchMedia) {
          const matchMediaQuery = window.matchMedia(" (max-width: 1024px) ")
          const changeWidthT = (matchMediaQuery) => {
            this.isMobileExperience = matchMediaQuery.matches ? true : false;
          }
          mqT.addListener(changeWidthT)
        }
      }
    },
    mounted() { 
      const awakeResizeListener = this.widthChange;
    },
...
...

With a v-if and v-else evaluating a isMobileExperience data option you are good to go with the resizing.

Hope this can help anyone

0
On

matchMedia in Vue with reactiveness

The aforementioned answers did not work for me. Improved BroiSatse's answer by replacing the deprecated addListener with change event as mentioned on https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList

Vue Options API with Typescript example:

data(): { mediaQuery: MediaQueryList; isTablet: boolean; } {
    const mediaQuery = window.matchMedia('(max-width: 1024px)');

    return {
        mediaQuery,
        isTablet: mediaQuery.matches
    };
},
mounted(): void {
    this.mediaQuery.addEventListener('change', () => {
        this.isTablet = this.mediaQuery.matches;
    });
}
1
On

You are misusing computed properties here. They are supposed to be getters, meaning they are only to return ready to sue values. You're actually attaching event listeners there.

Instead, you need to use data attribute and initialize your listeners within mounted hook:

export default {
  name: 'Blah',
  data () {
    const tabletViewQuery = matchMedia('...')
    return {
      tabletViewQuery: tabletViewQuery.
      tabletView: tableViewQuery.matches,
    }  
  },
  mounted () {
     this.tabletViewQuery.addListener(() => {
       this.tabletView = tableViewQuery.matches
     }
  }
}

and use it in a table:

<div class="section-right" :class="{ 'col-7': tabletView }">

However, probably much cleaner solution would be to use vue-match-media plugin.