使用 React 在图像上放置交互式标记
P粉896751037
P粉896751037 2023-09-08 21:25:41
0
1
816

请帮忙。 我有一个像下图这样的图像显示在主页上(一个更大的图像)。 请注意,“FORGE”房屋的中间有一个白色和蓝色标记,并带有黑色箭头

“出租”房屋也是如此。

这些标记中的每一个都将充当交互式按钮。以下是预期的交互行为:

  • 将鼠标悬停时,蓝色背景将展开以显示“Forge”或“Rentals”等文本
  • 点击后,它将引导用户前往相应的“Forge”或“Rentals”页面。

还希望它能够响应,如果当屏幕调整大小时,按钮应保留在这些特定位置。

我正在尝试使用绝对定位、x、y 坐标来尝试使其工作。但由于我喜欢此类用户界面的经验,无法找到可行的解决方案。不确定我是否应该使用画布或其他方法。

任何帮助将不胜感激。

我的代码看起来像这样,但看起来我没有走在正确的轨道上:

const ImageComponent = () => {

  const markers = [
    { name: 'Forge', x: 100, y: 200 },
    { name: 'Rentals', x: 300, y: 150 },
    // Add more 
  ];

  const handleMarkerClick = (m) => {
    // do something with marker
  };

  return (
    <div style={{ position: 'relative' }}>
      <img src="path/to/image.jpg" alt="Image with markers" />

      {markers.map((marker, index) => (
        <div
          key={index}
          className="marker"
          style={{ left: marker.x, top: marker.y, position: "absolute" }}
          onClick={() => handleMarkerClick(marker)}
        />
      ))}
    </div>
  );
};

P粉896751037
P粉896751037

全部回复(1)
P粉412533525

您应该将控件放置在图像容器的绝对位置。 实现取决于多种因素,例如图像放置的位置、是否全屏显示、图像之前或之后是否有内容等。 但这段代码应该向您展示主要原理。

如果在调整窗口大小时调整图像大小,则应该创建一个与图像完全相同的容器。然后,您可以设置控件相对于该容器的位置,并使它们固定在各自的点上。

.container {
  width: 60vw; /* set 100vw to fit image window width*/
  position: relative;
}
.container img { width: 100%; display: block;}
.container .control {
  position: absolute;
  width: 7.5%;  /* size in percents to resize controls with image */
  height: 7%;
  border-radius: 200px;
  background: red;
  transition: all 0.2s ease-in-out;
}

.container .control:hover {
  width: 20%;
}

#c1 { left: 50.4%; top: 26%; } /* position in percents, not in pixels */
#c2 { left: 58.5%; top: 76.3%; }
<div class="container">
  <img src="https://i.stack.imgur.com/BVaY9.jpg"/>
  <div class="control" id="c1"></div>
  <div class="control" id="c2"></div>
</div>

使用你的代码,它会是这样的(但我建议在样式文件中移动你的样式,学习如何在react中使用模块样式):

const ImageComponent = () => {

  const markers = [
    { name: 'Forge', x: 50.4, y: 26 },
    { name: 'Rentals', x: 58.5, y: 76.3 },
    // Add more 
  ];

  const handleMarkerClick = (m) => {
    // do something with marker
  };

  return (
    <div style={{ position: 'relative', width: '100vw' }}>
      <img style={{ width: '100%', display: 'block'}} src="path/to/image.jpg" alt="Image with markers" />

      {markers.map((marker, index) => (
        <div
          key={index}
          className="marker"
          style={{ left: `${marker.x}%`, top: `${marker.y}%`, position: "absolute" }}
          onClick={() => handleMarkerClick(marker)}
        />
      ))}
    </div>
  );
};

只需修复位置并添加正常的控制视图即可。

为了进行控制,您应该制作单独的组件。以下是如何实现您想要的行为的示例:

.control {
  background: #08f;
  padding: 10px;
  width: 60px;
  box-sizing: border-box;
  border-radius: 200px;
  transition: all 0.2s ease-in-out;
  display: flex;
  align-items: center;
  overflow: hidden;
  cursor: pointer;
}

.control:hover {
  width: 200px;
}

.text {
  color: white;
  font: 30px Arial;
  margin-left: 16px;
  opacity: 0;
  transition: opacity 0.2s ease-in-out;
}

.control:hover .text {
  opacity: 1;
}

