目录
- 一、介绍
- 二、准备
- 三、目标
- 四、代码
- 五、完成
一、介绍
网购大家应该再熟悉不过,网购中有个很难让人忽略的功能就是地址管理,接下来就让我们通过完善代码来探索下地址管理中常用功能的实现吧~
本题需要在已提供的基础项目中使用 JS 知识完善代码,最终实现需求中的具体功能。
二、准备
开始答题前,需要先打开本题的项目代码文件夹,目录结构如下:
├── effect.gif
├── index.html
├── css
├── images
└── js
├── data.js
└── index.js
其中:
effect.gif 是最终实现的效果图。
index.html 是主页面。
css 是样式文件夹。
images 是图片文件夹。
js/data.js 是省市区列表数据。
js/index.js 是需要补充代码的 js 文件。
在浏览器中预览 index.html 页面,显示如下所示:
三、目标
请在 js/index.js 文件中补全代码,最终实现以下需求:
- 实现省市二级联动功能。
- 页面加载后省份下拉列表数据正常渲染。
- 在省份列表中选取某个数据后,对应的市区数据会渲染在其右侧的市区列表中。效果如下:
- 实现对提交的表单信息的验证功能。
- 填写表单信息,其中地址、联系人和手机号为必填项,有一项为空则点击保存按钮会弹出提示窗,点击提示窗周围的半透明蒙层后,该窗口会关闭。效果如下:
- 实现选择标签显示激活样式功能。
- 点击标签列表中的某个标签(例如:公司),该标签显示激活样式(即 .active**),其他未选择标签显示默认样式**。效果如下:
- 点击标签列表中的某个标签(例如:公司),该标签显示激活样式(即 .active**),其他未选择标签显示默认样式**。效果如下:
- 实现新增地址被正确渲染功能。
- 点击保存按钮,表单数据将以列表的形式显示在原有数据的上方,即整个地址列表的首位。效果如下:
- 点击保存按钮,表单数据将以列表的形式显示在原有数据的上方,即整个地址列表的首位。效果如下:
- 表单数据在地址列表中显示时,对应的标签有其不同的样式,具体如下:
- 家:.home。
- 公司:.company。
- 学校:.school。
完成后的效果见文件夹下面的 gif 图,图片名称为 effect.gif(提示:可以通过 VS Code 或者浏览器预览 gif 图片)。
规定
四、代码
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>新增地址</title>
<link rel="stylesheet" type="text/css" href="./css/index.css" />
</head>
<body>
<div id="app">
<!-- 带返回按钮的头部 -->
<div class="header">
<img class="back-btn" src="images/arrow.png" onclick="back()" />
<span id="main_title">新建收货地址</span>
<span class="blank"></span>
</div>
<!-- 地址、标签编辑区 -->
<ul class="address">
<li>
<i></i>
<span class="left">省市</span>
<div class="right">
<select
class="province"
name="province"
id="param_province"
onchange="provincechange()"
>
<option>请选择省份</option>
</select>
<select class="city" name="city" id="param_city">
<option>请选择城市</option>
</select>
</div>
</li>
<li>
<i>*</i>
<span class="left">地址</span>
<input
type="text"
placeholder="填写详细地址,例:XX 小区 1 幢 101"
id="param_address"
/>
</li>
<li class="mark">
<i></i>
<span class="left">标签</span>
<a class="active">家</a>
<a>公司</a>
<a>学校</a>
<input type="hidden" id="param_mark" value="0" />
</li>
</ul>
<!-- 联系人信息编辑及表单提交区 -->
<ul class="user-info">
<li>
<i>*</i>
<span class="left">联系人</span>
<input type="text" placeholder="收货人姓名" id="param_name" />
</li>
<li>
<i>*</i>
<span class="left">手机号</span>
<input type="text" placeholder="收货人手机号码" id="param_phone" />
</li>
<li>
<a class="save-btn" onclick="saveInfo()">保存</a>
</li>
</ul>
<!-- 收获地址列表展示区 -->
<ul class="address-list">
<li>
<div class="show-area">
<label class="school">学校</label>
<span>浙江省杭州市</span>
</div>
<div class="show-address">
<span>仓前街道梦想小镇天使村</span>
<a><img src="./images/edit.png" /></a>
</div>
<div class="show-info">
<span>张三</span>
<span>18912345678</span>
</div>
</li>
</ul>
<!-- 提示弹窗 -->
<div class="warning-dialog" onclick="this.style.display='none';">
<div class="warning-msg">省市、地址以及联系人和手机号不能为空!</div>
</div>
</div>
<script type="text/javascript" src="./js/data.js"></script>
<script type="text/javascript" src="./js/index.js"></script>
</body>
</html>
js/data.js
var provinces = [
"请选择省份",
"北京市",
"上海市",
"天津市",
"重庆市",
"河北省",
"山西省",
"内蒙古省",
"辽宁省",
"吉林省",
"黑龙江省",
"江苏省",
"浙江省",
"安徽省",
"福建省",
"江西省",
"山东省",
"河南省",
"湖北省",
"湖南省",
"广东省",
"广西省",
"海南省",
"四川省",
"贵州省",
"云南省",
"西藏省",
"陕西省",
"甘肃省",
"宁夏省",
"青海省",
"新疆省",
"香港",
"澳门",
"台湾省",
];
var citys = [
["请选择城市"],
[
"东城区",
"西城区",
"崇文区",
"宣武区",
"朝阳区",
"丰台区",
"石景山区",
"海淀区",
"门头沟区",
"房山区",
"通州区",
"顺义区",
"昌平区",
"大兴区",
"怀柔区",
"平谷区",
"密云县",
"延庆县",
],
[
"黄浦区",
"卢湾区",
"徐汇区",
"长宁区",
"静安区",
"普陀区",
"虹口区",
"杨浦区",
"闵行区",
"宝山区",
"嘉定区",
"浦东新区",
"金山区",
"松江区",
"青浦区",
"南汇区",
"奉贤区",
"崇明县",
],
[
"和平区",
"河东区",
"河西区",
"南开区",
"河北区",
"红桥区",
"塘沽区",
"汉沽区",
"大港区",
"东丽区",
"西青区",
"津南区",
"北辰区",
"武清区",
"宝坻区",
"宁河县",
"静海县",
"蓟县",
],
[
"万州区",
"涪陵区",
"渝中区",
"大渡口区",
"江北区",
"沙坪坝区",
"九龙坡区",
"南岸区",
"北碚区",
"万盛区",
"双桥区",
"渝北区",
"巴南区",
"黔江区",
"长寿区",
"綦江县",
"潼南县",
"铜梁县",
"大足县",
"荣昌县",
"璧山县",
"梁平县",
"城口县",
"丰都县",
"垫江县",
"武隆县",
"忠县",
"开县",
"云阳县",
"奉节县",
"巫山县",
"巫溪县",
"石柱土家族自治县",
"秀山土家族苗族自治县",
"酉阳土家族苗族自治县",
"彭水苗族土家族自治县",
"江津市",
"合川市",
"永川市",
"南川市",
],
[
"石家庄市",
"张家口市",
"承德市",
"秦皇岛市",
"唐山市",
"廊坊市",
"保定市",
"衡水市",
"沧州市",
"邢台市",
"邯郸市",
],
[
"太原市",
"朔州市",
"大同市",
"阳泉市",
"长治市",
"晋城市",
"忻州市",
"晋中市",
"临汾市",
"吕梁市",
"运城市",
],
[
"呼和浩特市",
"包头市",
"乌海市",
"赤峰市",
"通辽市",
"呼伦贝尔市",
"鄂尔多斯市",
"乌兰察布市",
"巴彦淖尔市",
"兴安盟",
"锡林郭勒盟",
"阿拉善盟",
],
[
"沈阳市",
"朝阳市",
"阜新市",
"铁岭市",
"抚顺市",
"本溪市",
"辽阳市",
"鞍山市",
"丹东市",
"大连市",
"营口市",
"盘锦市",
"锦州市",
"葫芦岛市",
],
[
"长春市",
"白城市",
"松原市",
"吉林市",
"四平市",
"辽源市",
"通化市",
"白山市",
"延边州",
],
[
"哈尔滨市",
"齐齐哈尔市",
"七台河市",
"黑河市",
"大庆市",
"鹤岗市",
"伊春市",
"佳木斯市",
"双鸭山市",
"鸡西市",
"牡丹江市",
"绥化市",
"大兴安岭地区",
],
[
"南京市",
"徐州市",
"连云港市",
"宿迁市",
"淮安市",
"盐城市",
"扬州市",
"泰州市",
"南通市",
"镇江市",
"常州市",
"无锡市",
"苏州市",
],
[
"杭州市",
"湖州市",
"嘉兴市",
"舟山市",
"宁波市",
"绍兴市",
"衢州市",
"金华市",
"台州市",
"温州市",
"丽水市",
],
[
"合肥市",
"宿州市",
"淮北市",
"亳州市",
"阜阳市",
"蚌埠市",
"淮南市",
"滁州市",
"马鞍山市",
"芜湖市",
"铜陵市",
"安庆市",
"黄山市",
"六安市",
"巢湖市",
"池州市",
"宣城市",
],
[
"福州市",
"南平市",
"莆田市",
"三明市",
"泉州市",
"厦门市",
"漳州市",
"龙岩市",
"宁德市",
],
[
"南昌市",
"九江市",
"景德镇市",
"鹰潭市",
"新余市",
"萍乡市",
"赣州市",
"上饶市",
"抚州市",
"宜春市",
"吉安市",
],
[
"济南市",
"青岛市",
"聊城市",
"德州市",
"东营市",
"淄博市",
"潍坊市",
"烟台市",
"威海市",
"日照市",
"临沂市",
"枣庄市",
"济宁市",
"泰安市",
"莱芜市",
"滨州市",
"菏泽市",
],
[
"郑州市",
"开封市",
"三门峡市",
"洛阳市",
"焦作市",
"新乡市",
"鹤壁市",
"安阳市",
"濮阳市",
"商丘市",
"许昌市",
"漯河市",
"平顶山市",
"南阳市",
"信阳市",
"周口市",
"驻马店市",
"济源市",
],
[
"武汉市",
"十堰市",
"襄樊市",
"荆门市",
"孝感市",
"黄冈市",
"鄂州市",
"黄石市",
"咸宁市",
"荆州市",
"宜昌市",
"随州市",
"省直辖县级行政单位",
"恩施州",
],
[
"长沙市",
"张家界市",
"常德市",
"益阳市",
"岳阳市",
"株洲市",
"湘潭市",
"衡阳市",
"郴州市",
"永州市",
"邵阳市",
"怀化市",
"娄底市",
"湘西州",
],
[
"广州市",
"深圳市",
"清远市",
"韶关市",
"河源市",
"梅州市",
"潮州市",
"汕头市",
"揭阳市",
"汕尾市",
"惠州市",
"东莞市",
"珠海市",
"中山市",
"江门市",
"佛山市",
"肇庆市",
"云浮市",
"阳江市",
"茂名市",
"湛江市",
],
[
"南宁市",
"桂林市",
"柳州市",
"梧州市",
"贵港市",
"玉林市",
"钦州市",
"北海市",
"防城港市",
"崇左市",
"百色市",
"河池市",
"来宾市",
"贺州市",
],
["海口市", "三亚市", "省直辖县级行政单位"],
[
"成都市",
"广元市",
"绵阳市",
"德阳市",
"南充市",
"广安市",
"遂宁市",
"内江市",
"乐山市",
"自贡市",
"泸州市",
"宜宾市",
"攀枝花市",
"巴中市",
"达州市",
"资阳市",
"眉山市",
"雅安市",
"阿坝州",
"甘孜州",
"凉山州",
],
[
"贵阳市",
"六盘水市",
"遵义市",
"安顺市",
"毕节地区",
"铜仁地区",
"黔东南州",
"黔南州",
"黔西南州",
],
[
"昆明市",
"曲靖市",
"玉溪市",
"保山市",
"昭通市",
"丽江市",
"思茅市",
"临沧市",
"德宏州",
"怒江州",
"迪庆州",
"大理州",
"楚雄州",
"红河州",
"文山州",
"西双版纳州",
],
[
"拉萨市",
"那曲地区",
"昌都地区",
"林芝地区",
"山南地区",
"日喀则地区",
"阿里地区",
],
[
"西安市",
"延安市",
"铜川市",
"渭南市",
"咸阳市",
"宝鸡市",
"汉中市",
"榆林市",
"安康市",
"商洛市",
],
[
"兰州市",
"嘉峪关市",
"白银市",
"天水市",
"武威市",
"酒泉市",
"张掖市",
"庆阳市",
"平凉市",
"定西市",
"陇南市",
"临夏州",
"甘南州",
],
[
"西宁市",
"海东地区",
"海北州",
"海南州",
"黄南州",
"果洛州",
"玉树州",
"海西州",
],
["银川市", "石嘴山市", "吴忠市", "固原市", "中卫市"],
[
"乌鲁木齐市",
"克拉玛依市",
"自治区直辖县级行政单位",
"喀什地区",
"阿克苏地区",
"和田地区",
"吐鲁番地区",
"哈密地区",
"克孜勒苏柯州",
"博尔塔拉州",
"昌吉州",
"巴音郭楞州",
"伊犁州",
"塔城地区",
"阿勒泰地区",
],
["香港"],
["澳门"],
[
"台北市",
"高雄市",
"台中市",
"花莲市",
"基隆市",
"嘉义市",
"金门市",
"连江市",
"苗栗市",
"南投市",
"澎湖市",
"屏东市",
"台东市",
"台南市",
"桃园市",
"新竹市",
"宜兰市",
"云林市",
"彰化市",
],
];
js/index.js
// 初始化省份下拉列表内容
function provinceInit() {
var province = document.getElementById("param_province");
province.length = provinces.length;
for (var i = 0; i < provinces.length; i++) {
province.options[i].text = provinces[i];
province.options[i].value = provinces[i];
}
}
// 选择省份后对应城市下拉列表内容渲染
function provincechange() {
// TODO:请补充代码实现功能
}
/**
* 为标签绑定单击事件。
* 事件效果为:
* 1、鼠标点击该标签后该标签样式显示 class=active;
* 2、其他已选标签的 active 样式被移除;
* 3、将选中的标签对应下标(即选择器为 “mark a” 选中的标签对应的下标)更新到 id=param_mark 的隐藏的 input 中。
*/
function addClick() {
// TODO:请补充代码实现功能
}
// 提交信息后,读取并显示在页面中
function saveInfo() {
// TODO:请补充代码实现功能
}
// 切换新增地址和地址管理的显隐
function back() {
if (document.getElementById("main_title").innerHTML == "地址管理") {
document.getElementById("main_title").innerHTML = "新增地址";
document.querySelector(".address-list").style.display = "none";
document.querySelector(".address").style.display = "block";
document.querySelector(".user-info").style.display = "block";
}
}
// 页面加载后的初始化操作
function init() {
// 初始化省份下拉列表内容
provinceInit();
// 为标签绑定单击事件
addClick();
}
window.onload = function () {
// 初始化
init();
};
css/index.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background-color: #000000;
color: #333333;
}
a {
cursor: pointer;
}
ul {
list-style: none;
}
#app {
width: 414px;
margin: 50px auto;
background: #f5f5f5;
height: 700px;
overflow: hidden;
font-size: 14px;
position: relative;
}
.header {
height: 50px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 15px;
background: white;
}
.address {
background: white;
width: 88%;
border-radius: 8px;
margin: 20px auto;
margin-bottom: 10px;
padding: 8px 18px;
}
.address > li,
.user-info > li {
height: 44px;
display: flex;
align-items: center;
margin-bottom: 10px;
}
li .left {
width: 55px;
}
.address select {
margin-right: 10px;
border: none;
}
.address input,
.user-info input {
padding: 5px;
border: none;
border-bottom: 1px solid #eae6e6;
width: 240px;
height: 36px;
}
.mark > a {
height: 30px;
width: 50px;
line-height: 30px;
text-align: center;
display: inline-block;
border: 1px solid #eae6e6;
margin-right: 10px;
border-radius: 8px;
}
.active {
border: #03a9f4 solid 1px !important;
}
.user-info {
background: white;
width: 88%;
height: 500px;
border-radius: 8px;
margin: 0 auto;
padding: 18px;
}
.save-btn {
display: inline-block;
width: 300px;
height: 40px;
line-height: 40px;
text-align: center;
color: white;
background-color: #03a9f4;
border-radius: 20px;
margin: 0 auto;
margin-top: 50px;
}
.back-btn {
width: 24px;
}
.blank {
width: 24px;
display: inline-block;
height: 100%;
}
.address-list {
background: white;
width: 88%;
border-radius: 8px;
margin: 20px auto;
margin-bottom: 10px;
padding: 18px;
display: none;
}
.address-list > li {
padding-bottom: 8px;
border-bottom: 1px solid #eae6e6;
margin: 18px 0;
}
.show-area {
color: #8a8787;
font-size: 12px;
}
.show-area label {
padding: 1px 5px;
border-radius: 5px;
color: white;
}
.home {
background-color: red;
}
.company {
background-color: #03a9f4;
}
.school {
background-color: orange;
}
.show-address {
display: flex;
align-items: center;
justify-content: space-between;
}
.show-address img {
width: 20px;
}
.show-info {
color: #8a8787;
font-size: 12px;
}
.warning-dialog {
position: absolute;
z-index: 999;
background: rgba(0, 0, 0, 0.5);
top: 0;
right: 0;
left: 0;
bottom: 0;
display: none;
}
.warning-msg {
background-color: white;
width: 80%;
margin: 30% auto;
padding: 30px 10px;
border-radius: 8px;
text-align: center;
}
li i {
color: red;
width: 15px;
height: 100%;
display: flex;
align-items: center;
font-style: normal;
}
images/arrow.png
images/edit.png
五、完成
js/index.js
// 初始化省份下拉列表内容
function provinceInit() {
var province = document.getElementById("param_province");
province.length = provinces.length;
for (var i = 0; i < provinces.length; i++) {
province.options[i].text = provinces[i];
province.options[i].value = provinces[i];
}
}
// 选择省份后对应城市下拉列表内容渲染
function provincechange() {
// TODO:请补充代码实现功能
var province =
document.getElementById("param_province").selectedOptions[0].value;
var index = provinces.findIndex((item) => item == province);
var city = document.getElementById("param_city");
city.length = citys[index].length;
for (var i = 0; i < citys[index].length; i++) {
city.options[i].text = citys[index][i];
city.options[i].value = citys[index][i];
}
}
/**
* 为标签绑定单击事件。
* 事件效果为:
* 1、鼠标点击该标签后该标签样式显示 class=active;
* 2、其他已选标签的 active 样式被移除;
* 3、将选中的标签对应下标(即选择器为 “mark a” 选中的标签对应的下标)更新到 id=param_mark 的隐藏的 input 中。
*/
function addClick(e) {
// TODO:请补充代码实现功能
const mark = document.getElementsByClassName("mark")[0];
const lis = document.querySelectorAll(".mark a");
mark.addEventListener("click", function (e) {
if (e.target.nodeName.toLowerCase() == "a") {
for (var i = 0; i < lis.length; i++) {
lis[i].classList.remove("active");
}
e.target.classList.add("active");
}
});
}
// 提交信息后,读取并显示在页面中
function saveInfo() {
// TODO:请补充代码实现功能
//蒙层
const dialog = document.getElementsByClassName("warning-dialog")[0];
const address = document.getElementById("param_address");
const name = document.getElementById("param_name");
const phone = document.getElementById("param_phone");
if (!(address.value && name.value && phone.value)) {
dialog.style.display = "block";
} else {
//获取地址列表
const address_list = document.getElementsByClassName("address-list")[0];
//获取省
const province = document.getElementById("param_province").value;
//获取市
const city = document.getElementById("param_city").value;
//获取标签
const marks = document.querySelector(".mark .active").innerHTML;
let tag=''
switch (marks) {
case "家":
tag = "home";
break;
case "学校":
tag = "school";
break;
case "公司":
tag = "company";
break;
}
const temp = `
<div class="show-area">
<label class=${tag}>${marks}</label>
<span>${province + city}</span>
</div>
<div class="show-address">
<span>${address.value}</span>
<a><img src="./images/edit.png" /></a>
</div>
<div class="show-info">
<span>${name.value}</span>
<span>${phone.value}</span>
</div>
`;
const li = document.createElement("li");
li.innerHTML = temp;
address_list.insertBefore(li, address_list.firstElementChild);
back();
}
}
// 切换新增地址和地址管理的显隐
function back() {
if (document.getElementById("main_title").innerHTML == "地址管理") {
document.getElementById("main_title").innerHTML = "新增地址";
document.querySelector(".address-list").style.display = "none";
document.querySelector(".address").style.display = "block";
document.querySelector(".user-info").style.display = "block";
} else {
document.getElementById("main_title").innerHTML = "地址管理";
document.querySelector(".address-list").style.display = "block";
document.querySelector(".address").style.display = "none";
document.querySelector(".user-info").style.display = "none";
}
}
// 页面加载后的初始化操作
function init() {
// 初始化省份下拉列表内容
provinceInit();
// 为标签绑定单击事件
addClick();
}
window.onload = function () {
// 初始化
init();
};