react版模拟亚马逊人机交互菜单的实现

目录
  • 前言
  • 需求介绍
  • 实现方案
    • 实现需求3
  • 部分逻辑代码
  • 实现效果

前言

前段时间接了一个需求,实现一个模仿亚马逊和京东的菜单交互效果,这种效果被称为模拟人机交互。在网上搜了一下,目前没有见到有 reactVue的版本,然后就自己参考了一下现有的方式,实现了一个react版本。

需求介绍

本文都是在web端的需求

参考亚马逊和京东商城的首页左侧菜单效果,实现一个react版本的组件,以供业务使用。

我们先看下亚马逊和京东商城的效果:

亚马逊商城

京东商城

从上面的效果得出我们的菜单效果需求点:

  • 当我们的鼠标悬浮在左侧菜单的时候,右侧会对应展示它对应的子菜单项,
  • 当我们的鼠标在左侧菜单上下移动时,左侧可以快速切换为对应的子菜单
  • 当我们的鼠标移动以一定的倾斜角度移动到右侧的时候,鼠标虽然会经过其它的左侧菜单,但是不会执行切换。

到目前为止,我们就搞情况了我们的需求。接下来就要去实现我们的方案了。

实现方案

要实现我们的需求,复杂点主要是在如何实现上述的需求3。需求1和需求2 的基本切换效果我就不再说了,直接进入需求3

实现需求3

如果要实现这个需求,我们需要记录鼠标从左往右(从左侧菜单区域移动到右侧菜单区域)的移动轨迹,然后根据它的移动轨迹去判断它是否是在一个三角形的区域之内,如果在的话,就不让它切换菜单。

我们先看一张图:

  • P1:鼠标的起始位置
  • P2:左侧菜单的固定点1,鼠标在左侧区域的最大位移点
  • P3:左侧菜单的固定点2,鼠标在左侧区域的最大位移点
  • M:鼠标在左侧菜单移动的结束位置

从上图我们可以得出:

如果鼠标的起始点是在 P1 的话,当鼠标移动到右侧区域,鼠标可能经过的三角形区域就是 P1-P2-P3所在的三角形,M点是鼠标的结束位置。所以我们判断鼠标的运动轨迹是否在三角形中就可以了。

部分逻辑代码

