最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

react版模擬亞馬遜人機(jī)交互菜單的實(shí)現(xiàn)

 更新時(shí)間:2022年02月08日 11:47:08   作者:forever_Mamba  
本文主要介紹了react版模擬亞馬遜人機(jī)交互菜單的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

前言

前段時(shí)間接了一個(gè)需求,實(shí)現(xiàn)一個(gè)模仿亞馬遜和京東的菜單交互效果,這種效果被稱為模擬人機(jī)交互。在網(wǎng)上搜了一下,目前沒有見到有 reactVue的版本,然后就自己參考了一下現(xiàn)有的方式,實(shí)現(xiàn)了一個(gè)react版本。

需求介紹

本文都是在web端的需求

參考亞馬遜和京東商城的首頁左側(cè)菜單效果,實(shí)現(xiàn)一個(gè)react版本的組件,以供業(yè)務(wù)使用。

我們先看下亞馬遜和京東商城的效果:

亞馬遜商城

京東商城

從上面的效果得出我們的菜單效果需求點(diǎn):

  • 當(dāng)我們的鼠標(biāo)懸浮在左側(cè)菜單的時(shí)候,右側(cè)會(huì)對應(yīng)展示它對應(yīng)的子菜單項(xiàng),
  • 當(dāng)我們的鼠標(biāo)在左側(cè)菜單上下移動(dòng)時(shí),左側(cè)可以快速切換為對應(yīng)的子菜單
  • 當(dāng)我們的鼠標(biāo)移動(dòng)以一定的傾斜角度移動(dòng)到右側(cè)的時(shí)候,鼠標(biāo)雖然會(huì)經(jīng)過其它的左側(cè)菜單,但是不會(huì)執(zhí)行切換。

到目前為止,我們就搞情況了我們的需求。接下來就要去實(shí)現(xiàn)我們的方案了。

實(shí)現(xiàn)方案

要實(shí)現(xiàn)我們的需求,復(fù)雜點(diǎn)主要是在如何實(shí)現(xiàn)上述的需求3。需求1和需求2 的基本切換效果我就不再說了,直接進(jìn)入需求3

實(shí)現(xiàn)需求3

如果要實(shí)現(xiàn)這個(gè)需求,我們需要記錄鼠標(biāo)從左往右(從左側(cè)菜單區(qū)域移動(dòng)到右側(cè)菜單區(qū)域)的移動(dòng)軌跡,然后根據(jù)它的移動(dòng)軌跡去判斷它是否是在一個(gè)三角形的區(qū)域之內(nèi),如果在的話,就不讓它切換菜單。

我們先看一張圖:

  • P1:鼠標(biāo)的起始位置
  • P2:左側(cè)菜單的固定點(diǎn)1,鼠標(biāo)在左側(cè)區(qū)域的最大位移點(diǎn)
  • P3:左側(cè)菜單的固定點(diǎn)2,鼠標(biāo)在左側(cè)區(qū)域的最大位移點(diǎn)
  • M:鼠標(biāo)在左側(cè)菜單移動(dòng)的結(jié)束位置

從上圖我們可以得出:

如果鼠標(biāo)的起始點(diǎn)是在 P1 的話,當(dāng)鼠標(biāo)移動(dòng)到右側(cè)區(qū)域,鼠標(biāo)可能經(jīng)過的三角形區(qū)域就是 P1-P2-P3所在的三角形,M點(diǎn)是鼠標(biāo)的結(jié)束位置。所以我們判斷鼠標(biāo)的運(yùn)動(dòng)軌跡是否在三角形中就可以了。

部分邏輯代碼

