我正在寻找一种方法来让组件渲染它的所有子组件,测量它们的高度,然后根据这些高度修改布局。例如,假设我有一个文档组件,其中包含多个(数量未知(段落组件。我希望文档组件能够测量这些段落,并在分页符所在的位置插入水平线。
布局前:
<Document pageSize="A4" layout="portrait">
<Paragraph text="some long text" />
<Paragraph text="some long text" />
<Paragraph text="some long text" />
<Paragraph text="some long text" />
<Paragraph text="some long text" />
<Paragraph text="some long text" />
</Document>
布局后:
<Document pageSize="A4" layout="portrait">
<Paragraph text="some long text" />
<Paragraph text="some long text" />
<hr /><!-- End of page 1 -->
<Paragraph text="some long text" />
<Paragraph text="some long text" />
<Paragraph text="some long text" />
<hr /><!-- End of page 2 -->
<Paragraph text="some long text" />
</Document>
我可以使用钩子常见问题解答中的useClientRect()
钩子来测量每个段落组件本身,但我不知道如何让文档组件访问该高度。任何建议将不胜感激!
我还想澄清一下,我希望在屏幕上提供有关打印时分页符位置的视觉反馈,类似于Google Docs或MS Word提供的反馈。
这个问题让我彻夜难眠。但我想我找到了一个应该适合你的解决方案。
本质上,您需要为每个Paragraph
组件提供一个ref
.ref
将包含有关整个组件高度的信息。然后,您只需将该高度备份传递给包含Document
组件的Parent
组件。
从段落中收到所有高度后,您可以计算一个runningHeight
以动态添加您的PageBreaks
。在这种情况下,分页符只是在每个Paragraph
组件中按条件添加的<hr>
标记。
请参阅工作沙盒:https://codesandbox.io/s/dynamically-adding-pagebreaks-fjvfl
主代码:
应用.js
import React from "react";
import ReactDOM from "react-dom";
import Document from "./Document";
import Paragraph from "./Paragraph";
import data from "./data.js";
import "./styles.css";
class App extends React.Component {
state = {
pageBreak: 500,
heights: [],
breaks: []
};
updateHeight = height => {
this.setState(
prevState => {
return {
heights: [...prevState.heights, height]
};
},
() => {
this.setBreaks();
}
);
};
setBreaks = () => {
const { heights, pageBreak } = this.state;
const breaks = [];
let runningHeights = [];
let runningHeight = 0;
heights.forEach((height, index) => {
if (index === 0) {
runningHeight = height;
runningHeights.push(runningHeight);
if (runningHeight >= pageBreak) {
breaks.push(true);
} else {
breaks.push(false);
}
} else if (index > 0) {
if (runningHeights[index - 1] < pageBreak) {
runningHeight = runningHeights[index - 1] + height;
runningHeights.push(runningHeight);
if (runningHeight >= pageBreak) {
breaks.push(true);
} else {
breaks.push(false);
}
} else {
runningHeight = height;
runningHeights.push(runningHeight);
if (runningHeight >= pageBreak) {
breaks.push(true);
} else {
breaks.push(false);
}
}
}
});
this.setState({
breaks: breaks
});
};
render() {
const { breaks } = this.state;
return (
<div className="App">
<Document>
{data.map((item, index) => {
return (
<Paragraph
text={item.text}
updateHeight={this.updateHeight}
break={breaks[index]}
/>
);
})}
</Document>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
段.js
import React, { useEffect } from "react";
const Paragraph = ({ text, updateHeight, ...props }) => {
const paragraphRef = React.createRef();
useEffect(() => {
updateHeight(paragraphRef.current.offsetHeight);
}, []);
return (
<div ref={paragraphRef}>
{text} {props.break && <hr />}
</div>
);
};
export default Paragraph;
文档.js
import React from "react";
const Document = props => {
return <div>{props.children}</div>;
};
export default Document;
我最近使用以下代码做了类似的事情。我没有设置标准页面大小和插入 HR,而是让一堆磁贴将它们的高度设置为相同。但是,它可能会为您指明正确的方向...
export const standardiseTiles = (className) => {
const nodes = [...document.getElementsByClassName(className)];
nodes.forEach(n => {
n.style.height = 'auto';
});
const maxHeight = nodes.reduce((p, c) => {
return c.clientHeight > p ? c.clientHeight : p;
}, 0);
nodes.forEach(n => {
n.style.height = `${maxHeight}px`;
});
};
我在组件DidUpdate中调用它,传递父容器的类名。
不完美,但它正在工作。
希望对您有所帮助!