二级下拉菜单在网站中应用非常广泛,这次我们利用CSS和原生Js来编写一个实用的二级下拉菜单。主要应用到的技术有CSS的定位,列表项和JS事件。
CSS定位
四种定位方式
static:定位的默认值。
relative:相对定位,相对于原来位置。(用的较多)
absolute:相对于有定位的父级元素或更上级元素进行定位。(用的较多)
fixed:相对于视窗本身进行固定定位。
javascript事件
针对JS事件本人做了三个页面来学习这块内容。
事件与事件监听
<!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>
<!--事件属性-->
<button onclick="console.log(this.innerText)">按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<!--事件属性只有最后一次是有效的 同名事件刚覆盖-->
<script>
// querySelector() 方法仅仅返回匹配指定选择器的第一个元素。如果你需要返回所有的元素,请使用 querySelectorAll() 方法替代
document.querySelectorAll("button")[1].onclick = function () {
console.log("第一次点击");
};
document.querySelectorAll("button")[1].onclick = function () {
console.log("第二次点击");
};
//事件监听器 可以给一个元素多次添加同一个事件,
//并且可以自定义事件的出发阶段
const btn3 = document.querySelectorAll("button")[2];
btn3.addEventListener("click", function () {
console.log("第一次点击");
});
btn3.addEventListener("click", function () {
console.log("第二次点击");
});
</script>
</body>
</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>
<div>
<li><a href="">事件触发阶段</a></li>
</div>
<script>
const body = document.querySelector("body");
//也可以这样写 document.body;
const div = document.querySelector("div");
const li = document.querySelector("li");
const a = document.querySelector("a");
// a.addEventListener("click", showTagName,false);
//第三个值false是默认值,不写也可默认就是冒泡。如果是True,则是由外至内的捕获
// a.addEventListener("click", showTagName);
// li.addEventListener("click", showTagName);
// div.addEventListener("click", showTagName);
// body.addEventListener("click", showTagName);
a.addEventListener("click", showTagName, true);
li.addEventListener("click", showTagName, true);
div.addEventListener("click", showTagName, true);
body.addEventListener("click", showTagName, true);
function showTagName() {
alert(this.tagName);
}
</script>
</body>
</html>
事件代理与事件委托
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<ul>
<li>项目1</li>
<li>项目2</li>
<li>项目3</li>
<li>项目4</li>
<li>项目5</li>
<li>项目6</li>
<li>项目7</li>
<li>项目8</li>
<li>项目9</li>
<li>项目10</li>
</ul>
<script>
const lis = document.querySelectorAll("li");
//forEach() 方法用于调用数组的每个元素,并将元素传递给回调函数。
// lis.forEach(function (li) {
// li.addEventListener("click", function () {
// console.log(li.innerText);
// });
// });
// for (var i = 0; i <= lis.length; i++) {
// lis[i].addEventListener("click", function () {
// console.log(this.innerText);
// });
// }
//ev 事件对象
//事件代理,用父级代理子元素以及更下一级的元素上的同名事件
// document.querySelector("ul").addEventListener("click", function (ev) {
// console.log(this.tagName);
// });
//Event 对象 简写ev
//Event 对象代表事件的状态,比如事件在其中发生的元素、键盘按键的状态、鼠标的位置、鼠标按钮的状态。
document.querySelector("ul").addEventListener("click", function (ev) {
console.log(ev.target);
});
//event.target 返回事件的目标节点(触发该事件的节点)
document.querySelector("ul").addEventListener("click", function (ev) {
console.log(ev.currentTarget);
});
////event.currentTarget 返回的是事件绑定者
</script>
</body>
</html>
下拉菜单代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
* {
padding: 0;
margin: 0;
list-style: none;
}
a {
text-decoration: none;
color: tomato;
}
#nav {
background-color: black;
height: 50px;
line-height: 50px;
}
#nav > li {
display: block;
width: 150px;
float: left;
margin-right: 30px;
position: relative;//父元素相对定位
text-align: center;
}
#nav > li > a:hover {
color: yellow;
}
#nav > li > ul {
position: absolute; //绝对定位,相对于有相对定位的父LI定位
top: 50px;
width: 150px;
display: none;
}
#nav > li > ul li {
height: 40px;
border-bottom: 1px solid white;
line-height: 40px;
text-align: center;
background-color: rgba(0, 0, 0, 0.8);
}
#nav > li > ul li:hover {
background-color: rgba(0, 0, 0, 0.6);
}
</style>
</head>
<body>
<ul id="nav">
<li><a href="">网站首页</a></li>
<li>
<a href="">国内景点</a>
<ul>
<li><a href="">故宫</a></li>
<li><a href="">长城</a></li>
<li><a href="">后海</a></li>
<li><a href="">颐和园</a></li>
</ul>
</li>
<li>
<a href="">国外景点</a>
<ul>
<li><a href="">金字塔</a></li>
<li><a href="">圣母院</a></li>
<li><a href="">埃菲尔铁塔</a></li>
<li><a href="">自由女神</a></li>
</ul>
</li>
<li>
<a href="">中国名人</a>
<ul>
<li><a href="">秦始皇</a></li>
<li><a href="">孔子</a></li>
<li><a href="">李白</a></li>
<li><a href="">杜甫</a></li>
</ul>
</li>
<li>
<a href="">世界名人</a>
<ul>
<li><a href="">亚历山大</a></li>
<li><a href="">拿破仑</a></li>
<li><a href="">俾斯麦</a></li>
<li><a href="">斯大林</a></li>
</ul>
</li>
</ul>
<script>
const navs = document.querySelectorAll("#nav>li");
navs.forEach(function (nav) {
nav.addEventListener("mouseover", showSubMenu);
nav.addEventListener("mouseout", closeSubMenu);
});
function showSubMenu(ev) {
// console.log(ev.target);
// 当前这个导航有没有子菜单?
if (
//ev.target.nodeName === "A" &&
//这里加上面判断的话,必须鼠标在A标签上才可显示。鼠标在LI上显示不了
ev.target.nextElementSibling !== null
) {
ev.target.nextElementSibling.style.display = "block";
}
}
function closeSubMenu(ev) {
if (
ev.target.nodeName === "A" && //这里必须加判断,要不移动到其它LI标签上就会消失。因为冒泡
ev.target.nextElementSibling !== null
) {
ev.target.nextElementSibling.style.display = "none";
}
}
</script>
</body>
</html>
展示效果如下
制做二级菜单总结如下
- 在学习过程中,有很多不明白的地方,多看视频教程。
- 不懂的知识点,参数、名字等多百度搜索一下。
- 多写几遍代码,多写注释。