js練習(xí)-setTimeout應(yīng)用

一直覺得js學(xué)的不扎實(shí),網(wǎng)上找了項(xiàng)目練手,項(xiàng)目地址在這里。

分析

  1. 首先,子菜單被全部隱藏,將子菜單的樣式設(shè)為 display: block;,發(fā)現(xiàn)子菜單和他所對(duì)應(yīng)的主菜單的左端對(duì)其,后三項(xiàng)子菜單的右端超出導(dǎo)航欄的右端,說(shuō)明后面需要對(duì)子菜單的位置進(jìn)行設(shè)置;
  2. 子菜單的小箭頭位置也需要移動(dòng)到他所對(duì)應(yīng)主菜單的中間;
  3. 最重要的,需要為主菜單添加鼠標(biāo)事件。

實(shí)現(xiàn)

  1. 最簡(jiǎn)單的,先為主菜單添加鼠標(biāo)事件,鼠標(biāo)懸停,顯示子菜單,代碼如下。
let nav = document.querySelector("#nav");
let li = nav.querySelectorAll("li");

li.forEach(function (item) {
  if (item.children.length > 1) { //為有子菜單的主菜單添加鼠標(biāo)事件
    item.addEventListener("mouseenter", function () {
      let itemSecondChild = item.children[1];
      itemSecondChild.style.display = "block";
      //后續(xù)代碼
    }, false);
  }
})
image1.png
  1. 在鼠標(biāo)離開主菜單后,子菜單應(yīng)消失。
li.forEach(function (item) {
  if (item.children.length > 1) {
    //為有子菜單的主菜單添加鼠標(biāo)事件
    item.addEventListener("mouseenter", function () {
      //鼠標(biāo)懸停,顯示子菜單
      let itemSecondChild = item.children[1];
      itemSecondChild.style.display = "block";
      //后續(xù)代碼
    }, false);
    //鼠標(biāo)離開主菜單,子菜單消失
    item.addEventListener("mouseleave", function () {
      item.children[1].style.display = "none";   
    }, false);
  }
})

注:如果當(dāng)前節(jié)點(diǎn)有子節(jié)點(diǎn),鼠標(biāo)在節(jié)點(diǎn)內(nèi)部移動(dòng)時(shí),mouseenter只會(huì)被觸發(fā)一次,mouseover移動(dòng)就會(huì)被觸發(fā);mouseleavemouseout同理,當(dāng)鼠標(biāo)離開當(dāng)前節(jié)點(diǎn)內(nèi)的子節(jié)點(diǎn),mouseleave不會(huì)被觸發(fā),mouseout會(huì)被觸發(fā)。所以為避免多次觸發(fā),選擇mouseentermouseover

這樣操作會(huì)發(fā)現(xiàn),子菜單很難被點(diǎn)到(除非手速夠快),為了客戶的體驗(yàn)感,當(dāng)然要進(jìn)行優(yōu)化,就把子菜單的顯示時(shí)間變得久一點(diǎn)。

  1. 更改「鼠標(biāo)離開事件」,代碼如下。

在聲明navli的位置添加

let timer = null;

更改「鼠標(biāo)離開事件」

item.addEventListener("mouseleave", function () {
  timer = setTimeout(function () {
    item.children[1].style.display = "none";
  }, 300);
}, false);

還是有問(wèn)題,雖然子菜單可以被點(diǎn)擊到,但還是有問(wèn)題,他會(huì)憑空消失,console.log()測(cè)試一下。
在「鼠標(biāo)懸停事件」添加console.log("1");,在「鼠標(biāo)離開事件」添加
console.log("2");,輸出1 2 1 2,第一個(gè) 2 是我在從主菜單切換到子菜單輸出的,第二個(gè) 2 是哪里來(lái)的呢?第二個(gè) 2 是由于 setTimeout 異步執(zhí)行,在0.3秒后,進(jìn)入主線程,輸出的結(jié)果。該如何解決呢?

  1. 查閱資料,這可以通過(guò)「阻止冒泡」解決(可以google或百度一下)。代碼補(bǔ)充在‘后續(xù)代碼’后,見下。
//后續(xù)代碼
//阻止鼠標(biāo)離開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

運(yùn)行結(jié)果顯示,雖然子菜單可以正常訪問(wèn),可是,子菜單不會(huì)正確消失,需要在「鼠標(biāo)懸停事件」對(duì)子菜單初始化。

  1. 對(duì)子菜單初始化。代碼補(bǔ)充在‘后續(xù)代碼’后,見下。
//后續(xù)代碼
// 將所有子菜單設(shè)為隱藏(如果不將子菜單進(jìn)行隱藏初始化,下方的 解決阻止冒泡 會(huì)一直將子菜單進(jìn)行保留??梢詫⒋诵写a注釋,查看不隱藏初始化的表現(xiàn))
for (let i = 0; i < subnav.length; i++) subnav[i].style.display = "none";

子菜單正常顯示。

  1. 解決最開始的需求分析:對(duì) 超出導(dǎo)航欄右側(cè)的 子菜單的位置進(jìn)行修改,并解決 子菜單的小箭頭 位置的問(wèn)題。
    在定義itemSecondChild位置下方添加 em(小箭頭)的定義
let em = itemSecondChild.children[0];

代碼同樣添加到‘后續(xù)代碼’后。

//對(duì)主菜單下的箭頭位置進(jìn)行設(shè)置,設(shè)置為主菜單的中間位置。
em.style.left = item.offsetWidth / 2 + "px";

//子菜單右側(cè)超出主菜單,對(duì)子菜單位置進(jìn)行調(diào)整。箭頭位置也隨之改變,也進(jìn)行設(shè)置。
if (nav.offsetWidth - item.offsetLeft < itemSecondChild.offsetWidth) {
  itemSecondChild.style.right = "0";
  em.style.left = item.offsetLeft - itemSecondChild.offsetLeft + item.offsetWidth / 2 + "px";
}

完整代碼在這里
如有錯(cuò)誤,歡迎指正。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容