首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在React中创建可调整大小的组件

如何在React中创建可调整大小的组件
EN

Stack Overflow用户
提问于 2020-03-21 19:23:44
回答 1查看 2.1K关注 0票数 1

就像标题里说的。我想要创建一个React组件,这样我就可以通过拖动来调整宽度-就像windows操作系统中的窗口一样。处理这个问题的最佳方法实际上是什么?

编辑

我把我目前处理这一问题的方法包括在内:

首先,我在容器的右上角放置了一个"dragger“元素。当我按下该元素上的鼠标时,我希望创建一个mousemove事件侦听器,它将修改光标相对于容器边缘的初始X位置的X坐标的containerWidth。我已经让事件侦听器在按住鼠标按钮后向我发送并记录坐标,但不幸的是,由于某种原因,事件在鼠标未按下(mouseUp事件)后没有被移除,这不是我想要的。任何值得赞赏的建议,也是那些关于一些问题,我可能期待在未来与这个议题有关。谢谢。

代码语言:javascript
运行
复制
type Props = MasterProps & LinkStateToProps & LinkDispatchToProps;
const Test3 = (Props: Props) => {

  const [containerWidth, setContainerWidth] = React.useState(640)
  const [isBeingStretched, setIsBeingStretched] = React.useState(false);
  const masterRef = React.useRef(null);


  const logMousePosition = React.useCallback((event:MouseEvent)=>{
    console.log(event.clientX);
  },[])


  const handleMouseDown=()=>{
    document.addEventListener('mousemove', logMousePosition);
    masterRef.current.addEventListener('mouseup', ()=>{
      document.removeEventListener('mouseup', logMousePosition)
    })
  }
  const handleMouseUp = () => { 
    document.removeEventListener('mousemove', logMousePosition);
  }
  return (
    <div className="master-wrapper" ref={masterRef}>
      <div className="stretchable-div" style={{ width: `${containerWidth}px` }}>
        <div className="dragger-wrapper">
          <h2>This is supposed to change width</h2>
          <div className="dragger"
            id="dragger"
            onMouseDown={handleMouseDown}
            onMouseUp={handleMouseUp}/>
        </div>
      </div>

    </div>
  );

}

export default connect(mapStateToProps, mapDispatchToProps)(Test3);
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-03-21 23:25:07

我以前从来没有做过这样的事情,所以我决定试一试,最后用React状态管理来实现它是非常简单的。我明白为什么如果你是新的反应者,你可能不知道从哪里开始,这没关系,尽管在我讨论我的解决方案之前,有两件事要注意:

  1. document.getElementByIddocument.addEventListener这样的语句将不再按预期工作。使用React,您将操作一个虚拟DOM,它将为您更新实际的DOM,您应该尽可能让它这样做。
  2. 使用refs来回避这一事实是错误的做法。他们的行为可能与上面提到的陈述相似,但这不是他们的意图用例。阅读文档ref良好用例的看法。

下面是我演示的JSX部分的样子:

代码语言:javascript
运行
复制
return (
    <div className="container" onMouseMove={resizeFrame} onMouseUp={stopResize}>
      <div className="box" style={boxStyle}>
        <button className="dragger" onMouseDown={startResize}>
          Size Me
        </button>
      </div>
    </div>
  );

我们需要三个不同的事件- onMouseDownonMouseMoveonMouseUp -来跟踪调整大小的不同阶段。你自己的代码已经有这么多了。在React中,我们将所有这些声明为元素本身的属性,尽管它们实际上不是行内函数。React将它们添加为后台的事件侦听器。

代码语言:javascript
运行
复制
const [drag, setDrag] = useState({
    active: false,
    x: "",
    y: ""
});

const startResize = e => {
    setDrag({
      active: true,
      x: e.clientX,
      y: e.clientY
    });
};

我们将使用一些状态来跟踪正在进行的调整大小。为了避免膨胀并使其更具可读性,我将所有东西浓缩到一个对象中,尽管如果您有依赖于该状态的其他挂钩(如useEffectuseMemo ),则这并不总是理想的。第一个事件只保存用户鼠标的初始x和y位置,并为下一个要引用的事件设置为true。

代码语言:javascript
运行
复制
const [dims, setDims] = useState({
    w: 200,
    h: 200
});

const resizeFrame = e => {
    const { active, x, y } = drag;
    if (active) {
      const xDiff = Math.abs(x - e.clientX);
      const yDiff = Math.abs(y - e.clientY);
      const newW = x > e.clientX ? dims.w - xDiff : dims.w + xDiff;
      const newH = y > e.clientY ? dims.h + yDiff : dims.h - yDiff;

      setDrag({ ...drag, x: e.clientX, y: e.clientY });
      setDims({ w: newW, h: newH });
    }
};

第二种状态将初始化元素,并在其值变化时更新元素的维度。这可以使用您想要的任何度量,尽管它必须与某些CSS属性相关。

resizeFrame函数执行以下操作:

  1. 通过销毁赋值,使drag的属性易于获得。这将使代码更易读,更易于键入。
  2. 检查调整大小是否处于活动状态。onMouseMove会为鼠标移动到相关元素上的每个像素触发,因此我们希望确保它是适当的条件。
  3. 使用Math.abs()作为正整数获取当前鼠标位置和保存的鼠标位置之间的差值。这将使我们不必执行第二轮条件语句。
  4. 根据新的鼠标位置是否大于或小于任何一个轴上的新位置,使用循环语句添加或减去维度之间的差异。
  5. 使用新值设置状态,使用spread运算符...drag的不相关部分保留下来。
代码语言:javascript
运行
复制
const stopResize = e => {
    setDrag({ ...drag, active: false });
};

const boxStyle = {
    width: `${dims.x}px`,
    height: `${dims.y}px`
};

然后,我们简单地将用户完成后拖动状态的活动设置为false。JS样式的对象被传递给元素,状态变量在适当的位置,以便自动处理。

这是完成效果的码箱

这样做的缺点之一是,它基本上要求将mouseMove事件侦听器分配给最大的站点容器,因为在调整大小时,鼠标不会停留在框的范围内。如果您想要拥有具有相同功能的多个元素,那么这可能是一个问题,尽管在良好的状态管理下没有什么是无法解决的。您可能可以对此进行微调,以便鼠标始终停留在拖放元素上,尽管这需要更复杂的实现。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60792300

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档