<!--
  Forked from:
  https://quasar.dev/vue-components/input#Example--Design-Overview
-->
<div id="q-app">
  <q-card class="q-ma-sm bg-grey-10" style="max-width: 300px">
    <q-card-section>
      <div class="q-gutter-sm">
        <mask-phone-provider :value="landline" v-slot="{ mask }">
          <q-input v-model="landline" unmasked-value :mask="mask" outlined dark label="Tel. Fixo"></q-input>
        </mask-phone-provider>
        <mask-phone-provider :value="cellphone" v-slot="{ mask }">
          <q-input v-model="cellphone" unmasked-value :mask="mask" outlined dark label="Celular"></q-input>
        </mask-phone-provider>
      </div>
    </q-card-section>
  </q-card>
</div>
Vue.component('mask-phone-provider', {
  name: 'PhoneMaskProviderComponent',
  props: {
    value: String
  },
  watch: {
    mask () {
      let input = this.$children[0].$refs.input
      requestAnimationFrame(() => {
        input.selectionStart = input.value.length
      })
    }
  },
  computed: {
    mask () {
      switch (true) {
        case (this.value || '').length <= 8: return '####-#####'
        case (this.value || '').length === 9: return '#####-#####'
        case (this.value || '').length === 10: return '(##) ####-#####'
        default: return '(##) #####-####'
      }
    }
  },
  render (h) {
    return this.$scopedSlots.default({ mask: this.mask })[0]
  }
})

new Vue({
  el: '#q-app',
  data () {
    return {
      landline: '',
      cellphone: ''
    }
  }
})
View Compiled

External CSS

  1. https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900|Material+Icons
  2. https://cdn.jsdelivr.net/npm/quasar@1.9.3/dist/quasar.min.css

External JavaScript

  1. https://cdn.jsdelivr.net/npm/vue/dist/vue.js
  2. https://cdn.jsdelivr.net/npm/quasar@1.9.3/dist/quasar.umd.min.js