const [active, setActive] = useState(null) // 选中的菜单
  const [showSub, setShowSub] = useState(false) // 是否显示子菜单
  let timeout = useRef(null) //  设置延迟定时器,防止鼠标移到tab内容经过菜单时的切换
  let mouseLocs = useRef([]) // 记录鼠标移动时的坐标数组
  let firstSlope = useRef(null) // 菜单栏的固定点1, 根据菜单栏和内容的位置而改变
  let secondSlope = useRef(null) // 菜单栏的固定点2, 根据菜单栏和内容的位置而改变
  const refNavigation = useRef(null)
  const refNav = useRef(null)
  const refSubnav = useRef(null)

  /**
   * 根据内容栏相对于菜单栏的位置,判断移动过程中的点是否在三角形内
   * @param {Object} p1 开始位置
   * @param {Object} p2 菜单栏固定点1
   * @param {Object} p3 菜单栏固定点2
   * @param {Object} m 结束位置
   * @return {*}
   */
  function proPosInTriangle(p1, p2, p3, m) {
    // 结束时鼠标坐标位置
    let x = m.x,
      y = m.y,
      // 开始鼠标坐标位置
      x1 = p1.x,
      y1 = p1.y,
      // 菜单栏包裹层右上角坐标
      x2 = p2.x,
      y2 = p2.y,
      // 右下角坐标
      x3 = p3.x,
      y3 = p3.y,
      // (y2 - y1) / (x2 - x1)为两坐标连成直线的斜率
      // 因为直线的公式为y=kx+b;当斜率相同时,只要比较
      // b1和b2的差值就可以知道该点是在
      // (x1,y1),(x2,y2)的直线的哪个方向
      // 当r1大于0,说明该点在直线右侧,其它以此类推
      r1 = y - y1 - ((y2 - y1) / (x2 - x1)) * (x - x1),
      r2 = y - y2 - ((y3 - y2) / (x3 - x2)) * (x - x2),
      r3 = y - y3 - ((y1 - y3) / (x1 - x3)) * (x - x3),
      compare

    compare = r1 * r2 * r3 < 0 && r1 > 0
    // 返回是否在三角形内的结果
    return compare
  }

  /**
   * 获取元素相对于浏览器左上角的坐标位置,为正值
   * @param element
   * @return {{x: Number, y: Number}}
   * @constructor
   */
  function LocFromdoc(element) {
    const { x, y, width, height } = element.getBoundingClientRect()
    return {
      x: x,
      y: y,
      width,
      height,
    }
  }
  /**
   * 记录元素的位置信息
   * @param element
   * @return {{top: *, topAndHeight: number, left: *, leftAndWidth: number}}
   */
  function getInfo(element) {
    const location = LocFromdoc(element)
    return {
      top: location.y,
      topAndHeight: location.y + element.offsetHeight, // offsetHeight 元素的像素高度, 高度包含该元素的垂直内边距和边框,且是一个整数
      left: location.x,
      leftAndWidth: location.x + element.offsetWidth,
    }
  }
  /**
   * 根据内容栏相对于菜单栏的位置, 返回菜单栏的固定点1,和固定点2,保存在this.firstSlope和this.secondSlope对象里
   * 即 左侧菜单栏的右上角和右下角的位置
   */
  function ensureTriangleDots() {
    // 获取菜单栏的位置
    const info = getInfo(refNav.current)
    const x1 = info.leftAndWidth
    const y1 = info.top
    const x2 = x1
    const y2 = info.topAndHeight

    firstSlope.current = {
      x: x1,
      y: y1,
    }
    secondSlope.current = {
      x: x2,
      y: y2,
    }
  }

  const onMouseOver = useCallback(
    obj => {
      let diff
      try {
        // 是否在指定三角形内
        diff = proPosInTriangle(
          mouseLocs.current[0],
          firstSlope.current,
          secondSlope.current,
          mouseLocs.current[2]
        )
      } catch (ex) {}
      // 是就启动延迟显示,
      // 否则不延迟
      if (diff) {
        timeout.current = setTimeout(() => {
          setActive(obj.key)
          setShowSub(true)
        }, 300)
      } else {
        setActive(obj.key)
        setShowSub(true)
      }
    },
    [mouseLocs, timeout]
  )

  const onMouseEnter = () => {
    // 计算位置
    if (refNav.current) {
      ensureTriangleDots()
    }
    setShowSub(true)
  }

  // 移出菜单所在区域
  const onMouseLeave = () => {
    if (refSubnav.current) {
      setActive(null)
      setShowSub(false)
    }
  }

  // 记录鼠标在菜单栏中移动的最后三个坐标位置
  const onMousemove = event => {
    mouseLocs.current.push({
      x: event.pageX,
      y: event.pageY,
    })
    if (mouseLocs.current.length > 3) {
      // 移除超过三项的数据
      mouseLocs.current.shift()
    }
  }
  // 鼠标移出的时候,清除延时器
  const onMouseout = () => {
    if (timeout.current) {
      clearTimeout(timeout.current)
    }
  }

实现效果