const [active, setActive] = useState(null) // 選中的菜單
  const [showSub, setShowSub] = useState(false) // 是否顯示子菜單
  let timeout = useRef(null) //  設(shè)置延遲定時(shí)器,防止鼠標(biāo)移到tab內(nèi)容經(jīng)過菜單時(shí)的切換
  let mouseLocs = useRef([]) // 記錄鼠標(biāo)移動(dòng)時(shí)的坐標(biāo)數(shù)組
  let firstSlope = useRef(null) // 菜單欄的固定點(diǎn)1, 根據(jù)菜單欄和內(nèi)容的位置而改變
  let secondSlope = useRef(null) // 菜單欄的固定點(diǎn)2, 根據(jù)菜單欄和內(nèi)容的位置而改變
  const refNavigation = useRef(null)
  const refNav = useRef(null)
  const refSubnav = useRef(null)


  /**
   * 根據(jù)內(nèi)容欄相對于菜單欄的位置,判斷移動(dòng)過程中的點(diǎn)是否在三角形內(nèi)
   * @param {Object} p1 開始位置
   * @param {Object} p2 菜單欄固定點(diǎn)1
   * @param {Object} p3 菜單欄固定點(diǎn)2
   * @param {Object} m 結(jié)束位置
   * @return {*}
   */
  function proPosInTriangle(p1, p2, p3, m) {
    // 結(jié)束時(shí)鼠標(biāo)坐標(biāo)位置
    let x = m.x,
      y = m.y,
      // 開始鼠標(biāo)坐標(biāo)位置
      x1 = p1.x,
      y1 = p1.y,
      // 菜單欄包裹層右上角坐標(biāo)
      x2 = p2.x,
      y2 = p2.y,
      // 右下角坐標(biāo)
      x3 = p3.x,
      y3 = p3.y,
      // (y2 - y1) / (x2 - x1)為兩坐標(biāo)連成直線的斜率
      // 因?yàn)橹本€的公式為y=kx+b;當(dāng)斜率相同時(shí),只要比較
      // b1和b2的差值就可以知道該點(diǎn)是在
      // (x1,y1),(x2,y2)的直線的哪個(gè)方向
      // 當(dāng)r1大于0,說明該點(diǎn)在直線右側(cè),其它以此類推
      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
    // 返回是否在三角形內(nèi)的結(jié)果
    return compare
  }

  /**
   * 獲取元素相對于瀏覽器左上角的坐標(biāo)位置,為正值
   * @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 元素的像素高度, 高度包含該元素的垂直內(nèi)邊距和邊框,且是一個(gè)整數(shù)
      left: location.x,
      leftAndWidth: location.x + element.offsetWidth,
    }
  }
  /**
   * 根據(jù)內(nèi)容欄相對于菜單欄的位置, 返回菜單欄的固定點(diǎn)1,和固定點(diǎn)2,保存在this.firstSlope和this.secondSlope對象里
   * 即 左側(cè)菜單欄的右上角和右下角的位置
   */
  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 {
        // 是否在指定三角形內(nèi)
        diff = proPosInTriangle(
          mouseLocs.current[0],
          firstSlope.current,
          secondSlope.current,
          mouseLocs.current[2]
        )
      } catch (ex) {}
      // 是就啟動(dòng)延遲顯示,
      // 否則不延遲
      if (diff) {
        timeout.current = setTimeout(() => {
          setActive(obj.key)
          setShowSub(true)
        }, 300)
      } else {
        setActive(obj.key)
        setShowSub(true)
      }
    },
    [mouseLocs, timeout]
  )

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

  // 移出菜單所在區(qū)域
  const onMouseLeave = () => {
    if (refSubnav.current) {
      setActive(null)
      setShowSub(false)
    }
  }

  // 記錄鼠標(biāo)在菜單欄中移動(dòng)的最后三個(gè)坐標(biāo)位置
  const onMousemove = event => {
    mouseLocs.current.push({
      x: event.pageX,
      y: event.pageY,
    })
    if (mouseLocs.current.length > 3) {
      // 移除超過三項(xiàng)的數(shù)據(jù)
      mouseLocs.current.shift()
    }
  }
  // 鼠標(biāo)移出的時(shí)候,清除延時(shí)器
  const onMouseout = () => {
    if (timeout.current) {
      clearTimeout(timeout.current)
    }
  }