.icon {
  width: 40px;
  min-width: 40px;
  height: 40px;
  border-radius: 50%;
  box-shadow: 2px 2px 7px #0005;
  background-color: white;
  background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pgo8IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPgo8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPgo8c3ZnIGZpbGw9IiMwMDAwMDAiIGhlaWdodD0iODAwcHgiIHdpZHRoPSI4MDBweCIgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiAKCSB2aWV3Qm94PSIwIDAgMjk3IDI5NyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxnPgoJPHBhdGggZD0iTTI5NC4wNzcsMjUxLjE5OWwtNTkuMTA1LTU5LjEwN2w0Mi4xNjctMjQuMzU2YzMuMjk1LTEuOTAzLDUuMjEyLTUuNTIsNC45MzgtOS4zMTVjLTAuMjc0LTMuNzk2LTIuNjkyLTcuMTAxLTYuMjI2LTguNTEKCQlMODcuODIsNzQuOTA1Yy0zLjY4Ni0xLjQ3Mi03Ljg5NS0wLjYwNS0xMC43MDIsMi4yMDFjLTIuODA3LDIuODA4LTMuNjc0LDcuMDE2LTIuMjAzLDEwLjcwMmw3NC45OTQsMTg4LjA1MwoJCWMxLjQxLDMuNTM0LDQuNzE1LDUuOTUzLDguNTExLDYuMjI3YzMuNzk2LDAuMjc2LDcuNDE0LTEuNjQyLDkuMzE2LTQuOTM4bDI0LjM1NC00Mi4xNjdsNTkuMTAxLDU5LjEwNwoJCWMxLjg2MiwxLjg2Myw0LjM5LDIuOTEsNy4wMjMsMi45MWMyLjYzNSwwLDUuMTYxLTEuMDQ3LDcuMDIzLTIuOTFsMjguODQxLTI4Ljg0NUMyOTcuOTU2LDI2MS4zNjYsMjk3Ljk1NiwyNTUuMDc4LDI5NC4wNzcsMjUxLjE5OQoJCXoiLz4KCTxwYXRoIGQ9Ik00My42MSwyOS41NTJjLTMuODc5LTMuODc2LTEwLjE2Ni0zLjg3Ny0xNC4wNDcsMGMtMy44NzgsMy44NzktMy44NzgsMTAuMTY4LDAsMTQuMDQ3bDIyLjA2OSwyMi4wNjkKCQljMS45MzksMS45MzksNC40OCwyLjkwOSw3LjAyMywyLjkwOWMyLjU0MSwwLDUuMDgzLTAuOTcsNy4wMjItMi45MDljMy44NzktMy44NzksMy44NzktMTAuMTY3LDAtMTQuMDQ2TDQzLjYxLDI5LjU1MnoiLz4KCTxwYXRoIGQ9Ik01MS4wODksOTguMjE1YzAtNS40ODQtNC40NDctOS45MzItOS45MzMtOS45MzJIOS45NDZjLTUuNDg1LDAtOS45MzMsNC40NDctOS45MzMsOS45MzJjMCw1LjQ4NSw0LjQ0Nyw5LjkzMyw5LjkzMyw5LjkzMwoJCWgzMS4yMUM0Ni42NDIsMTA4LjE0Nyw1MS4wODksMTAzLjcsNTEuMDg5LDk4LjIxNXoiLz4KCTxwYXRoIGQ9Ik00Ny4wNjMsMTI4Ljg2OWwtMjIuMDcyLDIyLjA3MWMtMy44NzgsMy44NzktMy44NzgsMTAuMTY4LDAsMTQuMDQ2YzEuOTQsMS45MzksNC40ODIsMi45MDksNy4wMjMsMi45MDkKCQljMi41NDEsMCw1LjA4NC0wLjk3LDcuMDIzLTIuOTA5bDIyLjA3MS0yMi4wN2MzLjg3OS0zLjg3OSwzLjg3OS0xMC4xNjgsMC0xNC4wNDdDNTcuMjMsMTI0Ljk5Myw1MC45NDQsMTI0Ljk5Miw0Ny4wNjMsMTI4Ljg2OXoiLz4KCTxwYXRoIGQ9Ik05OC4yMjIsNTEuMDc4YzUuNDg1LDAsOS45MzMtNC40NDcsOS45MzMtOS45MzNWOS45MzJjMC01LjQ4NS00LjQ0Ny05LjkzMi05LjkzMy05LjkzMmMtNS40ODQsMC05LjkzMiw0LjQ0Ni05LjkzMiw5LjkzMgoJCXYzMS4yMTRDODguMjksNDYuNjMxLDkyLjczNyw1MS4wNzgsOTguMjIyLDUxLjA3OHoiLz4KCTxwYXRoIGQ9Ik0xMzUuODk0LDY0LjAwNmMyLjU0MywwLDUuMDg0LTAuOTcsNy4wMjMtMi45MDlsMjIuMDY4LTIyLjA2OWMzLjg3OS0zLjg3OSwzLjg3OS0xMC4xNjgsMC0xNC4wNDcKCQljLTMuODc5LTMuODc3LTEwLjE2OC0zLjg3Ny0xNC4wNDYsMGwtMjIuMDY4LDIyLjA3Yy0zLjg3OSwzLjg3OS0zLjg3OSwxMC4xNjgsMCwxNC4wNDYKCQlDMTMwLjgxMSw2My4wMzYsMTMzLjM1Miw2NC4wMDYsMTM1Ljg5NCw2NC4wMDZ6Ii8+CjwvZz4KPC9zdmc+');
  background-size: 60%;
  background-repeat: no-repeat;
  background-position: center;
}
<div class="control">
  <div class="icon"></div>
  <div class="text">Home</div>
</div>
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板