到此这篇关于react版模拟亚马逊人机交互菜单的实现的文章就介绍到这了,更多相关react 交互菜单内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • React Native仿美团下拉菜单的实例代码

    本文介绍了React Native仿美团下拉菜单的实例代码,最近也在学习React Native,顺便分享给大家 在很多产品中都会涉及到下拉菜单选择功能,用的最好的当属美团了,其效果如下: 要实现上面的效果,在原生中比较好做,直接使用PopWindow组件即可.如果使用React Native开发上面的效果,需要注意几个问题: 1. 在下拉的时候有动画过度效果: 2.下拉菜单出现后点击菜单项,菜单项可选择,并触发对应的事件: 3.下拉菜单中的项目可以配置: 要实现弹框效果,我们马上回想到使用Mo

  • react实现移动端下拉菜单的示例代码

    前言 项目中要实现类似与vant的DropdownMenu:下拉菜单.看了vans 的效果 其实也没什么难度,于是动手鲁了一个这样的组件. 项目的技术栈为react全家桶+material UI + ant Design mobile. vans的效果 我自己实现的效果 思路 常规做法获取dom元素,动态修改选中dom的innerHtml. 当然这种方式不是react推荐的 我的做法既然react不推荐直接操作dom元素,那可以采用动态动态修改class的方式达到效果,例如: let cls =

  • React Js 微信禁止复制链接分享禁止隐藏右上角菜单功能

    废话不多说了,直接给大家贴代码了,具体代码如下所示: /** * Created by wuyakun on 2017/5/23. */let wxUtils = {}; /** * 是否开启右上角Menu * @param open */ wxUtils.optionMenu = function (open = true) { if (open) { openOptionMenu(); } else { disabledOptionMenu(); } }; /** * 是否禁用右上角 */

  • react实现菜单权限控制的方法

    通常公司的后台管理系统都需要权限控制,即不同的角色用户看到不同的菜单,如下图: 下面,通过react实现这样的后台管理系统(脚手架),功能简介: 1.顶部的菜单项根据用户的角色动态生成. 2.侧边测菜单项根据已选的顶部菜单动态生成. 直接上代码: 路由配置: export default ( <Route path="/" component={App}> <IndexRoute component={EmployeeList}/> <Route path

  • React Native自定义控件底部抽屉菜单的示例

    一.需求分析 原生开发中,自定义View可谓是屡见不鲜的事情,往往系统的控件总不能满足现实的需求.五花八门的产品设计需要我们做出不同的View.关于自定义View的内容网上已经有很多的博文,本篇博客要和大家分享如何在React Native中自定义组件实现抽屉菜单控件效果.分享功能在App中的重要性想必是不言而喻的,那么RN中如何实现这种效果呢? React Native 系统库中只提供了IOS的实现,即ActionSheetIOS.该控件的显示方式有两种实现: (1)showActionShe

  • 使用ReactJS实现tab页切换、菜单栏切换、手风琴切换和进度条效果

    ReactJS是Facebook推出的产品.在2013年的Qcon大会(上海)上面,当时Facebook的前端工程师做过一次讲座,就专门介绍了ReactJS. ReactJS可以看做就是用来Render的.ReactJS是可以达到游戏级别的渲染,fps可以保持在60左右,相当的了不起,它做了一个虚拟dom tree加速了渲染过程,根据当时的数据说比angularjs快20%以上. 前沿 对于React, 去年就有耳闻, 挺不想学的, 前端那么多东西, 学了一个框架又有新框架要学

  • react版模拟亚马逊人机交互菜单的实现

    目录 前言 需求介绍 实现方案 实现需求3 部分逻辑代码 实现效果 前言 前段时间接了一个需求,实现一个模仿亚马逊和京东的菜单交互效果,这种效果被称为模拟人机交互.在网上搜了一下,目前没有见到有 react和Vue的版本,然后就自己参考了一下现有的方式,实现了一个react版本. 需求介绍 本文都是在web端的需求 参考亚马逊和京东商城的首页左侧菜单效果,实现一个react版本的组件,以供业务使用. 我们先看下亚马逊和京东商城的效果: 亚马逊商城 京东商城 从上面的效果得出我们的菜单效果需求点:

  • 亚马逊经典面试题实例详解

    亚马逊面试题: 如下所示的Map中,0代表海水,1代表岛屿,其中每一个岛屿与其八领域的区间的小岛能相连组成岛屿群.写代码,统计Map中岛屿个数. /* Q1. Map [ 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 ] */ 实现代码: #include<iostream> #include<queue> using namespace

  • Python爬取当当、京东、亚马逊图书信息代码实例

    注:1.本程序采用MSSQLserver数据库存储,请运行程序前手动修改程序开头处的数据库链接信息 2.需要bs4.requests.pymssql库支持 3.支持多线程 from bs4 import BeautifulSoup import re,requests,pymysql,threading,os,traceback try: conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='root',

  • python爬取亚马逊书籍信息代码分享

    我有个需求就是抓取一些简单的书籍信息存储到mysql数据库,例如,封面图片,书名,类型,作者,简历,出版社,语种. 我比较之后,决定在亚马逊来实现我的需求. 我分析网站后发现,亚马逊有个高级搜索的功能,我就通过该搜索结果来获取书籍的详情URL. 由于亚马逊的高级搜索是用get方法的,所以通过分析,搜索结果的URL,可得到node参数是代表书籍类型的.field-binding_browse-bin是代表书籍装饰. 所以我固定了书籍装饰为平装,而书籍的类型,只能每次运行的时候,爬取一种类型的书籍难

  • Python实现爬取亚马逊数据并打印出Excel文件操作示例

    本文实例讲述了Python实现爬取亚马逊数据并打印出Excel文件操作.分享给大家供大家参考,具体如下: python大神们别喷,代码写的很粗糙,主要是完成功能,能够借鉴就看下吧,我是学java的,毕竟不是学python的,自己自学看了一点点python,望谅解. #!/usr/bin/env python3 # encoding=UTF-8 import sys import re import urllib.request import json import time import zli

  • 用pushplus+python监控亚马逊到货动态推送微信

    xbox series和ps5发售以来,国内黄牛价格一直居高不下.虽然海外amazon上ps5补货很少而且基本撑不过一分钟,但是xbox series系列明显要好抢很多. 日亚.德亚的xbox series x/s都可以直邮中国大陆,所以我们只需要借助脚本,监控相关网页的动态,在补货的第一时刻通过微信告知我们,然后迅速人工购买即可! 需求:pushplus(需要微信关注公众号).python3 一.pushplus相关介绍 pushplus提供了免费的微信消息推送api,具体内容可以参考他的官网

  • 用Python获取亚马逊商品信息

    目录 引言 一.获取亚马逊列表页的信息 二.获取详情页信息 三.代理设置 四.全部代码 总结 引言 亚马逊网站相较于国内的购物网站,可以直接使用python的最基本的requests进行请求.访问不是过于频繁,在未触发保护机制的情况下,可以获取我们想要的数据.本次通过以下三部分简单介绍下基本爬取流程: 使用requests的get请求,获取亚马逊列表和详情页的页面内容使用css/xpath对获取的内容进行解析,取得关键数据动态IP的作用及其使用方法 一.获取亚马逊列表页的信息 以游戏区为例: 获

  • 基于Python获取亚马逊的评论信息的处理

    目录 一.分析亚马逊的评论请求 二.获取亚马逊评论的内容 三.亚马逊评论信息的处理 四.代码整合 4.1代理设置 4.2while循环翻页 总结 上次亚马逊的商品信息都获取到了,自然要看一下评论的部分.用户的评论能直观的反映当前商品值不值得购买,亚马逊的评分信息也能获取到做一个评分的权重. 亚马逊的评论区由用户ID,评分及评论标题,地区时间,评论正文这几个部分组成,本次获取的内容就是这些. 测试链接:https://www.amazon.it/product-reviews/B08GHGTGQ2

  • jquery 插件之仿“卓越亚马逊”首页弹出菜单效果

    复制代码 代码如下: /*弹出式菜单*/ //没剑 2008-07-03 //http://regedit.cnblogs.com /*参数说明*/ //showobj:要显示的菜单ID //timeout:延时时间,鼠标停留/离开后延时多久开始显示/隐藏菜单 //speed:菜单显示速度,数字越大,显示越慢,默认为100 //调用示例:$("#button").DMenu("#content"); jQuery.fn.DMenu=function(showobj,

  • jsoneditor二次封装实时预览json编辑器组件react版

    目录 前言 设计思路 正文 jsoneditor的使用 结合react进行二次封装 前言 做为一名前端开发人员,掌握vue/react/angular等框架已经是必不可少的技能了,我们都知道,vue或react等MVVM框架提倡组件化开发,这样一方面可以提高组件复用性和可扩展性,另一方面也带来了项目开发的灵活性和可维护,方便多人开发协作.接下来文章将介绍如何使用react,开发一个自定义json编辑器组件.我们这里使用了jsoneditor这个第三方库,官方地址: jsoneditor 通过实现

随机推荐