首页 > 解决方案 > 使用 div 渲染元素(绝对位置、顶部、右侧、底部、左侧),获取 de screenPositions 以了解渲染位置。如何听滚动?

问题描述

我正在使用 Craft.js 构建 FrontPage 构建器。您可以将组件滑动到 Frame 组件中,以将它们添加到您的页面中,如下所示。

<Editor onRender={SettingsBarHover}><Frame>{useComponents}</Frame></Editor>

编辑器有一个 onRender 属性,它提供了使用附加组件渲染框架内的每个 useComponent 的可能性。

我想用 SettingsBarHover 渲染它,当组件被选中或 onHover 时,它在 useComponent 的顶部可见。类似于下面的示例图像:

在此处输入图像描述

一切正常,直到我滚动页面。怎么办?有一个例子,但它是使用 TypeScript 的,当我看到所有代码并寻找一个简单的解释时,我会感到困惑:

整个应用程序: https ://github.com/prevwong/craft.js/tree/master/packages/examples/landing

其中和组件是: https ://github.com/prevwong/craft.js/blob/master/packages/examples/landing/pages/index.tsx

RenderNode 组件在哪里: https://github.com/prevwong/craft.js/blob/master/packages/examples/landing/pages/index.tsx

这是我的代码:

  1. 我的编辑器和框架组件在哪里
  2. 我的渲染节点

import React from "react";
import { Typography, Paper } from "@material-ui/core";
import { TopbarBuild } from "./EditorComponents/TopbarBuild";
import ContainerBuild from "./UserComponents/ContainerBuild";
import { CardBuild, CardTopBuild, CardBottomBuild } from "./UserComponents/CardBuild";
import { ButtonBuild } from "./UserComponents/ButtonBuild";
import { TextBuild } from "./UserComponents/TextBuild";
import { ToolboxBuild } from "./EditorComponents/ToolboxBuild";
import Card from "../Card/Card";
import CardBody from "../Card/CardBody";
import { Editor, Frame, Element } from "@craftjs/core";
import withStyles from "@material-ui/core/styles/withStyles";
import BuilderAppStyles from "../../assets/jss/material-dashboard-pro-react/components/BuilderAppStyles";
import SettingsBarHover from "./EditorComponents/SettingsBarHover";
import { PanelBuild } from "./EditorComponents/Panels/PanelBuild";
import { ButtonAfhalenBuild } from "./UserComponents/ButtonAfhalenBuild";
import { ImageBuild } from "./UserComponents/ImageBuild";

function BuilderApp({ classes }) {
  return (
    <Card>
      <CardBody>
        <div style={{ margin: "0 auto", width: "100%", height: "800px" }}>
          <Typography variant="h5" align="center">
            A super simple page editor
          </Typography>
          <TopbarBuild />
          <Editor
            resolver={{
              CardBuild,
              CardTopBuild,
              CardBottomBuild,
              ButtonBuild,
              ButtonAfhalenBuild,
              TextBuild,
              ImageBuild,
              ContainerBuild,
            }}
            onRender={SettingsBarHover}
            enabled={true}
          >
            <div style={{ display: "flex", direction: "row" }}>
              <div style={{ display: "inline", width: "5%" }}>
                <Paper square>
                  <ToolboxBuild />
                </Paper>
              </div>
              <div className={"craftjs-renderer"} style={{ display: "inline", width: "75%" }}>
                <Paper square>
                  <Frame>
                    <Element
                      canvas
                      is={ContainerBuild}
                      name={"Page"}
                      height={"600px"}
                      flexDirection={"row"}
                      backgroundImage={"true"}
                      imageSource={"https://www.leza.nl/wp-content/uploads/2019/10/Jamezz-mobiel.jpg"}
                    />
                  </Frame>
                </Paper>
              </div>
              <div style={{ display: "inline", width: "20%" }}>
                <PanelBuild />
              </div>
            </div>
          </Editor>
        </div>
      </CardBody>
    </Card>
  );
}

export default withStyles(BuilderAppStyles)(BuilderApp);

import React, { useCallback, useEffect, useRef } from "react";
import BuilderAppStyles from "../../../assets/jss/material-dashboard-pro-react/components/BuilderAppStyles";
import withStyles from "@material-ui/core/styles/withStyles";
import Grid from "@material-ui/core/Grid";
import { Tooltip } from "@material-ui/core";
import EditIcon from "@material-ui/icons/Edit";
import LayersIcon from "@material-ui/icons/Layers";
import DeleteForeverIcon from "@material-ui/icons/DeleteForever";
import Divider from "@material-ui/core/Divider";
import DragIndicatorIcon from "@material-ui/icons/DragIndicator";
import { useEditor, useNode } from "@craftjs/core";

const SettingsBarHover = ({ render }) => {
  const { actions, selected } = useEditor((state, query) => {
    const currentNodeId = state.events.selected;
    let selected;
    if (currentNodeId) {
      selected = {
        id: currentNodeId,
        name: state.nodes[currentNodeId].data.props.name,
        settings: state.nodes[currentNodeId].related && state.nodes[currentNodeId].related.settings,
        isDeletable: query.node(currentNodeId).isDeletable(),
        descendants: query.node(currentNodeId).descendants(),
      };
    }
    return {
      selected,
    };
  });
  const { id, isActive, isHover, dom } = useNode((node) => ({
    isActive: node.events.selected,
    isHover: node.events.hovered,
    dom: node.dom,
  }));

  // const currentRef = React.createRef(HTMLDivElement);

  const getPos = useCallback((dom) => {
    const { top, left, bottom } = dom ? dom.getBoundingClientRect() : { top: 0, left: 0, bottom: 0 };
    return {
      top: `${top > 0 ? top : bottom}px`,
      left: `${left}px`,
    };
  }, []);

  const scroll = useCallback(() => {
    // const { current: currentDOM } = currentRef;
    // if (!currentDOM) return;
    // const { top, left } = getPos(dom);
    // currentDOM.style.top = top;
    // currentDOM.style.left = left;
  }, [dom]);

  useEffect(() => {
    window.addEventListener("scroll", scroll);

    return () => {
      window.removeEventListener("scroll", scroll);
    };
  }, [scroll]);

  return (
    <>
      {isActive && (
        <div style={{ position: "absolute", ...getPos(dom) }}>
          <Grid container>
            <Grid item>{selected.name}</Grid>
            <Grid item>
              <Tooltip title={"Edit"}>
                <EditIcon style={{ margin: "3px" }} onClick={() => setShowEditPanel((prevState) => !prevState)} />
              </Tooltip>
            </Grid>
            <Grid item>
              <LayersIcon style={{ margin: "3px" }} onClick={() => setShowLayersPanel((prevState) => !prevState)} />
            </Grid>
            {selected.isDeletable && (
              <Grid item>
                <DeleteForeverIcon
                  style={{ margin: "5px" }}
                  onClick={() => {
                    console.log("onCLick");
                  }}
                />
              </Grid>
            )}
            <Divider orientation={"vertical"} flexItem />
            <Grid item>
              <Tooltip title={"Drag panel"}>
                <DragIndicatorIcon style={{ margin: "3px" }} />
              </Tooltip>
            </Grid>
          </Grid>
        </div>
      )}
      {render}
    </>
  );
};

export default withStyles(BuilderAppStyles)(SettingsBarHover);

我相信我需要使用 RefHook、listenerEvents 和 className 来识别绝对定位的 div 应该相对于的 div ..?

标签: reactjscss-positionuse-refonscrolllistener

解决方案


推荐阅读