實(shí)現(xiàn)效果

 到此這篇關(guān)于react版模擬亞馬遜人機(jī)交互菜單的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)react 交互菜單內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 2022最新前端常見react面試題合集

    2022最新前端常見react面試題合集

    這篇文章主要介紹了前端常見react面試題合集,介紹了React?Fiber的簡介及fetch封裝代碼,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下
    2022-09-09
  • 一文搞懂redux在react中的初步用法

    一文搞懂redux在react中的初步用法

    Redux是JavaScript狀態(tài)容器,提供可預(yù)測化的狀態(tài)管理,今天通過本文給大家分享redux在react中使用及配置redux到react項(xiàng)目中的方法,感興趣的朋友跟隨小編一起看看吧
    2021-06-06
  • react 跳轉(zhuǎn)后路由變了頁面沒刷新的解決方案

    react 跳轉(zhuǎn)后路由變了頁面沒刷新的解決方案

    最近在學(xué)習(xí)React的過程中遇到了路由跳轉(zhuǎn)后頁面不刷新的問題,本文就詳細(xì)的介紹一下解決方法,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-06-06
  • next-redux-wrapper使用細(xì)節(jié)及源碼分析

    next-redux-wrapper使用細(xì)節(jié)及源碼分析

    這篇文章主要為大家介紹了next-redux-wrapper使用細(xì)節(jié)及源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • React?state結(jié)構(gòu)設(shè)計(jì)原則示例詳解

    React?state結(jié)構(gòu)設(shè)計(jì)原則示例詳解

    這篇文章主要為大家介紹了React?state結(jié)構(gòu)設(shè)計(jì)原則示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • React 實(shí)現(xiàn)拖拽功能的示例代碼

    React 實(shí)現(xiàn)拖拽功能的示例代碼

    這篇文章主要介紹了React 實(shí)現(xiàn)拖拽功能的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-01-01
  • 使用useImperativeHandle時(shí)父組件第一次沒拿到子組件的問題

    使用useImperativeHandle時(shí)父組件第一次沒拿到子組件的問題

    這篇文章主要介紹了使用useImperativeHandle時(shí)父組件第一次沒拿到子組件的問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-08-08
  • react組件實(shí)例屬性state詳解

    react組件實(shí)例屬性state詳解

    這篇文章主要介紹了react組件實(shí)例屬性state,有狀態(tài)state的組件稱作復(fù)雜組件,沒有狀態(tài)的組件稱為簡單組件,狀態(tài)里存儲(chǔ)數(shù)據(jù),數(shù)據(jù)的改變驅(qū)動(dòng)頁面的展示,本文結(jié)合實(shí)例代碼給大家詳細(xì)講解,需要的朋友可以參考下
    2023-02-02
  • 使用webpack搭建react開發(fā)環(huán)境的方法

    使用webpack搭建react開發(fā)環(huán)境的方法

    本篇文章主要介紹了使用webpack搭建react開發(fā)環(huán)境的方法,在這篇文章中我們開始利用我們之前所學(xué)搭建一個(gè)簡易的React開發(fā)環(huán)境,用以鞏固我們之前學(xué)習(xí)的Webpack知識(shí)。一起跟隨小編過來看看吧
    2018-05-05
  • react-native 實(shí)現(xiàn)漸變色背景過程

    react-native 實(shí)現(xiàn)漸變色背景過程

    這篇文章主要介紹了react-native 實(shí)現(xiàn)漸變色背景過程,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-09-09

最新評論

罗城| 临武县| 吴江市| 尤溪县| 随州市| 德令哈市| 普兰店市| 建德市| 隆回县| 明光市| 孙吴县| 姚安县| 吴川市| 普陀区| 山阴县| 津市市| 潮安县| 玉林市| 自治县| 德惠市| 江津市| 连江县| 同仁县| 永嘉县| 桂平市| 宁晋县| 上饶县| 区。| 无锡市| 西峡县| 轮台县| 团风县| 革吉县| 长汀县| 衡阳市| 丽江市| 尼勒克县| 平湖市| 河北区| 满洲里市| 辽中县|