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产品菜单栏的优化解析

上一篇:《阿里云飞天大数据平台 DataWorks 前端技术解密:工作流调度可视化》(脱敏版本)


下一篇:C++模板实现,支持多维,安全数组的完整代码