| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541 |
- <template>
- <view class="phone-input-container">
- <!-- 手机号输入区域 -->
- <view class="phone-input-wrap">
- <!-- 区号选择 -->
- <view class="code-selector" @tap="showCodePicker = true">
- <text class="code-text">{{ selectedCode }}</text>
- <u-icon name="arrow-down-fill" size="20" color="#636B77"></u-icon>
- </view>
- </view>
- <!-- 区号选择弹窗 -->
- <u-popup :show="showCodePicker" mode="bottom" :round="20">
- <view class="code-picker-wrap">
- <view class="title">
- <text>请选择区号</text>
- <image :src="imgBase+'remind_close.png'" @tap="showCodePicker = false"></image>
- </view>
- <!-- 搜索框 -->
- <view class="search-wrap">
- <input class="search-input" type="text" placeholder="搜索国家/地区/区号" v-model="searchKeyword" @input="filterCodeList" />
- </view>
- <!-- 区号列表 -->
- <scroll-view class="code-list-scroll" scroll-y :style="{ height: '600rpx' }">
- <view class="code-item" v-for="(item, index) in filteredCodeList" :key="index" @tap="selectCode(item)">
- <text class="country-name">{{ item.name }}</text>
- <text class="code-num">{{ item.code }}</text>
- </view>
- <!-- 无搜索结果提示 -->
- <view v-if="filteredCodeList.length === 0" class="empty-tip">未找到相关国家/地区</view>
- </scroll-view>
- </view>
- </u-popup>
- </view>
- </template>
- <script>
- export default {
- name: 'PhoneInput',
- props: {
- // 初始区号,默认+86
- initCode: {
- type: String,
- default: '+86'
- },
- // 是否必填
- required: {
- type: Boolean,
- default: true
- }
- },
- data() {
- return {
- // 显示区号选择弹窗
- showCodePicker: false,
- // 当前选中的区号
- selectedCode: '',
- // 手机号
- phoneNumber: '',
- // 搜索关键词
- searchKeyword: '',
- // 完整的全球国家/地区区号列表(200+)
- codeList: [
- { name: '中国', code: '+86' },
- { name: '中国香港', code: '+852' },
- { name: '中国澳门', code: '+853' },
- { name: '中国台湾', code: '+886' },
- { name: '阿富汗', code: '+93' },
- { name: '阿尔巴尼亚', code: '+355' },
- { name: '阿尔及利亚', code: '+213' },
- { name: '美属萨摩亚', code: '+1684' },
- { name: '安道尔', code: '+376' },
- { name: '安哥拉', code: '+244' },
- { name: '安圭拉', code: '+1264' },
- { name: '安提瓜和巴布达', code: '+1268' },
- { name: '阿根廷', code: '+54' },
- { name: '亚美尼亚', code: '+374' },
- { name: '阿鲁巴', code: '+297' },
- { name: '澳大利亚', code: '+61' },
- { name: '奥地利', code: '+43' },
- { name: '阿塞拜疆', code: '+994' },
- { name: '巴哈马', code: '+1242' },
- { name: '巴林', code: '+973' },
- { name: '孟加拉国', code: '+880' },
- { name: '巴巴多斯', code: '+1246' },
- { name: '白俄罗斯', code: '+375' },
- { name: '比利时', code: '+32' },
- { name: '伯利兹', code: '+501' },
- { name: '贝宁', code: '+229' },
- { name: '百慕大', code: '+1441' },
- { name: '不丹', code: '+975' },
- { name: '玻利维亚', code: '+591' },
- { name: '波黑', code: '+387' },
- { name: '博茨瓦纳', code: '+267' },
- { name: '巴西', code: '+55' },
- { name: '英属印度洋领地', code: '+246' },
- { name: '文莱', code: '+673' },
- { name: '波斯尼亚和黑塞哥维那', code: '+387' },
- { name: '保加利亚', code: '+359' },
- { name: '布基纳法索', code: '+226' },
- { name: '布隆迪', code: '+257' },
- { name: '佛得角', code: '+238' },
- { name: '柬埔寨', code: '+855' },
- { name: '喀麦隆', code: '+237' },
- { name: '加拿大', code: '+1' },
- { name: '佛得角', code: '+238' },
- { name: '开曼群岛', code: '+1345' },
- { name: '中非', code: '+236' },
- { name: '乍得', code: '+235' },
- { name: '智利', code: '+56' },
- { name: '哥伦比亚', code: '+57' },
- { name: '科摩罗', code: '+269' },
- { name: '刚果(布)', code: '+242' },
- { name: '刚果(金)', code: '+243' },
- { name: '库克群岛', code: '+682' },
- { name: '哥斯达黎加', code: '+506' },
- { name: '科特迪瓦', code: '+225' },
- { name: '克罗地亚', code: '+385' },
- { name: '古巴', code: '+53' },
- { name: '塞浦路斯', code: '+357' },
- { name: '捷克', code: '+420' },
- { name: '丹麦', code: '+45' },
- { name: '吉布提', code: '+253' },
- { name: '多米尼克', code: '+1767' },
- { name: '多米尼加', code: '+1809' },
- { name: '东帝汶', code: '+670' },
- { name: '厄瓜多尔', code: '+593' },
- { name: '埃及', code: '+20' },
- { name: '萨尔瓦多', code: '+503' },
- { name: '赤道几内亚', code: '+240' },
- { name: '厄立特里亚', code: '+291' },
- { name: '爱沙尼亚', code: '+372' },
- { name: '埃塞俄比亚', code: '+251' },
- { name: '福克兰群岛', code: '+500' },
- { name: '法罗群岛', code: '+298' },
- { name: '斐济', code: '+679' },
- { name: '芬兰', code: '+358' },
- { name: '法国', code: '+33' },
- { name: '法属圭亚那', code: '+594' },
- { name: '法属波利尼西亚', code: '+689' },
- { name: '加蓬', code: '+241' },
- { name: '冈比亚', code: '+220' },
- { name: '格鲁吉亚', code: '+995' },
- { name: '德国', code: '+49' },
- { name: '加纳', code: '+233' },
- { name: '直布罗陀', code: '+350' },
- { name: '希腊', code: '+30' },
- { name: '格陵兰', code: '+299' },
- { name: '格林纳达', code: '+1473' },
- { name: '瓜德罗普', code: '+590' },
- { name: '关岛', code: '+1671' },
- { name: '危地马拉', code: '+502' },
- { name: '几内亚', code: '+224' },
- { name: '几内亚比绍', code: '+245' },
- { name: '圭亚那', code: '+592' },
- { name: '海地', code: '+509' },
- { name: '洪都拉斯', code: '+504' },
- { name: '匈牙利', code: '+36' },
- { name: '冰岛', code: '+354' },
- { name: '印度', code: '+91' },
- { name: '印度尼西亚', code: '+62' },
- { name: '伊朗', code: '+98' },
- { name: '伊拉克', code: '+964' },
- { name: '爱尔兰', code: '+353' },
- { name: '以色列', code: '+972' },
- { name: '意大利', code: '+39' },
- { name: '牙买加', code: '+1876' },
- { name: '日本', code: '+81' },
- { name: '约旦', code: '+962' },
- { name: '哈萨克斯坦', code: '+7' },
- { name: '肯尼亚', code: '+254' },
- { name: '基里巴斯', code: '+686' },
- { name: '朝鲜', code: '+850' },
- { name: '韩国', code: '+82' },
- { name: '科威特', code: '+965' },
- { name: '吉尔吉斯斯坦', code: '+996' },
- { name: '老挝', code: '+856' },
- { name: '拉脱维亚', code: '+371' },
- { name: '黎巴嫩', code: '+961' },
- { name: '莱索托', code: '+266' },
- { name: '利比里亚', code: '+231' },
- { name: '利比亚', code: '+218' },
- { name: '列支敦士登', code: '+423' },
- { name: '立陶宛', code: '+370' },
- { name: '卢森堡', code: '+352' },
- { name: '马达加斯加', code: '+261' },
- { name: '马拉维', code: '+265' },
- { name: '马来西亚', code: '+60' },
- { name: '马尔代夫', code: '+960' },
- { name: '马里', code: '+223' },
- { name: '马耳他', code: '+356' },
- { name: '马绍尔群岛', code: '+692' },
- { name: '马提尼克', code: '+596' },
- { name: '毛里塔尼亚', code: '+222' },
- { name: '毛里求斯', code: '+230' },
- { name: '马约特', code: '+262' },
- { name: '墨西哥', code: '+52' },
- { name: '密克罗尼西亚', code: '+691' },
- { name: '摩尔多瓦', code: '+373' },
- { name: '摩纳哥', code: '+377' },
- { name: '蒙古', code: '+976' },
- { name: '黑山', code: '+382' },
- { name: '蒙特塞拉特', code: '+1664' },
- { name: '摩洛哥', code: '+212' },
- { name: '莫桑比克', code: '+258' },
- { name: '缅甸', code: '+95' },
- { name: '纳米比亚', code: '+264' },
- { name: '瑙鲁', code: '+674' },
- { name: '尼泊尔', code: '+977' },
- { name: '荷兰', code: '+31' },
- { name: '荷属安的列斯', code: '+599' },
- { name: '新喀里多尼亚', code: '+687' },
- { name: '新西兰', code: '+64' },
- { name: '尼加拉瓜', code: '+505' },
- { name: '尼日尔', code: '+227' },
- { name: '尼日利亚', code: '+234' },
- { name: '纽埃', code: '+683' },
- { name: '诺福克岛', code: '+672' },
- { name: '北马里亚纳群岛', code: '+1670' },
- { name: '挪威', code: '+47' },
- { name: '阿曼', code: '+968' },
- { name: '巴基斯坦', code: '+92' },
- { name: '帕劳', code: '+680' },
- { name: '巴勒斯坦', code: '+970' },
- { name: '巴拿马', code: '+507' },
- { name: '巴布亚新几内亚', code: '+675' },
- { name: '巴拉圭', code: '+595' },
- { name: '秘鲁', code: '+51' },
- { name: '菲律宾', code: '+63' },
- { name: '波兰', code: '+48' },
- { name: '葡萄牙', code: '+351' },
- { name: '波多黎各', code: '+1787' },
- { name: '卡塔尔', code: '+974' },
- { name: '罗马尼亚', code: '+40' },
- { name: '俄罗斯', code: '+7' },
- { name: '卢旺达', code: '+250' },
- { name: '留尼汪', code: '+262' },
- { name: '圣赫勒拿', code: '+290' },
- { name: '圣基茨和尼维斯', code: '+1869' },
- { name: '圣卢西亚', code: '+1758' },
- { name: '圣皮埃尔和密克隆', code: '+508' },
- { name: '圣文森特和格林纳丁斯', code: '+1784' },
- { name: '萨摩亚', code: '+685' },
- { name: '圣马力诺', code: '+378' },
- { name: '圣多美和普林西比', code: '+239' },
- { name: '沙特阿拉伯', code: '+966' },
- { name: '塞内加尔', code: '+221' },
- { name: '塞尔维亚', code: '+381' },
- { name: '塞舌尔', code: '+248' },
- { name: '塞拉利昂', code: '+232' },
- { name: '新加坡', code: '+65' },
- { name: '斯洛伐克', code: '+421' },
- { name: '斯洛文尼亚', code: '+386' },
- { name: '所罗门群岛', code: '+677' },
- { name: '索马里', code: '+252' },
- { name: '南非', code: '+27' },
- { name: '南苏丹', code: '+211' },
- { name: '西班牙', code: '+34' },
- { name: '斯里兰卡', code: '+94' },
- { name: '苏丹', code: '+249' },
- { name: '苏里南', code: '+597' },
- { name: '斯威士兰', code: '+268' },
- { name: '瑞典', code: '+46' },
- { name: '瑞士', code: '+41' },
- { name: '叙利亚', code: '+963' },
- { name: '塔吉克斯坦', code: '+992' },
- { name: '坦桑尼亚', code: '+255' },
- { name: '泰国', code: '+66' },
- { name: '多哥', code: '+228' },
- { name: '汤加', code: '+676' },
- { name: '特立尼达和多巴哥', code: '+1868' },
- { name: '突尼斯', code: '+216' },
- { name: '土耳其', code: '+90' },
- { name: '土库曼斯坦', code: '+993' },
- { name: '特克斯和凯科斯群岛', code: '+1649' },
- { name: '图瓦卢', code: '+688' },
- { name: '乌干达', code: '+256' },
- { name: '乌克兰', code: '+380' },
- { name: '阿联酋', code: '+971' },
- { name: '英国', code: '+44' },
- { name: '美国', code: '+1' },
- { name: '乌拉圭', code: '+598' },
- { name: '乌兹别克斯坦', code: '+998' },
- { name: '瓦努阿图', code: '+678' },
- { name: '梵蒂冈', code: '+379' },
- { name: '委内瑞拉', code: '+58' },
- { name: '越南', code: '+84' },
- { name: '英属维尔京群岛', code: '+1284' },
- { name: '美属维尔京群岛', code: '+1340' },
- { name: '瓦利斯和富图纳', code: '+681' },
- { name: '西撒哈拉', code: '+212' },
- { name: '也门', code: '+967' },
- { name: '赞比亚', code: '+260' },
- { name: '津巴布韦', code: '+263' }
- ],
- // 筛选后的区号列表
- filteredCodeList: []
- };
- },
- computed: {
- // 根据区号获取手机号最大长度(扩展更多常用国家)
- getPhoneMaxlength() {
- switch (this.selectedCode) {
- case '+86':
- return 11; // 中国大陆
- case '+852':
- case '+853':
- return 8; // 港澳
- case '+886':
- return 10; // 台湾
- case '+1':
- return 10; // 美国/加拿大
- case '+44':
- return 11; // 英国
- case '+81':
- return 11; // 日本
- case '+82':
- return 11; // 韩国
- case '+65':
- return 8; // 新加坡
- case '+60':
- return 10; // 马来西亚
- case '+91':
- return 10; // 印度
- case '+61':
- return 9; // 澳大利亚
- case '+33':
- return 10; // 法国
- case '+49':
- return 11; // 德国
- case '+34':
- return 9; // 西班牙
- case '+39':
- return 10; // 意大利
- default:
- return 20; // 其他国家默认
- }
- }
- },
- watch: {
- // 监听初始区号变化
- initCode: {
- immediate: true,
- handler(val) {
- this.selectedCode = val;
- this.filteredCodeList = [...this.codeList];
- }
- }
- },
- methods: {
- // 优化筛选逻辑:支持拼音/汉字/区号模糊匹配
- filterCodeList() {
- if (!this.searchKeyword) {
- this.filteredCodeList = [...this.codeList];
- return;
- }
- const keyword = this.searchKeyword.trim().toLowerCase();
- // 模糊搜索名称(中文)或区号
- this.filteredCodeList = this.codeList.filter((item) => {
- return item.name.toLowerCase().includes(keyword) || item.code.toLowerCase().includes(keyword);
- });
- },
- // 选择区号
- selectCode(item) {
- this.selectedCode = item.code;
- this.showCodePicker = false;
- this.$emit('code-change', item.code);
- this.validatePhone();
- },
- // 手机号输入处理
- handlePhoneInput() {
- this.$emit('phone-change', {
- code: this.selectedCode,
- phone: this.phoneNumber
- });
- this.validatePhone();
- },
- // 手机号格式校验(扩展常用国家)
- validatePhone() {
- let isValid = true;
- let message = '';
- // 空值校验
- if (this.required && !this.phoneNumber) {
- isValid = false;
- message = '请输入手机号';
- } else if (this.phoneNumber) {
- // 扩展更多国家的校验规则
- const phone = this.phoneNumber;
- switch (this.selectedCode) {
- case '+86': // 中国大陆
- isValid = /^1[3-9]\d{9}$/.test(phone);
- message = isValid ? '' : '请输入正确的中国大陆手机号';
- break;
- case '+852':
- case '+853': // 港澳
- isValid = /^\d{8}$/.test(phone);
- message = isValid ? '' : `请输入正确的${this.selectedCode === '+852' ? '香港' : '澳门'}手机号`;
- break;
- case '+886': // 台湾
- isValid = /^\d{10}$/.test(phone);
- message = isValid ? '' : '请输入正确的台湾手机号';
- break;
- case '+1': // 美国/加拿大
- isValid = /^\d{10}$/.test(phone);
- message = isValid ? '' : '请输入正确的美国/加拿大手机号';
- break;
- case '+65': // 新加坡
- isValid = /^\d{8}$/.test(phone);
- message = isValid ? '' : '请输入正确的新加坡手机号';
- break;
- // 其他国家仅校验非空,可根据需求扩展
- default:
- isValid = phone.length > 0;
- message = isValid ? '' : '请输入正确的手机号';
- }
- }
- this.$emit('validate', {
- isValid,
- message,
- fullPhone: `${this.selectedCode}${this.phoneNumber}`
- });
- return isValid;
- },
- // 对外暴露的获取完整手机号方法
- getFullPhone() {
- const isValid = this.validatePhone();
- return {
- isValid,
- fullPhone: isValid ? `${this.selectedCode}${this.phoneNumber}` : ''
- };
- }
- }
- };
- </script>
- <style scoped lang="scss">
- .phone-input-container {
- width: 100%;
- }
- .phone-input-wrap {
- display: flex;
- }
- .code-selector {
- display: flex;
- align-items: center;
- margin-right: 20rpx;
- min-width: 80rpx;
- }
- .code-text {
- font-size: 30rpx;
- color: #002846;
- margin-right: 8rpx;
- margin-left: 50rpx;
- line-height: 48rpx;
- }
- .phone-input {
- flex: 1;
- font-size: 32rpx;
- color: #333;
- height: 60rpx;
- }
- .code-picker-wrap {
- background: #fff;
- padding: 30rpx 20rpx 40rpx;
- border-radius: 20rpx 20rpx 0 0;
- .title {
- position: relative;
- text-align: center;
- text {
- font-size: 36rpx;
- font-family: PingFang-SC-Bold, PingFang-SC;
- font-weight: bold;
- color: #333333;
- }
- image {
- width: 46rpx;
- height: 46rpx;
- position: absolute;
- right: 10rpx;
- top: 50%;
- margin-top: -23rpx;
- }
- }
- }
- .search-wrap {
- padding: 20rpx;
- border-bottom: 1px solid #f5f5f5;
- }
- .search-input {
- width: 100%;
- height: 72rpx;
- padding: 0 20rpx;
- border: 1px solid #e5e5e5;
- border-radius: 8rpx;
- box-sizing: border-box;
- font-size: 30rpx;
- margin-top: 20rpx;
- }
- .code-list-scroll {
- width: 100%;
- }
- .code-item {
- display: flex;
- justify-content: space-between;
- align-items: center;
- padding: 24rpx 20rpx;
- border-bottom: 1px solid #f5f5f5;
- font-size: 30rpx;
- }
- .country-name {
- color: #333;
- }
- .code-num {
- color: #666;
- }
- .empty-tip {
- text-align: center;
- padding: 40rpx 0;
- font-size: 28rpx;
- color: #999;
- }
- </style>
|