一直覺得js學的不扎實,網上找了項目練手终惑,項目地址在這里绍在。
分析
- 首先,子菜單被全部隱藏,將子菜單的樣式設為
display: block;
偿渡,發(fā)現子菜單和他所對應的主菜單的左端對其臼寄,后三項子菜單的右端超出導航欄的右端,說明后面需要對子菜單的位置進行設置溜宽; - 子菜單的小箭頭位置也需要移動到他所對應主菜單的中間脯厨;
- 最重要的,需要為主菜單添加鼠標事件坑质。
實現
- 最簡單的,先為主菜單添加鼠標事件临梗,鼠標懸停涡扼,顯示子菜單,代碼如下盟庞。
let nav = document.querySelector("#nav");
let li = nav.querySelectorAll("li");
li.forEach(function (item) {
if (item.children.length > 1) { //為有子菜單的主菜單添加鼠標事件
item.addEventListener("mouseenter", function () {
let itemSecondChild = item.children[1];
itemSecondChild.style.display = "block";
//后續(xù)代碼
}, false);
}
})
image1.png
- 在鼠標離開主菜單后吃沪,子菜單應消失。
li.forEach(function (item) {
if (item.children.length > 1) {
//為有子菜單的主菜單添加鼠標事件
item.addEventListener("mouseenter", function () {
//鼠標懸停什猖,顯示子菜單
let itemSecondChild = item.children[1];
itemSecondChild.style.display = "block";
//后續(xù)代碼
}, false);
//鼠標離開主菜單票彪,子菜單消失
item.addEventListener("mouseleave", function () {
item.children[1].style.display = "none";
}, false);
}
})
注:如果當前節(jié)點有子節(jié)點,鼠標在節(jié)點內部移動時不狮,mouseenter
只會被觸發(fā)一次降铸,mouseover
移動就會被觸發(fā);mouseleave
和mouseout
同理摇零,當鼠標離開當前節(jié)點內的子節(jié)點推掸,mouseleave
不會被觸發(fā),mouseout
會被觸發(fā)驻仅。所以為避免多次觸發(fā)谅畅,選擇mouseenter
和mouseover
。
這樣操作會發(fā)現噪服,子菜單很難被點到(除非手速夠快)毡泻,為了客戶的體驗感,當然要進行優(yōu)化粘优,就把子菜單的顯示時間變得久一點仇味。
- 更改「鼠標離開事件」,代碼如下敬飒。
在聲明nav
和li
的位置添加
let timer = null;
更改「鼠標離開事件」
item.addEventListener("mouseleave", function () {
timer = setTimeout(function () {
item.children[1].style.display = "none";
}, 300);
}, false);
還是有問題邪铲,雖然子菜單可以被點擊到,但還是有問題无拗,他會憑空消失带到,console.log()
測試一下。
在「鼠標懸停事件」添加console.log("1");
,在「鼠標離開事件」添加
console.log("2");
揽惹,輸出1 2 1 2
被饿,第一個 2
是我在從主菜單切換到子菜單輸出的,第二個 2
是哪里來的呢搪搏?第二個 2
是由于 setTimeout
異步執(zhí)行狭握,在0.3秒后,進入主線程疯溺,輸出的結果论颅。該如何解決呢?
- 查閱資料囱嫩,這可以通過「阻止冒泡」解決(可以google或百度一下)恃疯。代碼補充在‘后續(xù)代碼’后,見下墨闲。
//后續(xù)代碼
//阻止鼠標離開item瞬間的冒泡行為今妄,如果不阻止,0.3秒后鸳碧,子菜單將不再顯示
//w3c的方法是e.stopPropagation()盾鳞,IE則是使用e.cancelBubble = true
item.addEventListener("mouseover", function (event) {
event? event.cancelBubble = true : event.stopPropagation();
clearTimeout(timer);
}, false);
image2.png
運行結果顯示,雖然子菜單可以正常訪問瞻离,可是腾仅,子菜單不會正確消失,需要在「鼠標懸停事件」對子菜單初始化琐脏。
- 對子菜單初始化攒砖。代碼補充在‘后續(xù)代碼’后,見下日裙。
//后續(xù)代碼
// 將所有子菜單設為隱藏(如果不將子菜單進行隱藏初始化吹艇,下方的 解決阻止冒泡 會一直將子菜單進行保留“悍鳎可以將此行代碼注釋受神,查看不隱藏初始化的表現)
for (let i = 0; i < subnav.length; i++) subnav[i].style.display = "none";
子菜單正常顯示。
- 解決最開始的需求分析:對 超出導航欄右側的 子菜單的位置進行修改格侯,并解決 子菜單的小箭頭 位置的問題鼻听。
在定義itemSecondChild
位置下方添加em
(小箭頭)的定義
let em = itemSecondChild.children[0];
代碼同樣添加到‘后續(xù)代碼’后。
//對主菜單下的箭頭位置進行設置联四,設置為主菜單的中間位置撑碴。
em.style.left = item.offsetWidth / 2 + "px";
//子菜單右側超出主菜單,對子菜單位置進行調整朝墩。箭頭位置也隨之改變醉拓,也進行設置。
if (nav.offsetWidth - item.offsetLeft < itemSecondChild.offsetWidth) {
itemSecondChild.style.right = "0";
em.style.left = item.offsetLeft - itemSecondChild.offsetLeft + item.offsetWidth / 2 + "px";
}
完整代碼在這里
如有錯誤,歡迎指正亿卤。