数据格式如下:
{
河北: {
石家庄: ["长安区","桥东区","桥西区","新华区","井陉矿区","裕华区","井陉县","正定县","栾城县","行唐县","灵寿县","高邑县","深泽县","赞皇县","无极县","平山县","元氏县","赵县","辛集市","藁城市","晋州市","新乐市","鹿泉市","其他",],
...
},
...
}
组件JS代码:
export default class List extends EventTarget {
elem;
btn;
ul;
_list;
name;
data;
callback;
displayBool = false;
static prev;
constructor(_list, _name, _callback) {
super();
this._list = _list;
this.name = _name;
this.callback = _callback;
this.elem = this.createElem();
}
createElem() {
if (this.elem) return this.elem;
let div = document.createElement("div");
Object.assign(div.style, {
position: "relative",
float: "left",
paddingRight: "15px",
paddingLeft: "15px",
});
this.createBtn(div);
this.createUl(div);
this.btn.addEventListener("mouseover", (e) => this.mouseoverHandler(e));
this.ul.addEventListener("mouseover", (e) => this.mouseoverHandler(e));
this.btn.addEventListener("mouseout", (e) => this.mouseoutHandler(e));
this.ul.addEventListener("mouseout", (e) => this.mouseoutHandler(e));
this.btn.addEventListener("click", (e) => this.clickHandler(e));
this.ul.addEventListener("click", (e) => this.ulClickHandler(e));
document.addEventListener("click", (e) => this.clickHandler(e));
return div;
}
appendTo(parent) {
if (typeof parent === "string") parent = document.querySelector(parent);
parent.appendChild(this.elem);
}
createBtn(parent) {
this.btn = document.createElement("button");
Object.assign(this.btn.style, {
color: "#333",
backgroundColor: "#fff",
border: "1px solid #ccc",
borderRadius: "4px",
textAlign: "center",
cursor: "pointer",
padding: "6px 12px",
fontSize: "14px",
userSelect: "none",
});
this.btn.innerHTML = `
<span></span>
<span></span>
`;
Object.assign(this.btn.children[1].style, {
display: "inline-block",
width: 0,
height: 0,
verticalAlign: "middle",
borderTop: "4px dashed",
borderRight: "4px solid transparent",
borderLeft: "4px solid transparent",
});
parent.appendChild(this.btn);
}
createUl(parent) {
this.ul = document.createElement("ul");
Object.assign(this.ul.style, {
position: "absolute",
top: "100%",
left: 0,
zIndex: 1000,
display: this.displayBool ? "block" : "none",
float: "left",
minWidth: "160px",
padding: "5px 0",
margin: "2px 0 0",
fontSize: "14px",
textAlign: "left",
listStyle: "none",
border: "1px solid rgba(0, 0, 0, 0.15)",
borderRadius: "4px",
boxShadow: "0 6px 12px rgba(0, 0, 0, 0.175)",
});
this.list = this._list;
parent.appendChild(this.ul);
}
set list(_list) {
this.data = _list[0];
this.btn.firstElementChild.textContent = this.data;
var str = "";
_list.forEach((item) => {
str += `<li><a>${item}</a></li>`;
});
this.ul.innerHTML = str;
Array.from(this.ul.children).forEach((item) => {
Object.assign(item.children[0].style, {
display: "block",
padding: "3px 20px",
clear: "both",
color: "#333333",
textDecoration: "none",
cursor: "pointer",
});
});
}
get list() {
return this._list;
}
mouseoverHandler(e) {
if (e.currentTarget === this.btn) {
Object.assign(e.currentTarget.style, {
backgroundColor: "#e6e6e6",
borderColor: "#adadad",
});
} else if (e.target.constructor === HTMLAnchorElement) {
Object.assign(e.target.style, {
backgroundColor: "#e6e6e6",
});
}
}
mouseoutHandler(e) {
var target = e.currentTarget === this.btn ? e.currentTarget : e.target;
target.style.backgroundColor = "#fff";
target.style.borderColor = "#ccc";
}
clickHandler(e) {
if (e.currentTarget === this.btn) {
e.stopPropagation();
if (List.prev) {
List.prev.displayBool = false;
List.prev.elem.lastElementChild.style.display = "none";
}
List.prev = this;
List.prev.displayBool = !List.prev.displayBool;
} else if (e.currentTarget === document) this.displayBool = false;
this.ul.style.display = this.displayBool ? "block" : "none";
}
ulClickHandler(e) {
if (e.target.constructor !== HTMLAnchorElement) return;
this.data = e.target.textContent;
this.btn.firstElementChild.textContent = this.data;
if (this.callback) this.callback(this.name);
}
}
HTML代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>省市县三级级联式菜单</title>
</head>
<body>
<script type="module">
import List from "./List.js";
var province, city, county;
function ajax(type, data) {
if (data === undefined) data = "";
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", loadHandler);
xhr.open("GET", "http://10.9.72.238:4001/" + type + "/?" + data);
xhr.send();
}
function loadHandler(e) {
var xhr = e.currentTarget;
xhr.removeEventListener("load", loadHandler);
var type = xhr.responseURL.trim().split("?")[0];
if (type.slice(-1) === "/") type = type.slice(0, -1);
type = type.split("/").pop();
var res = JSON.parse(xhr.response);
switch (type) {
case "init":
province = new List(res.provinceList, "province", clickItem);
city = new List(res.cities, "city", clickItem);
county = new List(res.counties);
province.appendTo("body");
city.appendTo("body");
county.appendTo("body");
break;
case "province":
city.list = res.cities;
case "city":
county.list = res.counties;
break;
}
}
ajax("init");
function clickItem(name) {
if (name === "province") {
ajax("province", "provinceName=" + province.data);
} else if (name === "city") {
ajax(
"city",
"provinceName=" + province.data + "&cityName=" + city.data
);
}
}
</script>
</body>
</html>
NodeJs代码:
var http = require("http");
var querystring = require("querystring");
var server = http.createServer(function (req, res) {
var data = "";
res.writeHead(200, {
"content-type": "text/html;charset=utf-8",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "*",
});
req.on("data", function (_data) {
data += _data;
});
req.on("end", function () {
var type = req.url.trim().split("?")[0].replace(/\//g, "");
if (req.method.toLowerCase() === "get") {
if (req.url.includes("favicon.ico")) return res.end();
data = req.url.includes("?") ? req.url.split("?")[1] : "";
}
try {
data = JSON.parse(data);
} catch (e) {
data = data ? querystring.parse(data) : {};
}
var o = {};
switch (type) {
case "init":
var provinceList = Object.keys(dataList);
o.provinceList = provinceList;
var cities = Object.keys(dataList[provinceList[0]]);
o.cities = cities;
o.counties = dataList[provinceList[0]][cities[0]];
break;
case "province":
var provinceName = data.provinceName;
var cities = Object.keys(dataList[provinceName]);
o.cities = cities;
o.counties = dataList[provinceName][cities[0]];
break;
case "city":
var provinceName = data.provinceName;
var cityName = data.cityName;
o.counties = dataList[provinceName][cityName];
break;
}
res.write(JSON.stringify(o));
res.end();
});
});
server.listen(4001, "10.9.72.238", function () {
console.log("服务启动成功");
});