reactjs - 使用 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
这是我的代码:
- 我的编辑器和框架组件在哪里
- 我的渲染节点
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 ..?
解决方案
推荐阅读
- bash - bash脚本中的xset不起作用
- winforms - 需要在 Powershell 中创建、使用和存储动态对象名称
- javascript - 在 Google Script 自定义对话框中创建下拉菜单,其中包含来自 Google Sheet 中数据的选项
- python - 使用 openpyxl 导出数据框时的空行
- php - Take parts of two separate arrays and combine them into one
- android - 共享临时图像
- java - Firestore 数据库模型、文档或子集合中的属性
- php - 即使使用 unset 方法刷新页面时重新提交表单
- java - Spring中的动态依赖注入
- css - CSS 变量:Sugar 语法存在吗?