想法:每一個下拉式選單作為一個元件,可以接收一組數據,根據數據內容不同產生不同的選單選項。三級之間的關聯是透過事件拋發來實現。數據從後台獲取。
當點擊省份選單選擇陝西時,菜單組件會透過事件拋發把當前的省份拋發出來。得知省份之後就可以從後台取得省份下面的城市資料。依序類推。
實現效果:
## URL:http://10.9.72.245:4010
## Method: "GET"
## 資料格式:
請求:QueryString
回應:JSON
1、http: //10.9.72.245:4010/getProvince
2、http://10.9.72.245:4010/getCity
3、http://10.9.72.245:4010/getCounty
介面名稱:/getProvince
請求:無參數
回應:{ "province":["北京","天津","河北",...]}
介面名稱:/getCity
請求:?province="河北"
回應:{"city":["石家莊" , "唐山", "秦皇島",...]}
介面名稱:/getCounty
請求:?city="石家莊"
回應:{"county":["長安區", "橋東區", "橋西區",...]}
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script type="module"> import QueryString from './js/QueryString.js'; import DropDownMemu from './js/DropDownMemu.js'; let cityInfo = {}; init(); function init(){ ajax("http://10.9.72.245:4010","getProvince").then(succeseFunction).catch(failFunction); } // ajax通訊成功後執行: function succeseFunction(_data){ let data = JSON.parse(_data); let key = Object.keys(data)[0]; data = Object.values(data)[0]; if(DropDownMemu.Obj[key]){ DropDownMemu.Obj[key].list = data; DropDownMemu.Obj[key].name = data[0]; }else{ let memu = new DropDownMemu(key); memu.addEventListener("change",changeHandler); memu.list = data; memu.name =data[0]; memu.appendTo("body"); cityInfo[key] = data[0]; } } // 當選單顯示內容改變時接收到選單拋出的事件並取得事件中所攜帶的資訊例如{"province":"陝西"}或{"city":"西安"} function changeHandler(e){ let key = e.currentTarget.label; cityInfo[key] = e.data[key]; let interfaceName; if(e.data.province){ interfaceName = "getCity"; }else if(e.data.city){ interfaceName = "getCounty"; }else{ return } ajax("http://10.9.72.245:4010",interfaceName,cityInfo).then(succeseFunction).catch(failFunction); } /* ajax通訊: 參數列表: url: 後台服務位址interfaceType:介面類型,如"getProvince" data:傳送的資料,例如:{"province":"陝西"} 通訊類型type:預設"GET"請求是否以json格式傳送資料:預設為false */ function ajax(url,interfaceType,data,type="get",json=false){ type = type.toUpperCase(); let o = type==="GET"? null : data; if(data) data = json? JSON.stringify(data) : QueryString.stringify(data); else data = ""; return new Promise(function(resolve,reject){ let xhr = new XMLHttpRequest(); xhr.open(type,url + "/" + interfaceType + (type==="GET"? "?"+data : "")); xhr.send(o); xhr.onreadystatechange = function(){ if(xhr.readyState===4 && xhr.status===200){ resolve(xhr.response); }else if(xhr.readyState===4){ resolve(xhr.status); } } xhr.onerror= function(){ reject(xhr.response); } }) } // ajax通訊失敗時執行function failFunction(_err){ console.log(_err); } </script> </body> </html>
import Component from "./Component.js"; export default class DropDownMemu extends Component { _list; // 目前下拉式選單的可選項。 _name; // 目前選擇顯示的名字例如: "北京" label; // 目前下拉式選單的標籤,province city county spanLabel; // 標籤容器spanCaret; // 三角形ul; // 下拉選項容器bool=false; // 控制滑鼠事件,聚焦狀態或正在選擇時,不觸發滑鼠劃入滑出效果。 // 根據不同的狀態設定下拉式選單的樣式。 static DROPDOWN = Symbol(); static DEFAULT = Symbol(); // 靜態全域變數每建立一個下拉式選單,都儲存到這個物件中,全域管理所建立的每一個下拉式選單。 static Obj = {}; constructor(_label) { super("p"); this.label = _label; // 建立HTML結構this.render(); // 設定樣式this.setStyle(); // 滑鼠滑入滑出點擊,聚焦失焦,點擊事件this.elem.addEventListener("focusin", e =>this.mouseHandler(e)); this.elem.addEventListener("focusout", e =>this.mouseHandler(e)); this.elem.addEventListener("mouseenter", e=>this.mouseHandler(e)); this.elem.addEventListener("mouseleave", e=>this.mouseHandler(e)); this.elem.addEventListener("click", e => this.mouseHandler(e)); } mouseHandler(e){ switch(e.type){ case "mouseenter": if(this.bool) return this.elem.style.backgroundColor = "#e6e6e6"; break; case "mouseleave": if(this.bool) return this.elem.style.backgroundColor = "#fff"; break; case "focusin": this.setState(DropDownMemu.DROPDOWN); this.bool = true; break; case "focusout": this.setState(DropDownMemu.DEFAULT); this.bool = false; case "click" : if(e.target.constructor !== HTMLLIElement) return this._name = e.target.textContent; // 當點擊時修改目前顯示的內容,重設樣式,並拋發事件告知外部目前的內容。 this.setContent(); let evt = new FocusEvent("focusout"); this.elem.dispatchEvent(evt); } } set name(_name){ this._name = _name; this.setContent(); } get name(){ return this._name; } set list(_list){ this._list = _list; this.ul.innerHTML = ""; this.ul.appendChild(this.createLi()); } // 修改選單目前顯示的內容並並拋發資料setContent(_name){ this._name = _name || this._name; this.spanLabel.textContent = this._name; let evt = new MouseEvent("change"); if(!evt.data) evt.data = {} evt.data[this.label] = this._name; this.dispatchEvent(evt); } // 根據指定的list建立下拉式選單選項。 createLi(_list){ this._list = _list || this._list; let elem = document.createDocumentFragment(); this._list.forEach((item, index) => { let li = document.createElement("li"); li.textContent = item; Object.assign(li.style, { lineHeight:"26px", padding:"0 15px", }) elem.appendChild(li); }) return elem; } setState(type){ switch(type){ case DropDownMemu.DROPDOWN: this.elem.style.backgroundColor = "#e6e6e6"; this.ul.style.display = "block"; break; case DropDownMemu.DEFAULT: this.elem.style.backgroundColor = "#fff"; this.ul.style.display = "none"; break; } } appendTo(parent){ super.appendTo(parent); DropDownMemu.Obj[this.label] = this; } render() { this.elem.setAttribute("tabIndex",1); this.spanLabel = document.createElement("span"); this.spanCaret = document.createElement("span"); this.ul = document.createElement("ul"); this.elem.appendChild(this.ul); this.spanLabel.textContent = this._name; this.elem.appendChild(this.spanLabel); this.elem.appendChild(this.spanCaret); } setStyle() { Object.assign(this.elem.style, { float: "left", minHeight: "20px", minWidht: "80px", color: "#333", fontWeight: "normal", textAlign: "center", whiteSpace: "nowrap", verticalAlign: "middle", cursor: "pointer", border: "1px solid #ccc", borderRadius: "4px", backgroundColor: "#fff", padding: "6px 12px", fontSize: "14px", userSelect: "none", marginRight: "100px", position:"relative", }); Object.assign(this.spanLabel.style, { float: "left", padding: "0 5px" }) Object.assign(this.spanCaret.style, { display: "inline-block", verticalAlign: "middle", borderTop: "4px dashed", borderRight: "4px solid transparent", borderLeft: "4px solid transparent", }) Object.assign(this.ul.style, { listStyle: "none", position: "absolute", top: "100%", left: "0", zIndex: "1000", minWidth: "100px", padding: "5px 0px", margin: "2px 0 0", fontSize: "14px", textAlign: "left", backgroundColor: "#fff", border: "1px solid rgba(0, 0, 0, 0.15)", borderRadius: "4px", boxShadow: "0 6px 12px rgba(0, 0, 0, 0.175)", display: "none", }) } }
export default class Component extends EventTarget{ elem; constructor(_type){ super(); this.elem = this.createElem(_type); } createElem(_type){ let elem = document.createElement(_type); return elem; } appendTo(parent){ if(typeof parent==="string") parent = document.querySelector(parent); parent.appendChild(this.elem); } }
let http = require("http"); let querystring = require("querystring"); let data, req, res; // 讀取所有城市資料並解析為對象,同步讀取。 let fs = require("fs"); let allCityInfo = JSON.parse(fs.readFileSync('./city.json')); let server = http.createServer(listenerHandler); server.listen(4010,"10.9.72.245",listenerDoneHandler); function listenerHandler(_req,_res){ req = _req; res = _res; res.writeHead(200,{ "content-type":"text/html;charset=utf-8", "Access-Control-Allow-Origin":"*", "Access-Control-Allow-Headers":"*", }); data=""; req.on("data",function(_data){ data=_data; }) req.on("end",receiveHandler); } function receiveHandler(){ // console.log(allCityInfo); // 根據請求頭的url解析介面類型let type = req.url.trim().split("?")[0].replace(///g,""); console.log(type); // 根據請求頭的url解析傳入的參數if(req.method.toUpperCase()==="GET"){ if(req.url.includes("favicon.ico")) return res.end(); else data = req.url.includes("?") ? req.url.split("?")[1] : ""; } try{ data = JSON.parse(data); }catch{ data = querystring.parse(data); } console.log(data); // 根據介面類型尋找資料。 let list = {}; switch(type){ case "getProvince": list.province = Object.keys(allCityInfo); break; case "getCity" : list.city = Object.keys(allCityInfo[data.province]); break; case "getCounty": list.county = allCityInfo[data.province][data.city]; break; } console.log(list); res.write(JSON.stringify(list)); res.end() } function listenerDoneHandler(){ console.log("開啟服務成功"); }
{
"北京": {
"北京": ["東城區", "西城區", "崇文區", "宣武區", "朝陽區", "豐台區", "石景山區", "海淀區", "門頭溝區", "房山區", "通州區", "順義區", "昌平區", "大興區", "平谷區", "懷柔區", "密雲縣", "延慶縣", "其他"]
} ,
"天津": {
"天津": ["和平區", "河東區", "河西區", "南開區", "河北區", "紅撟區", "濱海新區", "東麗區", "西青區", "津南區", "北辰區", "寧河區", "武清區", "靜海縣", "寶坻區", "薊縣", "塘沽區", "漢沽區", "大港區", "寶坻區", "其他"]
},
}
以上就是一文詳解JS實現三級聯動菜單(附思路說明)的詳細內容,更多請關注php中文網其它相關文章!