Vue
Директива v-mask из tinyval-mask/vue вешает маску на поле. Сам Vue пакету не нужен: директива — обычный объект, Vue используется только для типов.
<script setup lang="ts">
import { ref } from 'vue';
import { phone, money } from 'tinyval-mask/presets';
import { vMask } from 'tinyval-mask/vue';
// create masks once, not inline in the template
const phoneMask = phone();
const moneyMask = money({ currency: '₽' });
const tel = ref('');
const amount = ref('');
</script>
<template>
<input v-model="tel" v-mask="phoneMask" />
<input v-model="amount" v-mask="moneyMask" inputmode="decimal" />
<input v-mask="'99.99.9999'" />
</template>- В
v-modelпопадает значение с маской:+7 (999) 123-45-67. Чтобы получить значение без маски, добавьте модификатор.raw— см. ниже. - Маску создавайте в
<script>: выражение вродеv-mask="phone()"создаёт новую маску при каждой перерисовке. - Директиву можно повесить на обёртку — она найдёт
<input>внутри. Так маска работает с полями UI-библиотек. - Для глобальной регистрации:
app.directive('mask', vMask).
Значение без маски — .raw
С модификатором .raw в поле видна маска, а в v-model попадает значение без неё — то же, что вернул бы unmask. Его можно сразу сохранять:
<input v-model="tel" v-mask.raw="phoneMask" /> <!-- tel: '79991234567' -->
<input v-model="amount" v-mask.raw="moneyMask" /> <!-- amount: '1500.5' -->Значение из модели показывается с маской: tel = '79991234567' → в поле +7 (999) 123-45-67. Курсор при правке в середине не прыгает, даже когда Vue перерисовывает поле.
Видимый шаблон
Передайте символ-заполнитель — при фокусе в поле появится весь шаблон, курсор встанет на первую пустую позицию:
<input v-model="tel" v-mask.raw="{ mask: phoneMask, placeholder: '_' }" placeholder="Phone" />
<!-- on focus: +7 (___) ___-__-__ typing: +7 (999) 12_-__-__ -->- В
v-modelшаблон не попадает: без.rawтам+7 (999) 12, с.raw—7999912. - Пустое поле при уходе очищается — видна обычная подсказка
placeholder. Частично заполненное сохраняет шаблон. - У числовых масок шаблона нет: их длина не фиксирована.
С tinyval-vue
v-mask работает на <TvField> и на любом поле формы tinyval-vue. С .raw в форму сразу попадают цифры, и схема проверяет их без unmask:
<script setup lang="ts">
import { object, string, pipe, length } from 'tinyval';
import { useForm, TvForm, TvField, TvError } from 'tinyval-vue';
import { phone } from 'tinyval-mask/presets';
import { vMask } from 'tinyval-mask/vue';
const phoneMask = phone();
const Contact = object({
phone: pipe(string(), length(11)),
});
const form = useForm(Contact, { initial: { phone: '' } });
</script>
<template>
<TvForm :form="form" @submit="(data) => api.post('/contacts', data)">
<TvField name="phone" v-mask.raw="{ mask: phoneMask, placeholder: '_' }" inputmode="tel" />
<TvError name="phone" />
</TvForm>
</template>В поле — +7 (999) 123-45-67, в form.values.phone и в data — 79991234567.
UI-библиотеки
<el-input v-model="tel" v-mask="phoneMask" />
<v-text-field v-model="tel" v-mask="phoneMask" />