Popover 没有出现在 React 中

Pha*_*aki 8 html javascript popover reactjs treeviz-react

我正在尝试制作一个具有 Treeviz 依赖项的 Web 应用程序。目标是在树的每个节点上放置一个弹出按钮,如果用户单击该按钮,他/她可以看到该节点的描述,并且之后应该可以编辑。我尝试了很多方法,但对我来说,弹出窗口在 React 中不起作用。

有一个我想做的例子。你可以看到我必须将 React 组件插入 HTML,因为我正在使用 renderToString。您只需查看树的 renderNode 属性即可。我引用 renderNode 中的 React 组件,例如:${tooltip} ${popover}。

import React from "react";
import { TreevizReact } from "treeviz-react";
import { renderToString } from "react-dom/server";
const data_1 = [
  {
    id: 1,
    text_1: "Chaos",
    description: "Void",
    father: null,
    color: "#FF5722"
  },
  {
    id: 2,
    text_1: "Tartarus",
    description: "Abyss",
    father: 1,
    color: "#FFC107"
  },
  { id: 3, text_1: "Gaia", description: "Earth", father: 1, color: "#8BC34A" },
  { id: 4, text_1: "Eros", description: "Desire", father: 1, color: "#00BCD4" }
];

export const App = () => {
  return (
    <div style={{ marginLeft: 10 }}>
      <div style={{ display: "flex" }}>
        <TreevizReact
          data={data_1}
          relationnalField={"father"}
          nodeWidth={120}
          nodeHeight={80}
          areaHeight={500}
          areaWidth={1000}
          mainAxisNodeSpacing={2}
          secondaryAxisNodeSpacing={2}
          linkShape={"quadraticBeziers"}
          renderNode={(data) => {
            const nodeData = data.data;
            const settings = data.settings;
            let result = "";
            const tooltip = renderToString(
              <strong
                data-toggle="tooltip"
                data-placement="top"
                title={nodeData.description}
              >
                {nodeData.text_1}
              </strong>
            );
            const popover = renderToString(
              <button
                type="button"
                className="btn btn-secondary"
                data-container="body"
                data-toggle="popover"
                data-placement="top"
                data-content={nodeData.description}
              >
                Popover on top
              </button>
            );
            if (data.depth !== 2) {
              result = `<div className="box" 
              style='cursor:pointer;height:${settings.nodeHeight}px; width:${settings.nodeWidth}px;display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:${nodeData.color};border-radius:5px;'>
              <div>
          ${tooltip}
          ${popover}
          </div></div>`;
            } else {
              result = `<div className="box" style='cursor:pointer;height:${
                settings.nodeHeight
              }px; width:${
                settings.nodeHeight
              }px;display:flex;flex-direction:column;justify-content:center;align-items:center;background-color:${
                nodeData.color
              };border-radius:${settings.nodeHeight / 2}px;'><div><strong>
          ${nodeData.text_1}
          </strong></div></div>`;
            }
            return result;
          }}
          duration={600}
          isHorizontal
          linkWidth={(node) => 10}
        />
      </div>
    </div>
  );
};
export default App;

Run Code Online (Sandbox Code Playgroud)

工具提示正常工作,但弹出窗口未显示。 在此输入图像描述

您可以尝试一下:https://codesandbox.io/s/zealous-orla-4bq5f ?file=/src/App.js

也尝试过

const popover = renderToString(
              <Popup
                trigger={<button> Trigger</button>}
                position="right center"
              >
                <form onSubmit={saveHandler}>
                  <ContentEditable
                    html={text.current}
                    onChange={handleChange}
                  />
                  <button type="submit">Save</button>
                  <button>Cancel</button>
                </form>
              </Popup>
Run Code Online (Sandbox Code Playgroud)
const popoverContent = (
              <Popover id="popover-basic">
                <Popover.Header as="h3">Popover right</Popover.Header>
                <Popover.Body>
                  And here's some <strong>amazing</strong> content. It's very
                  engaging. right?
                </Popover.Body>
              </Popover>
            );

            const popover = renderToString(
              <OverlayTrigger
                trigger="click"
                placement="right"
                overlay={popoverContent}
              >
                <Button variant="success">Click me to see</Button>
              </OverlayTrigger>
            );
Run Code Online (Sandbox Code Playgroud)

他们都不为我工作。

die*_*edu 2

您的方法可能不起作用,因为树中的 dom 元素是动态创建的,并且bootstrap 不会设置它们

一种更具反应性的方法是使用react-bootstrap lib并管理状态中的每个UI方面。为了实现工具提示,该Overlay组件实际上是一个名为 target 的 prop,它允许您更改工具提示显示的元素。

    <Overlay target={tooltipTarget} show={showTooltip} placement="right">
      {(props) => (
        <Tooltip id="overlay-example" {...props}>
          {tooltipNode?.data.text_1}
        </Tooltip>
      )}
    </Overlay>
Run Code Online (Sandbox Code Playgroud)

然后你只需要在组件中管理所有这些状态onNodeMouseEnter和处理程序。onNodeMouseLeaveTreevizReact

        onNodeMouseEnter={(_event, node) => {
          const t = document.querySelector(`#node-${node.id}`);
          setTooltipTarget(t);
          setShowTooltip(true);
          setTooltipNode(node);
        }}
        onNodeMouseLeave={(_event, node) => {
          setTooltipTarget(null);
          setShowTooltip(false);
          setTooltipNode(null);
        }}
Run Code Online (Sandbox Code Playgroud)

弹出窗口与另一组状态遵循相同的逻辑。

  <div ref={ref}>
    <Overlay
      show={!!selectedNode.current}
      target={target}
      placement="bottom"
      container={ref.current}
      containerPadding={20}
    >
      <Popover id="popover-contained">
        {/* hack to avoid weird blinking (due mutable state) */}
        {!!selectedNode.current && (
          <>
            some form based on node data
            {JSON.stringify(selectedNode.current?.data)}
          </>
        )}
      </Popover>
    </Overlay>
  </div>
Run Code Online (Sandbox Code Playgroud)

并在 onNodeClick 处理程序中

        onNodeClick={(_event, node) => {
          const t = document.querySelector(`#node-${node.id}`);
          // unselect if already selected
          if (selectedNode.current?.id === node.id) {
            selectedNode.current = null;
            setTarget(null);
          } else {
            selectedNode.current = node;
            setTarget(t);
          }
        }}
Run Code Online (Sandbox Code Playgroud)

你可能会注意到这次我通过 ref ( selectedNode.current) 使用了一个可变变量,出于某种原因使用状态导致了一些问题,可能是由于 D3 和 React 具有不同的渲染周期,这就是为什么你可能会在此实现中遇到一些其他故障的原因。

https://codesandbox.io/s/quizzical-buck-slofh?file=/src/App.js