如何在同一网站复用国际区号选择器JavaScript代码
解决国际区号选择器跨表单复用的代码冲突问题
你的代码目前仅在联系表单生效,核心原因是document.querySelector()只会获取第一个匹配的DOM元素,咨询表单的选择器未被绑定事件;同时全局变量(如selectedCountry、ccDiv等)会被多个选择器共享,导致状态混乱。解决方案是将区号选择器封装为独立实例,每个表单的选择器拥有专属元素引用和状态,实现无冲突复用。
修改后的完整代码
HTML
<link rel="stylesheet" href="https://amitdutta.co.in/flag/css/flag-icon.css"> <!------------- 联系表单区号选择器 ------------> <div class="cc-wrapper contact-frm-cc"> <button class="cc-telcode">Tel code</button> <section class="cc-container"> <input type="text" class="cc-search-box" placeholder="Search for country" /> <ul class="cc-data-list"></ul> </section> </div> <!------------- 咨询表单区号选择器 ------------> <div class="cc-wrapper consult-frm-cc"> <button class="cc-telcode">Tel code</button> <section class="cc-container"> <input type="text" class="cc-search-box" placeholder="Search for country" /> <ul class="cc-data-list"></ul> </section> </div>
CSS
.cc-telcode { margin-bottom: 1em; display: flex; justify-content: center; width: 100%; } .cc-telcode div.cc-code, .cc-list-items div.name { margin-left: 0.25em; } .cc-container { display: none; width: 300px; position: absolute; } .show-cc-list { display: block; z-index: 999; } .cc-data-list { max-height: 100px; list-style: none; margin: 1em 0 0 0; padding: 0; overflow-y: scroll; border: 1px solid darkgray; /* 修复原代码拼写错误:soldi -> solid */ } .cc-list-items { display: flex; padding: 0.25em; border: 1px solid lightgray; } .cc-list-items:hover { cursor: pointer; background-color: lightyellow; } .selected-country { cursor: pointer; background-color: rgb(73, 118, 241); } .cc-wrapper { width: 100px; /* 统一容器宽度,减少重复代码 */ }
JavaScript
// 封装区号选择器为类,每个实例独立管理自身元素和状态 class CountryCodeSelector { constructor(container) { // 缓存当前实例的DOM元素 this.ccDiv = container; this.ccButton = container.querySelector(".cc-telcode"); this.ccContainer = container.querySelector(".cc-container"); this.ccSearchInput = container.querySelector(".cc-search-box"); this.ccList = container.querySelector(".cc-data-list"); this.selectedCountry = ""; // 每个实例自有状态,不共享 // 绑定事件(用bind确保this指向当前实例) this.ccButton.addEventListener("click", this.handleButton.bind(this)); this.ccSearchInput.addEventListener("input", this.handleInput.bind(this)); this.ccList.addEventListener("click", this.handleListClick.bind(this)); document.addEventListener("click", this.handleDocumentClick.bind(this)); } // 点击外部关闭选择器 handleDocumentClick(event) { if (!this.ccDiv.contains(event.target)) { this.ccContainer.classList.remove("show-cc-list"); } } // 过滤国家数据 filterData(value) { const data = [ { name: "Afghanistan", code: "93", flag: "afg" }, { name: "Albania", code: "355", flag: "alb" }, { name: "Algeria", code: "213", flag: "dza" }, { name: "American Samoa", code: "1-684", flag: "asm" }, { name: "Andorra", code: "376", flag: "and" }, { name: "Angola", code: "244", flag: "ago" }, { name: "Anguilla", code: "1-264", flag: "aia" }, { name: "Antarctica", code: "672", flag: "ata" }, { name: "Antigua and Barbuda", code: "1-268", flag: "atg" }, { name: "Argentina", code: "54", flag: "arg" }, { name: "Armenia", code: "374", flag: "arm" }, { name: "Aruba", code: "297", flag: "abw" }, { name: "Australia", code: "61", flag: "aus" }, { name: "Austria", code: "43", flag: "aut" }, { name: "Azerbaijan", code: "994", flag: "aze" }, { name: "Bahamas", code: "1-242", flag: "bhs" }, { name: "Bahrain", code: "973", flag: "bhr" }, { name: "Bangladesh", code: "880", flag: "bgd" }, { name: "Barbados", code: "1-246", flag: "brb" }, { name: "Belarus", code: "375", flag: "blr" }, { name: "Belgium", code: "32", flag: "bel" }, { name: "Belize", code: "501", flag: "blz" }, { name: "Benin", code: "229", flag: "ben" }, { name: "Bermuda", code: "1-441", flag: "bmu" }, { name: "Bhutan", code: "975", flag: "btn" }, { name: "Bolivia", code: "591", flag: "bol" }, { name: "Bosnia and Herzegovina", code: "387", flag: "bih" }, { name: "Botswana", code: "267", flag: "bwa" }, { name: "Brazil", code: "55", flag: "bra" }, { name: "British Indian Ocean Territory", code: "246", flag: "iot" }, { name: "British Virgin Islands", code: "1-284", flag: "vgb" }, { name: "Brunei", code: "673", flag: "brn" }, { name: "Bulgaria", code: "359", flag: "bgr" }, { name: "Burkina Faso", code: "226", flag: "bfa" }, { name: "Burundi", code: "257", flag: "bdi" }, { name: "Cambodia", code: "855", flag: "khm" }, { name: "Cameroon", code: "237", flag: "cmr" }, { name: "Canada", code: "1", flag: "can" }, { name: "Cape Verde", code: "238", flag: "cpv" }, { name: "Cayman Islands", code: "1-345", flag: "cym" }, { name: "Central African Republic", code: "236", flag: "caf" }, { name: "Chad", code: "235", flag: "tcd" }, { name: "Chile", code: "56", flag: "chl" }, { name: "China", code: "86", flag: "chn" }, { name: "Christmas Island", code: "61", flag: "cxr" }, { name: "Cocos Islands", code: "61", flag: "cck" }, { name: "Colombia", code: "57", flag: "col" }, { name: "Comoros", code: "269", flag: "com" }, { name: "Cook Islands", code: "682", flag: "cok" }, { name: "Costa Rica", code: "506", flag: "cri" }, { name: "Croatia", code: "385", flag: "hrv" }, // 更多国家数据可在此添加 ]; return data.filter(obj => { return obj.name.toLowerCase().startsWith(value.toLowerCase()) || obj.code.toLowerCase().startsWith(value.toLowerCase()); }); } // 生成国家列表HTML createListHtml(data) { return data.map(obj => { const { name, code, flag } = obj; const isSelected = obj.code === this.selectedCountry ? "selected-country" : ""; return ` <li class="cc-list-items ${isSelected}" data-name="${name}" data-code="${code}" data-flag="${flag}"> <div class="flag-icon flag-icon-${flag}"></div> <div class="name">${name} (+${code})</div> </li> `; }).join(""); } // 生成无数据提示HTML createNoDataHtml() { return '<li class="nodata">No data available</li>'; } // 生成按钮HTML createButtonHtml(code, flag) { return ` <div class="flag-icon flag-icon-${flag}"></div> <span class="cc-code">+${code}</span> `; } // 点击按钮切换选择器显示状态 handleButton() { this.ccContainer.classList.toggle("show-cc-list"); this.ccList.innerHTML = this.createListHtml(this.filterData("")); } // 搜索输入处理 handleInput(e) { const value = e.target.value.trim(); const filteredData = this.filterData(value); if (value && filteredData.length === 0) { this.ccList.innerHTML = this.createNoDataHtml(); } else { this.ccList.innerHTML = this.createListHtml(filteredData); } } // 选择国家处理 handleListClick(e) { const item = e.target.closest(".cc-list-items"); if (!item) return; const { code, flag } = item.dataset; this.selectedCountry = code; this.ccButton.innerHTML = this.createButtonHtml(code, flag); this.ccContainer.classList.remove("show-cc-list"); } } // 初始化所有区号选择器实例 document.querySelectorAll(".cc-wrapper").forEach(container => { new CountryCodeSelector(container); });
关键修改说明
- 封装为类:将选择器逻辑封装成
CountryCodeSelector类,每个实例对应一个表单的选择器,元素引用和状态完全独立,避免全局冲突。 - 批量初始化:用
document.querySelectorAll()获取所有选择器容器,遍历创建实例,实现一次代码复用多个表单。 - 修复事件绑定问题:原代码的
handleDocumentClick内部重复绑定document事件,会导致多次触发,现在改为每个实例单独处理外部点击关闭逻辑。 - 统一CSS类:添加通用类
.cc-wrapper,减少重复CSS代码,同时保留原表单类名用于特殊样式定制。 - 修复拼写错误:修正CSS中
border: 1px soldi darkgray的拼写错误为solid。
内容的提问来源于stack exchange,提问作者Gupa Dutta
相关产品推荐
相关产品推荐

