我试图创建一个范围输入,在滑块拇指正上方显示工具提示.
我在网上看了一些香草JS的例子,看来我需要有元素的宽度才能完成.
所以我只是想知道如何获得元素宽度?
几乎相当于JQuery方法 $(element).width()
Ric*_*iso 96
class MyComponent extends Component {
constructor(props){
super(props)
this.myInput = React.createRef()
}
componentDidMount () {
console.log(this.myInput.current.offsetWidth)
}
render () {
return (
// new way - as of React@16.3
<div ref={this.myInput}>some elem</div>
// legacy way
// <div ref={(ref) => this.myInput = ref}>some elem</div>
)
}
}
Run Code Online (Sandbox Code Playgroud)
mee*_*ern 33
这基本上是 Marco Antônio 对 React 自定义钩子的回答,但经过修改以最初设置尺寸,而不仅仅是在调整大小之后。
export const useContainerDimensions = myRef => {
const getDimensions = () => ({
width: myRef.current.offsetWidth,
height: myRef.current.offsetHeight
})
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
useEffect(() => {
const handleResize = () => {
setDimensions(getDimensions())
}
if (myRef.current) {
setDimensions(getDimensions())
}
window.addEventListener("resize", handleResize)
return () => {
window.removeEventListener("resize", handleResize)
}
}, [myRef])
return dimensions;
};
Run Code Online (Sandbox Code Playgroud)
以同样的方式使用:
const MyComponent = () => {
const componentRef = useRef()
const { width, height } = useContainerDimensions(componentRef)
return (
<div ref={componentRef}>
<p>width: {width}px</p>
<p>height: {height}px</p>
<div/>
)
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*nio 30
实际上,最好在自定义 hook 中隔离此调整大小逻辑。您可以像这样创建自定义钩子:
const useResize = (myRef) => {
const [width, setWidth] = useState(0)
const [height, setHeight] = useState(0)
useEffect(() => {
const handleResize = () => {
setWidth(myRef.current.offsetWidth)
setHeight(myRef.current.offsetHeight)
}
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
}, [myRef])
return { width, height }
}
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样使用它:
const MyComponent = () => {
const componentRef = useRef()
const { width, height } = useResize(componentRef)
return (
<div ref={myRef}>
<p>width: {width}px</p>
<p>height: {height}px</p>
<div/>
)
}
Run Code Online (Sandbox Code Playgroud)
Nel*_*elu 14
带挂钩:
const MyComponent = () => {
const ref = useRef(null);
useEffect(() => {
const width = ref.current ? ref.current.offsetWidth : 0;
console.log('width', width);
}, [ref.current]);
return <div ref={ref}>Hello</div>;
};
Run Code Online (Sandbox Code Playgroud)
Tha*_*you 13
2023 年 React 18.x
\n出于充分的理由,React 18 改变了useEffect工作方式。为组件运行一次初始化代码是有效的,但请阅读You might not need aneffect beforereach for useEffect。要获取元素的尺寸,我们可以使用新的useSyncExternalStore钩子 -
// useDimensions.js\n\nimport { useMemo, useSyncExternalStore } from "react"\n\nfunction subscribe(callback) {\n window.addEventListener("resize", callback)\n return () => {\n window.removeEventListener("resize", callback)\n }\n}\n\nfunction useDimensions(ref) {\n const dimensions = useSyncExternalStore(\n subscribe,\n () => JSON.stringify({\n width: ref.current?.offsetWidth ?? 0, // 0 is default width\n height: ref.current?.offsetHeight ?? 0, // 0 is default height\n })\n )\n return useMemo(() => JSON.parse(dimensions), [dimensions])\n}\n\nexport { useDimensions }\nRun Code Online (Sandbox Code Playgroud)\n你可以这样使用它 -
\nfunction MyComponent() {\n const ref = useRef(null)\n const {width, height} = useDimensions(ref)\n return <div ref={ref}>\n The dimensions of this div is {width} x {height}\n </div>\n}\nRun Code Online (Sandbox Code Playgroud)\n为什么 JSON.stringify?
\nuseSyncExternalStore期望getSnapshot函数返回一个缓存的值,否则会导致无限的重新渲染。
{width: 300, height: 200} === {width: 300, height: 200}\n// => false \xe2\x9d\x8c\nRun Code Online (Sandbox Code Playgroud)\nJSON.stringify将对象转换为字符串,以便可以建立相等性 -
\'{"width":300,"height":200}\' === \'{"width":300,"height":200}\'\n// => true \xe2\x9c\x85\nRun Code Online (Sandbox Code Playgroud)\n最后,该useMemo钩子确保在后续渲染中返回相同尺寸的对象。当dimensions字符串更改时,备忘录会更新,并且使用的组件useDimensions将重新渲染。
尺寸立即可用
\n这里的其他答案要求用户resize在访问维度之前触发事件。有些人尝试使用内部手动调用来缓解该问题useEffect,但是这些解决方案在 React 18 中失败。使用 的解决方案并非useSyncExternalState如此。享受在第一次渲染时立即访问尺寸的乐趣!
打字稿
\n这是useDimensions打字稿用户的钩子 -
import { RefObject, useMemo, useSyncExternalStore } from "react"\n\nfunction subscribe(callback: (e: Event) => void) {\n window.addEventListener("resize", callback)\n return () => {\n window.removeEventListener("resize", callback)\n }\n}\n\nfunction useDimensions(ref: RefObject<HTMLElement>) {\n const dimensions = useSyncExternalStore(\n subscribe,\n () => JSON.stringify({\n width: ref.current?.offsetWidth ?? 0,\n height: ref.current?.offsetHeight ?? 0,\n })\n )\n return useMemo(() => JSON.parse(dimensions), [dimensions])\n}\n\nexport { useDimensions }\nRun Code Online (Sandbox Code Playgroud)\n
cha*_*rri 10
一个简单且最新的解决方案是使用 React React useRef钩子来存储对组件/元素的引用,并结合使用在组件渲染时触发的useEffect钩子。
import React, {useState, useEffect, useRef} from 'react';
export default App = () => {
const [width, setWidth] = useState(0);
const elementRef = useRef(null);
useEffect(() => {
setWidth(elementRef.current.getBoundingClientRect().width);
}, []); //empty dependency array so it only runs once at render
return (
<div ref={elementRef}>
{width}
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
如果您需要的只是这个问题的标题:反应元素的宽度,请使用此解决方案。
补充克里斯托弗的评论:您可以使用“react-use”库来执行此操作。当浏览器调整大小时它也会监听。供参考:https ://github.com/streamich/react-use/blob/master/docs/useMeasure.md
import React from 'react';
import { useMeasure } from 'react-use'; // or just 'react-use-measure'
const sampleView = () => {
const [ref, { width }] = useMeasure<HTMLDivElement>();
console.log('Current width of element', width);
return <div ref={ref}></div>;
};
export default sampleView;
Run Code Online (Sandbox Code Playgroud)
这是@meseern 答案的 TypeScript 版本,可避免在重新渲染时进行不必要的分配:
import React, { useState, useEffect } from 'react';
export function useContainerDimensions(myRef: React.RefObject<any>) {
const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
useEffect(() => {
const getDimensions = () => ({
width: (myRef && myRef.current.offsetWidth) || 0,
height: (myRef && myRef.current.offsetHeight) || 0,
});
const handleResize = () => {
setDimensions(getDimensions());
};
if (myRef.current) {
setDimensions(getDimensions());
}
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
};
}, [myRef]);
return dimensions;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
65789 次 |
| 最近记录: |