基本上我希望能够检测反应组件是否有溢出的子项。就像在this question中一样。我发现使用ReactDOM可以做同样的事情,但是i cannot/should not use ReactDOM。我没有在建议的替代方案ref
上看到任何相同内容。
所以我需要知道的是,在这些条件下是否有可能检测到反应组分内的溢出。同样,是否可以检测宽度?
答案 0 :(得分:9)
除了@ jered的优秀答案之外,我还想提一下限定符,如果ref直接放在上,ref只会返回一个直接访问常规DOM元素的各种属性的元素。 DOM元素。也就是说,组件不会以这种方式运行。
所以,如果你像我一样,并拥有以下内容:
var MyComponent = React.createClass({
render: function(){
return <SomeComponent id="my-component" ref={(el) => {this.element = el}}/>
}
})
当您尝试访问this.element
的DOM属性(可能在componentDidMount
或componentDidUpdate
中)并且您没有看到所述属性时,以下内容可能是适合您的替代方案
var MyComponent = React.createClass({
render: function(){
return <div ref={(el) => {this.element = el}}>
<SomeComponent id="my-component"/>
</div>
}
})
现在您可以执行以下操作:
componentDidUpdate() {
const element = this.element;
// Things involving accessing DOM properties on element
// In the case of what this question actually asks:
const hasOverflowingChildren = element.offsetHeight < element.scrollHeight ||
element.offsetWidth < element.scrollWidth;
},
答案 1 :(得分:3)
是的,您可以使用ref
。
详细了解ref
在官方文档中的运作方式:https://facebook.github.io/react/docs/refs-and-the-dom.html
基本上,ref
只是在组件第一次呈现时,在调用componentDidMount
之前运行的回调。回调中的参数是调用ref
函数的DOM元素。所以,如果你有这样的事情:
var MyComponent = React.createClass({
render: function(){
return <div id="my-component" ref={(el) => {this.domElement = el}}>Hello World</div>
}
})
当MyComponent
挂载时,它会调用将ref
设置为DOM元素this.domElement
的{{1}}函数。
有了这个,使用像#my-component
这样的东西来渲染DOM元素并确定子元素是否溢出父元素是相当容易的:
https://jsbin.com/lexonoyamu/edit?js,console,output
请记住,在呈现之前无法测量DOM元素的大小/溢出量,因为根据定义它们尚不存在。在将其渲染到屏幕之前,您无法测量某物的宽度/高度。
答案 2 :(得分:1)
对于任何想知道如何使用钩子和useRef做到这一点的人:
// This is custom effect that calls onResize when page load and on window resize
const useResizeEffect = (onResize, deps = []) => {
useEffect(() => {
onResize();
window.addEventListener("resize", onResize);
return () => window.removeEventListener("resize", onResize);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [...deps, onResize]);
};
const App = () => {
const [isScrollable, setIsScrollable] = useState(false);
const [container, setContainer] = useState(null);
// this has to be done by ref so when window event resize listener will trigger - we will get the current element
const containerRef = useRef(container);
containerRef.current = container;
const setScrollableOnResize = useCallback(() => {
if (!containerRef.current) return;
const { clientWidth, scrollWidth } = containerRef.current;
setIsScrollable(scrollWidth > clientWidth);
}, [containerRef]);
useResizeEffect(setScrollableOnResize, [containerRef]);
return (
<div
className={"container" + (isScrollable ? " scrollable" : "")}
ref={(element) => {
if (!element) return;
setContainer(element);
const { clientWidth, scrollWidth } = element;
setIsScrollable(scrollWidth > clientWidth);
}}
>
<div className="content">
<div>some conetnt</div>
</div>
</div>
);
};
答案 3 :(得分:0)
@Jemar Jones提出的解决方案的实施:
export default class OverflowText extends Component {
constructor(props) {
super(props);
this.state = {
overflowActive: false
};
}
isEllipsisActive(e) {
return e.offsetHeight < e.scrollHeight || e.offsetWidth < e.scrollWidth;
}
componentDidMount() {
this.setState({ overflowActive: this.isEllipsisActive(this.span) });
}
render() {
return (
<div
style={{
width: "145px",
textOverflow: "ellipsis",
whiteSpace: "nowrap",
overflow: "hidden"
}}
ref={ref => (this.span = ref)}
>
<div>{"Triggered: " + this.state.overflowActive}</div>
<span>This is a long text that activates ellipsis</span>
</div>
);
}
}
答案 4 :(得分:0)
同样可以使用 React 钩子来实现:
你需要的第一件事是一个状态,它包含 text open 和 overflow active 的布尔值:
const [textOpen, setTextOpen] = useState(false);
const [overflowActive, setOverflowActive] = useState(false);
接下来,您需要对要检查是否溢出的元素进行引用:
const textRef = useRef();
<p ref={textRef}>
Some huuuuge text
</p>
接下来是一个检查元素是否溢出的函数:
function isOverflowActive(event) {
return event.offsetHeight < event.scrollHeight || e.offsetWidth < e.scrollWidth;
}
然后你需要一个 useEffect 钩子来检查上面的函数是否存在溢出:
useEffect(() => {
if (isOverflowActive(reviewTextRef.current)) {
setOverflowActive(true);
return;
}
setOverflowActive(false);
}, [isOverflowActive]);
现在有了这两个状态和一个检查溢出元素是否存在的函数,你可以有条件地渲染一些元素(例如显示更多按钮):
{!textOpen && !overflowActive ? null : (
<button>{textOpen ? 'Show less' : 'Show more'}</button>
)}