<!--
  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>
      <q-input v-model="phone" ref="phone" unmasked-value :mask="mask" outlined dark label="Telefone"></q-input>
    </q-card-section>
  </q-card>
</div>
new Vue({
  el: '#q-app',
  data () {
    return {
      phone: ''
    }
  },
  watch: {
    mask () {
      let input = this.$refs.phone.$refs.input
      requestAnimationFrame(() => {
        input.selectionStart = input.value.length
      })
    }
  },
  computed: {
    mask () {
      switch (true) {
        case this.phone.length <= 8: return '####-#####'
        case this.phone.length === 9: return '#####-#####'
        case this.phone.length === 10: return '(##) ####-#####'
        default: return '(##) #####-####'
      }
    }
  }
})
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