2026年民政部四级行政地址联动

image

 

  1 <!DOCTYPE html>
  2 <html>
  3 <head>
  4     <link rel="icon shortcut" href="/favicon.ico?v=1" type="image/x-icon">
  5     <meta name="viewport" content="width=device-width" />
  6     <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  7     <meta name="keywords" content="四级行政地址联动">
  8     <meta name="description" content="四级行政地址联动">
  9     <title>民政部四级联动 层级自动隐藏版</title>
 10     <style>
 11         body { font-family: "Microsoft YaHei", sans-serif; padding: 20px; background: #f0f2f5; }
 12         .container { max-width: 520px; margin: 50px auto; background: #fff; padding: 30px; border-radius: 10px; box-shadow: 0 0 20px rgba(0,0,0,0.1); }
 13         h2 { text-align: center; color: #333; margin-bottom: 25px; }
 14         .form-group { margin-bottom: 15px; }
 15         /* 隐藏层级容器 */
 16         .hide-item { display: none !important; }
 17         label { display: block; margin-bottom: 6px; font-weight: bold; color: #555; font-size: 14px; }
 18         select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-size: 14px; box-sizing: border-box; transition: all 0.3s; }
 19         select:disabled { background-color: #f9f9f9; color: #aaa; cursor: not-allowed; border-color: #eee; }
 20         .result { margin-top: 25px; padding: 15px; background: #e8f5e8; border-radius: 5px; color: #2e7d32; display: none; font-weight: bold; text-align: center;line-height: 1.6;}
 21     </style>
 22 </head>
 23 <body>
 24     <div class="container">
 25         <h2><span style="color: red;">📍 </span>民政部四级行政地址联动</h2>
 26         <div class="form-group" id="provinceBox">
 27             <label>省/市/直辖市</label>
 28             <select id="province"><option value="">加载中...</option></select>
 29         </div>
 30 
 31         <!-- 城市容器 可自动隐藏 -->
 32         <div class="form-group" id="cityBox">
 33             <label>地级市</label>
 34             <select id="city" disabled><option value="">请先选择省份</option></select>
 35         </div>
 36 
 37         <!-- 区县容器 可自动隐藏 -->
 38         <div class="form-group" id="districtBox">
 39             <label>区/县/市</label>
 40             <select id="district" disabled><option value="">请先选择城市</option></select>
 41         </div>
 42 
 43         <div class="form-group" id="townBox">
 44             <label>乡镇/街道</label>
 45             <select id="town" disabled><option value="">请先选择区县</option></select>
 46         </div>
 47 
 48         <div class="result" id="result"></div>
 49         <li>JSON数据来源: https://dmfw.mca.gov.cn/9095/xzqh/getList</li>
 50         <li>API文档: https://dmfw.mca.gov.cn/interface.html</li>
 51     </div>
 52 
 53 <script>
 54     const API_URL = 'https://dmfw.mca.gov.cn/9095/xzqh/getList';
 55     const memoryCache = { provinces: null, areas: {} };
 56     const selects = {
 57         province: document.getElementById('province'),
 58         city: document.getElementById('city'),
 59         district: document.getElementById('district'),
 60         town: document.getElementById('town')
 61     };
 62     const boxes = {
 63         provinceBox: document.getElementById('provinceBox'),
 64         cityBox: document.getElementById('cityBox'),
 65         districtBox: document.getElementById('districtBox'),
 66         townBox: document.getElementById('townBox')
 67     };
 68     const resultDiv = document.getElementById('result');
 69 
 70     // 特殊行政区
 71     const zhiXiaShi = ['北京市','天津市','上海市','重庆市'];
 72     const wuSheQuShi = ['东莞市','中山市','儋州市','嘉峪关市','济源市','仙桃市','潜江市','天门市','神农架林区'];
 73     const zhiXiaXian = ['琼海市','文昌市','万宁市','东方市','五指山市','胡杨河市','石河子市','阿拉尔市'];
 74 
 75     function resetAllShow() {
 76         boxes.cityBox.classList.remove('hide-item');
 77         boxes.districtBox.classList.remove('hide-item');
 78     }
 79 
 80     // ======================================
 81     // 核心规则:只缓存 市级(结尾000000)
 82     // 区县(422802000000) 一律 不缓存!
 83     // ======================================
 84     function isCityLevel(code) {
 85         return code && code.toString().endsWith('000000');
 86     }
 87 
 88     // 缓存工具
 89     function setLocalCache(key, data) { try { localStorage.setItem(key, JSON.stringify(data)); } catch (e) {} }
 90     function getLocalCache(key) { try { let d = localStorage.getItem(key); return d ? JSON.parse(d) : null; } catch (e) { return null; } }
 91 
 92     // 初始化省份
 93     async function init() {
 94         let local = getLocalCache('mca_provinces');
 95         if(local){
 96             memoryCache.provinces = local;
 97             populateSelect(selects.province, local);
 98             return;
 99         }
100         try{
101             let res = await fetch(`${API_URL}?maxLevel=1`);
102             let json = await res.json();
103             if(json.status === 200){
104                 memoryCache.provinces = json.data;
105                 setLocalCache('mca_provinces', json.data);
106                 populateSelect(selects.province, json.data);
107             }
108         }catch(e){
109             selects.province.innerHTML = '<option value="">加载失败</option>';
110         }
111     }
112 
113     function populateSelect(sel, data, tip='请选择'){
114         sel.innerHTML = `<option value="">${tip}</option>`;
115         let list = data.children || data;
116         if(Array.isArray(list)){
117             list.forEach(item=>{
118                 let opt = document.createElement('option');
119                 opt.value = item.code;
120                 opt.innerText = item.name;
121                 sel.appendChild(opt);
122             })
123         }
124     }
125 
126     // ======================================
127     // 核心加载方法:区县绝不缓存
128     // ======================================
129     async function loadData(code, sel, level){
130         if(!code) {resetSelect(sel);return null;}
131         let data = null;
132 
133         // 1. 只有市级才读缓存
134         if(isCityLevel(code)){
135             data = memoryCache.areas[code] || getLocalCache('mca_area_' + code);
136         }
137 
138         // 2. 无缓存 / 非市级 → 直接请求接口
139         if(!data){
140             try{
141                 let res = await fetch(`${API_URL}?code=${code}&maxLevel=${level}`);
142                 let json = await res.json();
143                 if(json.status === 200) data = json.data;
144             }catch(e){
145                 sel.innerHTML = '<option value="">请求失败</option>';
146                 return null;
147             }
148         }
149 
150         // 3. 只有市级才写入缓存
151         if(isCityLevel(code) && data){
152             memoryCache.areas[code] = data;
153             setLocalCache('mca_area_' + code, data);
154         }
155 
156         populateSelect(sel, data);
157         return data.children || [];
158     }
159 
160     function resetSelect(sel, msg='请选择'){
161         sel.innerHTML = `<option value="">${msg}</option>`;
162         sel.disabled = true;
163         sel.value = '';
164     }
165 
166     // 省份切换
167     selects.province.addEventListener('change',async function(){
168         resetAllShow();
169         let pCode = this.value;
170         let pName = this.selectedOptions[0]?.text||'';
171         resetSelect(selects.city); resetSelect(selects.district); resetSelect(selects.town);
172         resultDiv.style.display='none';
173         if(!pCode)return;
174 
175         if(zhiXiaShi.includes(pName)){
176             boxes.cityBox.classList.add('hide-item');
177             await loadData(pCode, selects.district, 3);
178             selects.district.disabled = false;
179             return;
180         }
181         await loadData(pCode, selects.city, 2);
182         selects.city.disabled = false;
183     })
184 
185     // 城市切换
186     selects.city.addEventListener('change',async function(){
187         let cCode = this.value;
188         let cName = this.selectedOptions[0]?.text||'';
189         resetSelect(selects.district); resetSelect(selects.town);
190         resultDiv.style.display='none';
191         if(!cCode)return;
192 
193         if([...wuSheQuShi,...zhiXiaXian].some(v=>cName.includes(v))){
194             boxes.districtBox.classList.add('hide-item');
195             await loadData(cCode, selects.town,4);
196             selects.town.disabled = false;
197             return;
198         }
199         await loadData(cCode, selects.district,3);
200         selects.district.disabled = false;
201     })
202 
203     // 区县切换 → 不缓存!
204     selects.district.addEventListener('change',async function(){
205         let dCode = this.value;
206         resetSelect(selects.town);
207         resultDiv.style.display='none';
208         if(!dCode)return;
209         await loadData(dCode, selects.town,4); // 区县,不缓存
210         selects.town.disabled = false;
211     })
212 
213     // 输出结果
214     selects.town.addEventListener('change',function(){
215         if(!this.value)return;
216         let provinceName = selects.province.selectedOptions[0]?.text||'';
217         let cityName = selects.city.selectedOptions[0]?.text||'';
218         let districtName = selects.district.selectedOptions[0]?.text||'';
219         let townName = this.selectedOptions[0]?.text||'';
220         let townCode = this.value||'';
221 
222         let nameArr = [];
223         nameArr.push(provinceName);
224         if(!boxes.cityBox.classList.contains('hide-item') && cityName) nameArr.push(cityName);
225         if(!boxes.districtBox.classList.contains('hide-item') && districtName) nameArr.push(districtName);
226         if(townName) nameArr.push(townName);
227         
228         let fullCode = townCode.replace(/000$/, '');
229 
230         resultDiv.innerHTML = `
231             ✅ 选中地址:${nameArr.join(' ')}<br>
232             🔖 完整编码:${fullCode}
233         `;
234         resultDiv.style.display = 'block';
235     })
236     
237     window.onload = init;
238 </script>
239 </body>
240 </html>

 

<!DOCTYPE html>
<html>
<head>
    <link rel="icon shortcut" href="/favicon.ico?v=1" type="image/x-icon">
    <meta name="viewport" content="width=device-width" />
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="keywords" content="四级行政地址联动">
    <meta name="description" content="四级行政地址联动">
    <title>民政部四级联动 层级自动隐藏版</title>
    <style>
        body { font-family: "Microsoft YaHei", sans-serif; padding: 20px; background: #f0f2f5; }
        .container { max-width: 520px; margin: 50px auto; background: #fff; padding: 30px; border-radius: 10px; box-shadow: 0 0 20px rgba(0,0,0,0.1); }
        h2 { text-align: center; color: #333; margin-bottom: 25px; }
        .form-group { margin-bottom: 15px; }
        /* 隐藏层级容器 */
        .hide-item { display: none !important; }
        label { display: block; margin-bottom: 6px; font-weight: bold; color: #555; font-size: 14px; }
        select { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 5px; font-size: 14px; box-sizing: border-box; transition: all 0.3s; }
        select:disabled { background-color: #f9f9f9; color: #aaa; cursor: not-allowed; border-color: #eee; }
        .result { margin-top: 25px; padding: 15px; background: #e8f5e8; border-radius: 5px; color: #2e7d32; display: none; font-weight: bold; text-align: center;}
    </style>
</head>
<body>
    <div class="container">
        <h2><span style="color: red;">📍 </span>民政部四级行政地址联动</h2>
        <div class="form-group" id="provinceBox">
            <label>省/市/直辖市</label>
            <select id="province"><option value="">加载中...</option></select>
        </div>

        <!-- 城市容器 可自动隐藏 -->
        <div class="form-group" id="cityBox">
            <label>地级市</label>
            <select id="city" disabled><option value="">请先选择省份</option></select>
        </div>

        <!-- 区县容器 可自动隐藏 -->
        <div class="form-group" id="districtBox">
            <label>区/县/市</label>
            <select id="district" disabled><option value="">请先选择城市</option></select>
        </div>

        <div class="form-group" id="townBox">
            <label>乡镇/街道</label>
            <select id="town" disabled><option value="">请先选择区县</option></select>
        </div>

        <div class="result" id="result"></div>
        <li>JSON数据来源: https://dmfw.mca.gov.cn/9095/xzqh/getList</li>
        <li>API文档: https://dmfw.mca.gov.cn/interface.html</li>
    </div>

    <script>
        const API_URL = 'https://dmfw.mca.gov.cn/9095/xzqh/getList';
        const memoryCache = { provinces: null, cities: {}, districts: {}, towns: {} };
        const selects = {
            province: document.getElementById('province'),
            city: document.getElementById('city'),
            district: document.getElementById('district'),
            town: document.getElementById('town')
        };
        const boxes = {
            provinceBox: document.getElementById('provinceBox'),
            cityBox: document.getElementById('cityBox'),
            districtBox: document.getElementById('districtBox'),
            townBox: document.getElementById('townBox')
        };
        const resultDiv = document.getElementById('result');

        // 行政区分类
        const zhiXiaShi = ['北京市','天津市','上海市','重庆市'];
        const wuSheQuShi = ['东莞市','中山市','儋州市','嘉峪关市','济源市','仙桃市','潜江市','天门市','神农架林区'];
        const zhiXiaXian = ['琼海市','文昌市','万宁市','东方市','五指山市','胡杨河市','石河子市','阿拉尔市'];

        // 重置所有显示
        function resetAllShow() {
            boxes.cityBox.classList.remove('hide-item');
            boxes.districtBox.classList.remove('hide-item');
        }

        function setLocalCache(key, data) {
            try { localStorage.setItem(key, JSON.stringify(data)); } catch (e) {}
        }
        function getLocalCache(key) {
            try {
                let d = localStorage.getItem(key);
                return d ? JSON.parse(d) : null;
            } catch (e) { return null; }
        }

        async function init() {
            let local = getLocalCache('mca_provinces');
            if(local){
                memoryCache.provinces = local;
                populateSelect(selects.province, local);
                return;
            }
            try{
                let res = await fetch(`${API_URL}?maxLevel=1`);
                let json = await res.json();
                if(json.status === 200){
                    memoryCache.provinces = json.data;
                    setLocalCache('mca_provinces', json.data);
                    populateSelect(selects.province, json.data);
                }
            }catch(e){
                selects.province.innerHTML = '<option value="">加载失败</option>';
            }
        }

        function populateSelect(sel, data, tip='请选择'){
            sel.innerHTML = `<option value="">${tip}</option>`;
            let list = data.children || data;
            if(Array.isArray(list)){
                list.forEach(item=>{
                    let opt = document.createElement('option');
                    opt.value = item.code.substring(0,6);
                    opt.innerText = item.name;
                    sel.appendChild(opt);
                })
            }
        }

        async function loadData(code, sel, level, cacheKey, localKey){
            if(!code) {resetSelect(sel);return null;}
            let data = null;
            if(memoryCache[cacheKey]?.[code]) data = memoryCache[cacheKey][code];
            else{
                let loc = getLocalCache(localKey+'_'+code);
                if(loc){
                    data = loc;
                    memoryCache[cacheKey] = memoryCache[cacheKey]||{};
                    memoryCache[cacheKey][code] = data;
                }else{
                    try{
                        let res = await fetch(`${API_URL}?code=${code}&maxLevel=${level}`);
                        let json = await res.json();
                        if(json.status===200){
                            data = json.data;
                            memoryCache[cacheKey] = memoryCache[cacheKey]||{};
                            setLocalCache(localKey+'_'+code, data);
                        }
                    }catch(e){
                        sel.innerHTML = '<option value="">请求失败</option>';
                        return null;
                    }
                }
            }
            populateSelect(sel, data);
            return data.children||[];
        }

        function resetSelect(sel, msg='请选择'){
            sel.innerHTML = `<option value="">${msg}</option>`;
            sel.disabled = true;
            sel.value = '';
        }

        // 省份切换
        selects.province.addEventListener('change',async function(){
            resetAllShow();
            let pCode = this.value;
            let pName = this.selectedOptions[0]?.text||'';
            resetSelect(selects.city);
            resetSelect(selects.district);
            resetSelect(selects.town);
            resultDiv.style.display='none';
            if(!pCode)return;

            // 直辖市:隐藏城市选择框,直接加载区县
            if(zhiXiaShi.includes(pName)){
                boxes.cityBox.classList.add('hide-item');
                let distList = await loadData(pCode, selects.district, 3, 'districts','mca_dist');
                if(distList.length) selects.district.disabled = false;
                return;
            }

            // 普通省份显示城市
            let cityList = await loadData(pCode, selects.city,2,'cities','mca_city');
            if(cityList.length) selects.city.disabled = false;
        })

        // 城市切换
        selects.city.addEventListener('change',async function(){
            let cCode = this.value;
            let cName = this.selectedOptions[0]?.text||'';
            resetSelect(selects.district);
            resetSelect(selects.town);
            resultDiv.style.display='none';
            if(!cCode)return;

            // 无区县城市:隐藏区县框,直接加载街道
            if([...wuSheQuShi,...zhiXiaXian].some(v=>cName.includes(v))){
                boxes.districtBox.classList.add('hide-item');
                let townList = await loadData(cCode, selects.town,4,'towns','mca_town');
                if(townList.length) selects.town.disabled = false;
                return;
            }

            // 正常显示区县
            boxes.districtBox.classList.remove('hide-item');
            let distList = await loadData(cCode, selects.district,3,'districts','mca_dist');
            if(distList.length) selects.district.disabled = false;
        })

        // 区县切换
        selects.district.addEventListener('change',async function(){
            let dCode = this.value;
            resetSelect(selects.town);
            resultDiv.style.display='none';
            if(!dCode)return;
            let townList = await loadData(dCode, selects.town,4,'towns','mca_town');
            //console.log("town: ", dCode);
            if(townList.length) selects.town.disabled = false;
        })

        // 地址拼接
        selects.town.addEventListener('change',function(){
            if(!this.value)return;
            let provinceName = selects.province.selectedOptions[0]?.text||'';
            let cityName = selects.city.selectedOptions[0]?.text||'';
            let districtName = selects.district.selectedOptions[0]?.text||'';
            let towName = this.selectedOptions[0]?.text||'';

            let arr = [];
            arr.push(provinceName);
            if(!boxes.cityBox.classList.contains('hide-item') && cityName) arr.push(cityName);
            if(!boxes.districtBox.classList.contains('hide-item') && districtName) arr.push(districtName);
            if(towName) arr.push(towName);

            resultDiv.innerText = '✅ 选中地址:' + arr.join(' ');
            //console.log("arr: ", towName);
            resultDiv.style.display = 'block';
        })
        
        window.onload = init;
    </script>
</body>
</html>
View Code

 

posted @ 2026-05-19 12:06  钢锅  阅读(31)  评论(0)    收藏  举报