feat: 国际手机号输入框
This commit is contained in:
145
src/components/IntlTelInput/index.vue
Normal file
145
src/components/IntlTelInput/index.vue
Normal file
@@ -0,0 +1,145 @@
|
||||
<!-- 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>
|
||||
Reference in New Issue
Block a user