天天看點

DataWorks産品菜單欄的優化解析

先來波廣告,DataWorks全新起航,提供給大家更優的資料開發體驗,有任何建議歡迎回報。

問題:

廢話不多說,看一下優化之前的菜單欄顯示的互動。

DataWorks産品菜單欄的優化解析

是的,我就是想直接選中資料開發,怎麼就這麼難。

這一塊整體的互動就是hover到上面的圖示,然後出現産品菜單,第一版在實作的時候,用css去控制菜單的display屬性,是以就會導緻當圖示失去焦點的時候,菜單就立馬消失了。

.logo:hover .list {
  display: none;
}​           

解決思路:

一種常見的解決方式就是設定延時,失去焦點後不會立馬消失。這種做法有一個缺點就是當使用者真的是想收起菜單時,還是要經過一段延時。

經過主管和師兄的指導,去看了下亞馬遜的菜單實作,他們的問題和這個相似,就是如何判斷使用者是要切換子菜單還是想移動到子菜單中,具體的互動如下:

DataWorks産品菜單欄的優化解析

可以看到在移動到子菜單的過程中,會經過下面的一級菜單,但是子菜單的内容并沒有發生變化。具體的實作過程,已經單獨抽成了一個jquery的元件,

https://github.com/kamens/jQuery-menu-aim

原了解析:

學習了下實作的代碼,其核心就是認為當下一刻的滑鼠軌迹在這個藍色三角區域的時候,使用者是想移動到子菜單的。

仔細想了下,确實如果使用者是想切換一級菜單的時候,滑鼠的軌迹一般是會往正下或者正上方向去滑動。

DataWorks産品菜單欄的優化解析

将這個原理應用到現在的場景中,假設目前的滑鼠位置為A,那麼如果下一刻滑鼠的位置在這個紅色區域内,就認為使用者是想移動到菜單中。

那麼怎麼判斷下一刻滑鼠的位置是在三角形内,方法有很多,最簡單的判定方法就是,AB與BC的夾角e'1<e1,AC與BC的夾角 e'2<e2。

DataWorks産品菜單欄的優化解析

代碼實作:

根據上面分析的原理,進行代碼實作。

export default class MenuAim {

  constructor(hoverDom, menuDom) {
    this.hoverDom = hoverDom; // icon
    this.menuDom = menuDom;   // product-list
    this.mouseTrack = [];  // 記錄滑鼠的移動軌迹,最多隻記錄三組資料

    this.onMouseOver = this.onMouseOver.bind(this);
    this.onMouseLeave = this.onMouseLeave.bind(this);
    this.onMouseMove = this.onMouseMove.bind(this);

    this.hoverDom.addEventListener('mouseover', this.onMouseOver);
    this.hoverDom.addEventListener('mouseleave', this.onMouseLeave);
    this.hoverDom.addEventListener('mousemove', this.onMouseMove);
    this.menuDom.addEventListener('mouseleave', () => {
      this.menuDom.style.display = 'none';
    });
  }

  onMouseOver() {
    this.menuDom.style.display = 'block';
  }

  onMouseMove(e) {
    this.mouseTrack.push({ x: e.pageX, y: e.pageY });
    if (this.mouseTrack.length > 3) {
      this.mouseTrack.shift();
    }
  }

  onMouseLeave(e) {
    // 滑鼠的目前位置
    const currentPosition = {
      x: e.pageX,
      y: e.pageY,
    };
    // 滑鼠的上一位置
    const prevPosition = this.mouseTrack[0];
    // 下拉菜單的左上角
    const menuLeftTop = {
      x: this.menuDom.offsetLeft,
      y: this.menuDom.offsetTop,
    };
    // 下拉菜單的右上角
    const menuRightTop = {
      x: this.menuDom.offsetLeft + this.menuDom.offsetWidth,
      y: this.menuDom.offsetTop,
    };

    // 現在的位置與左上角的角度  負值
    const currentLeftScale = (menuLeftTop.y - currentPosition.y) / (menuLeftTop.x - currentPosition.x);
    // 現在的位置與右上角的角度
    const currentRightScale = (menuRightTop.y - currentPosition.y) / (menuRightTop.x - currentPosition.x);

    // 上一位置與左上角的角度   負值
    const prevLeftScale = (menuLeftTop.y - prevPosition.y) / (menuLeftTop.x - prevPosition.x);
    // 上一位置與右上角的角度
    const prevRightScale = (menuRightTop.y - prevPosition.y) / (menuRightTop.x - prevPosition.x);

    if (currentLeftScale > prevLeftScale && currentRightScale < prevRightScale) {
      // 認為使用者是要移到下拉菜單
      this.menuDom.style.display = 'block';
    } else {
      this.menuDom.style.display = 'none';
    }
  }
}

           

優化結果:

最後看一下,優化後的效果。

DataWorks産品菜單欄的優化解析

繼續閱讀