【问题标题】:Conditionally displaying React components with hover and timeouts有条件地显示带有悬停和超时的 React 组件
【发布时间】:2022-01-23 12:20:56
【问题描述】:

我遇到了一个棘手的 React 布局问题。这是一个足够简单的问题,只是很难解释,所以我试图尽可能明确。我有一些数据可以像这样映射单个组件:

map => <TableRow name={props.name} actionOne={props.someAction} />

Name Type Show/Hide Controls Buttons (hidden by default)
John Deere Tractor show/hide <div style="hidden"><button id="actionOneButton"></div>
John Smith Person show/hide <div style="hidden"><button id="actionOneButton"></div>

控制按钮默认是隐藏的。此处的想法是仅当用户停留在某一行或用户决定让某些控制按钮在某些行上永久可见时才显示按钮工具

我们需要做两件事:

  1. 当进入表格并将鼠标悬停在一行上时,会有 500 毫秒的延迟,之后才会出现仅针对该行的操作按钮。如果此时我们将光标向上或向下移动到不同的行,没有延迟,新悬停的行立即显示其对应的按钮,并且上一行中先前显示的按钮立即隐藏

  2. 当用户将光标移出表格时,会有 500 毫秒的倒计时。在此期间,最后一次显示在一行中的按钮将保持显示状态。计时器到时,最后一个显示按钮的行现在将其隐藏。 将其视为“悬停时显示”,但在进入和退出桌子时会有 500 毫秒的延迟。

快完成了!

  1. 一个警告:单击show 链接将永久显示该行中的按钮,而隐藏链接通过隐藏按钮将其返回到原始状态。 (我们回到#1) 手动显示的按钮会永久保留,直到关闭,此时它们的行为与开始时相同。

重要提示: 如果光标退出表格,然后在“退出计时器”计时结束之前将鼠标悬停在表格内:

  • 当光标在表格之外时,之前突出显示的行显示按钮仍然可见;然后在达到 500 毫秒的退出超时时将其隐藏。
  • 同时,由于上述超时并即将消失,现在已经进入表格的光标再次启动500ms计数以显示它恰好重新进入的行的隐藏按钮。此时#1超时并隐藏,如果从表格内部悬停,将根据开始时的第一组标准立即出现:如果通过“进入”500ms门,则任何隐藏的按钮都会立即显示.

问题

我有一些松散的想法,但是在设计这样的东西时想到了什么,以便所有状态和超时(甚至是要走的路)都封装在最多两个组件中 - 像表格和行?

如何设计此组件功能?我是不是在这里找错了树,可以通过聪明的 CSS 完成显示/隐藏吗?

【问题讨论】:

    标签: javascript css reactjs mouseevent settimeout


    【解决方案1】:

    我会按照以下方式解决这个问题

    表格状态:

    1. lastHovered - 最后一个悬停行的 id(或 null)
    2. hoverTimerId - 当前定时器的定时器id
    3. hoverRowId - 当前定时器的行ID

    行道具:

    1. isLastHovered - 布尔值,当这是最后显示的道具时为真

    行状态:

    1. alwaysShow - boolean, true when the always show controls button is selected

    行/表外的悬停事件

    //can be called with null for outside hover or rowId for row hover
    onRowHover = (rowId) => {
        if(rowId === hoverRowId)
            return
        if(hoverTimerId !== null)
            clearTimeout(hoverTimerId)
        const timerId = setTimeout(() => {
            setLastHovered(rowId)
        }, 500)
        setHoverTimerId(timerId)
        setHoverRowId(rowId)
    }
    

    最后,如果 isLastHovered 属性为真,或者始终显示状态为真,请确保显示控件。

    (isLastHovered 状态由行中的显示/隐藏按钮| 控制)

    【讨论】:

    • 我不确定我是否完全理解此解决方案...您介意提供更多有关其工作原理的详细信息吗?
    • 什么不清楚? @麦克德普
    【解决方案2】:

    我相信这可能是一种可行的解决方案。通过更多的调整,我认为它可以实现您概述的所需行为。

    这通过使用离开表格点的鼠标坐标从行列表中捕获光标离开表格的最后一个元素。在示例中,退出的元素将保持可见,但您可以决定如何处理它。

    [...table.children[0].children].forEach(tr => {
        tr.classList.remove('exited');
        if(evt.offsetY >= tr.offsetTop 
           && evt.offsetY <= tr.offsetTop + tr.clientHeight
         ){
           tr.classList.add('exited'); // in react you could instead set this element to state.
         }
      });
    

    希望翻译成 JSX 不会成为问题。您可以使用refObject 保留对表的DOM 元素的引用。

    const table = document.getElementById("table");
    let hoverTimer = 0;
    
    table.addEventListener("mouseenter", () => {
      clearTimeout(hoverTimer);
      hoverTimer = setTimeout(() => 
        table.classList.add('active'),
        500
      );
    });
    
    table.addEventListener("mouseleave", (evt) => {
      [...table.children[0].children].forEach(tr => {
        tr.classList.remove('exited');
        if(evt.offsetY >= tr.offsetTop 
           && evt.offsetY <= tr.offsetTop + tr.clientHeight
         ){
           tr.classList.add('exited');
         }
      });
      
      clearTimeout(hoverTimer);
      hoverTimer = setTimeout(() => 
        table.classList.remove('active'),
        500
      );
    });
    tr.table-row button.action-btn {
      pointer-events: none;
    }
    
    table.active tr.table-row:hover button.action-btn {
      pointer-events: auto;
    }
    
    tr.table-row {
      opacity: 0;
      transition: opacity 0.5s;
    }
    
    table.active tr.table-row:hover {
      opacity: 1;
    }
    
    tr.exited {
      opacity: 1;
    }
    <table id="table">
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    <tr class="table-row"><td><button class="action-btn">click me!</button></td></tr>
    </table>

    【讨论】:

      猜你喜欢
      • 2017-09-29
      • 2015-03-19
      • 2020-10-28
      • 2011-05-05
      • 2015-04-25
      • 2018-12-02
      • 2021-11-13
      相关资源
      最近更新 更多