146 lines
3.4 KiB
Vue
146 lines
3.4 KiB
Vue
<!-- https://github.com/jackocnr/intl-tel-input/blob/master/react/src/intl-tel-input/react.tsx -->
|
|
<script lang="ts" setup>
|
|
import intlTelInput, { Iti, SomeOptions } from 'intl-tel-input';
|
|
import 'intl-tel-input/build/css/intlTelInput.min.css';
|
|
import 'intl-tel-input/build/js/utils.js';
|
|
import { ref, onMounted, onBeforeUnmount, nextTick, watch } from 'vue';
|
|
import useI18n from '@/hooks/useI18n';
|
|
const { currentLocale } = useI18n();
|
|
const emit = defineEmits(['update:value', 'update:change']);
|
|
const props = defineProps({
|
|
/**有效检验 */
|
|
preciseValidation: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
/**手机号 */
|
|
value: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
/**禁用输入 */
|
|
disabled: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
/**手机号输入提示 */
|
|
placeholder: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
/**手机号输入最大字符串长度 */
|
|
maxlength: {
|
|
type: Number,
|
|
default: 255,
|
|
},
|
|
/**允许清空手机号输入框 */
|
|
allowClear: {
|
|
type: Boolean,
|
|
},
|
|
});
|
|
|
|
const inputRef = ref<HTMLInputElement | null>(null);
|
|
const itiRef = ref<Iti | null>(null);
|
|
|
|
function fnChange() {
|
|
if (!itiRef.value) return;
|
|
|
|
const num = itiRef.value?.getNumber() || '';
|
|
const countryIso = itiRef.value?.getSelectedCountryData().iso2 || '';
|
|
// note: this number will be in standard E164 format, but any container component can use
|
|
// intlTelInputUtils.formatNumber() to convert this to another format
|
|
// as well as intlTelInputUtils.getNumberType() etc. if need be
|
|
let data = {
|
|
num,
|
|
countryIso,
|
|
validity: false,
|
|
errorCode: -1,
|
|
};
|
|
|
|
const isValid = props.preciseValidation
|
|
? itiRef.value.isValidNumberPrecise()
|
|
: itiRef.value.isValidNumber();
|
|
if (isValid) {
|
|
data.validity = true;
|
|
data.errorCode = 0;
|
|
} else {
|
|
const errorCode = itiRef.value.getValidationError();
|
|
data.validity = false;
|
|
data.errorCode = errorCode;
|
|
}
|
|
// console.log(data);
|
|
emit('update:value', num);
|
|
emit('update:change', data);
|
|
}
|
|
|
|
watch(
|
|
() => props.value,
|
|
v => {
|
|
if (v) {
|
|
itiRef.value?.setNumber(v);
|
|
} else {
|
|
itiRef.value?.setNumber('');
|
|
}
|
|
}
|
|
);
|
|
|
|
onMounted(() => {
|
|
nextTick(async () => {
|
|
if (inputRef.value) {
|
|
let i18n = undefined;
|
|
let initialCountry = 'us';
|
|
// 语言文件导入问题只能复制到项目内处理
|
|
// import fr from "intl-tel-input/i18n/fr";
|
|
if (currentLocale.value.startsWith('zh')) {
|
|
const { default: zh } = await import('./i18n/zh');
|
|
i18n = zh;
|
|
initialCountry = 'cn';
|
|
} else {
|
|
const { default: en } = await import('./i18n/en');
|
|
i18n = en;
|
|
initialCountry = 'us';
|
|
}
|
|
|
|
itiRef.value = intlTelInput(inputRef.value, {
|
|
initialCountry: initialCountry,
|
|
formatOnDisplay: true,
|
|
autoPlaceholder: 'polite',
|
|
i18n: i18n,
|
|
} as SomeOptions);
|
|
inputRef.value.addEventListener('countrychange', fnChange);
|
|
}
|
|
});
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
if (inputRef.value) {
|
|
inputRef.value.removeEventListener('countrychange', fnChange);
|
|
}
|
|
itiRef.value?.destroy();
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<input
|
|
type="tel"
|
|
class="ant-input"
|
|
ref="inputRef"
|
|
:value="value"
|
|
:disabled="disabled"
|
|
:placeholder="placeholder"
|
|
:maxlength="maxlength"
|
|
:allow-clear="allowClear"
|
|
@input="fnChange"
|
|
/>
|
|
</template>
|
|
|
|
<style lang="css">
|
|
.iti {
|
|
display: block;
|
|
}
|
|
|
|
.iti .iti__country-container .iti__search-input {
|
|
padding: 4px 8px;
|
|
}
|
|
</style>
|