在 ReactJS 中获取视口/窗口高度
Get viewport/window height in ReactJS
如何在ReactJS中获取视口高度?在普通的JavaScript中,我使用
。window.innerHeight()
但是使用 ReactJS,我不确定如何获取此信息。我的理解是
ReactDOM.findDomNode()
仅适用于创建的组件。但是,对于document
或body
元素来说并非如此,这可能会给我窗口的高度。
使用 useSyncExternalStore()
hook (React 18.0.0+
)
import { useSyncExternalStore } from 'react';
export function useWindowDimensions() {
// the 3rd parameter is optional and only needed for server side rendering
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}
function subscribe(callback) {
window.addEventListener('resize', callback);
return () => window.removeEventListener('resize', callback);
}
function getSnapshot() {
return { width: window.innerWidth, height: window.innerHeight };
}
function getServerSnapshot() {
return {
width: 0,
height: 0,
};
}
使用钩子(反应16.8.0+
)
创建useWindowDimensions
钩。
import { useState, useEffect } from 'react';
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height
};
}
export default function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}
之后,您将能够像这样在组件中使用它
const Component = () => {
const { height, width } = useWindowDimensions();
return (
<div>
width: {width} ~ height: {height}
</div>
);
}
工作示例
原答案
在 React 中也是如此,您可以使用window.innerHeight
来获取当前视口的高度。
正如你在这里看到的
这个答案与Jabran Saeed的类似,只是它也处理窗口大小调整。我从这里得到它。
constructor(props) {
super(props);
this.state = { width: 0, height: 0 };
this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
}
componentDidMount() {
this.updateWindowDimensions();
window.addEventListener('resize', this.updateWindowDimensions);
}
componentWillUnmount() {
window.removeEventListener('resize', this.updateWindowDimensions);
}
updateWindowDimensions() {
this.setState({ width: window.innerWidth, height: window.innerHeight });
}
我刚刚编辑了 QoP 的当前答案以支持 SSR 并将其与 Next.js (React 16.8.0+) 一起使用:
/hooks/useWindowDimensions.js:
import { useState, useEffect } from 'react';
export default function useWindowDimensions() {
const hasWindow = typeof window !== 'undefined';
function getWindowDimensions() {
const width = hasWindow ? window.innerWidth : null;
const height = hasWindow ? window.innerHeight : null;
return {
width,
height,
};
}
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useEffect(() => {
if (hasWindow) {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}
}, [hasWindow]);
return windowDimensions;
}
/yourComponent.js:
import useWindowDimensions from './hooks/useWindowDimensions';
const Component = () => {
const { height, width } = useWindowDimensions();
/* you can also use default values or alias to use only one prop: */
// const { height: windowHeight = 480 } useWindowDimensions();
return (
<div>
width: {width} ~ height: {height}
</div>
);
}
class AppComponent extends React.Component {
constructor(props) {
super(props);
this.state = {height: props.height};
}
componentWillMount(){
this.setState({height: window.innerHeight + 'px'});
}
render() {
// render your component...
}
}
设置道具
AppComponent.propTypes = {
height:React.PropTypes.string
};
AppComponent.defaultProps = {
height:'500px'
};
视口高度现在在渲染模板中以 {this.state.height} 的形式提供
我找到了 QoP 和 speckledcarp 的答案的简单组合,使用 React Hooks 和调整大小功能,代码行数略少:
const [width, setWidth] = useState(window.innerWidth);
const [height, setHeight] = useState(window.innerHeight);
const updateDimensions = () => {
setWidth(window.innerWidth);
setHeight(window.innerHeight);
}
useEffect(() => {
window.addEventListener("resize", updateDimensions);
return () => window.removeEventListener("resize", updateDimensions);
}, []);
哦,是的,请确保resize
事件用双引号引起来,而不是单引号。那个让我有点;)
@speckledcarp的答案很棒,但如果在多个组件中需要此逻辑,则可能会很乏味。您可以将其重构为 HOC(高阶组件),以使此逻辑更易于重用。
withWindowDimensions.jsx
import React, { Component } from "react";
export default function withWindowDimensions(WrappedComponent) {
return class extends Component {
state = { width: 0, height: 0 };
componentDidMount() {
this.updateWindowDimensions();
window.addEventListener("resize", this.updateWindowDimensions);
}
componentWillUnmount() {
window.removeEventListener("resize", this.updateWindowDimensions);
}
updateWindowDimensions = () => {
this.setState({ width: window.innerWidth, height: window.innerHeight });
};
render() {
return (
<WrappedComponent
{...this.props}
windowWidth={this.state.width}
windowHeight={this.state.height}
isMobileSized={this.state.width < 700}
/>
);
}
};
}
然后在您的主组件中:
import withWindowDimensions from './withWindowDimensions.jsx';
class MyComponent extends Component {
render(){
if(this.props.isMobileSized) return <p>It's short</p>;
else return <p>It's not short</p>;
}
export default withWindowDimensions(MyComponent);
如果您有另一个需要使用 HOC,您也可以"堆叠"HOC,例如 withRouter(withWindowDimensions(MyComponent))
编辑:我现在会使用 React 钩子(上面的例子),因为它们解决了 HOC 和类的一些高级问题
使用钩子:
在这里使用 useLayoutEffect 更有效:
import { useState, useLayoutEffect } from 'react';
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height
};
}
export default function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useLayoutEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}
用法:
const { height, width } = useWindowDimensions();
带有一个小打字稿
import { useState, useEffect } from 'react';
interface WindowDimentions {
width: number;
height: number;
}
function getWindowDimensions(): WindowDimentions {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height
};
}
export default function useWindowDimensions(): WindowDimentions {
const [windowDimensions, setWindowDimensions] = useState<WindowDimentions>(
getWindowDimensions()
);
useEffect(() => {
function handleResize(): void {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return (): void => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}
添加此内容以实现多样性和干净的方法。
此代码使用函数样式方法。我使用了onresize而不是addEventListener,如其他答案中所述。
import { useState, useEffect } from "react";
export default function App() {
const [size, setSize] = useState({
x: window.innerWidth,
y: window.innerHeight
});
const updateSize = () =>
setSize({
x: window.innerWidth,
y: window.innerHeight
});
useEffect(() => (window.onresize = updateSize), []);
return (
<>
<p>width is : {size.x}</p>
<p>height is : {size.y}</p>
</>
);
}
我只是花了一些认真的时间弄清楚 React 和滚动事件/位置的一些事情 - 所以对于那些仍在寻找的人,这是我发现的:
视口高度可以通过使用 window.innerHeight 或使用 document.documentElement.clientHeight 找到。 (当前视口高度)
可以使用 window.document.body.offsetHeight 找到整个文档(正文)的高度。
如果您试图找到文档的高度并知道何时触底 - 这就是我想出的:
if (window.pageYOffset >= this.myRefII.current.clientHeight && Math.round((document.documentElement.scrollTop + window.innerHeight)) < document.documentElement.scrollHeight - 72) {
this.setState({
trueOrNot: true
});
} else {
this.setState({
trueOrNot: false
});
}
}
(我的导航栏在固定位置为 72px,因此 -72 以获得更好的滚动事件触发器)
最后,这里有一些 console.log() 的滚动命令,它帮助我积极地弄清楚我的数学。
console.log('window inner height: ', window.innerHeight);
console.log('document Element client hieght: ', document.documentElement.clientHeight);
console.log('document Element scroll hieght: ', document.documentElement.scrollHeight);
console.log('document Element offset height: ', document.documentElement.offsetHeight);
console.log('document element scrolltop: ', document.documentElement.scrollTop);
console.log('window page Y Offset: ', window.pageYOffset);
console.log('window document body offsetheight: ', window.document.body.offsetHeight);
呼! 希望它对某人有所帮助!
美好的一天,
我知道我参加这个聚会迟到了,但让我告诉你我的答案。
const [windowSize, setWindowSize] = useState(null)
useEffect(() => {
const handleResize = () => {
setWindowSize(window.innerWidth)
}
window.addEventListener('resize', handleResize)
return () => window.removeEventListener('resize', handleResize)
}, [])
欲了解更多详情,请访问 https://usehooks.com/useWindowSize/
你可以像这样创建自定义钩子: useWindowSize()
import { useEffect, useState } from "react";
import { debounce } from "lodash";
const getWindowDimensions = () => {
const { innerWidth: width, innerHeight: height } = window;
return { width, height };
};
export function useWindowSize(delay = 0) {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions()
);
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
const debouncedHandleResize = debounce(handleResize, delay);
window.addEventListener("resize", debouncedHandleResize);
return () => window.removeEventListener("resize", debouncedHandleResize);
}, [delay]);
return windowDimensions;
}
// just use (useEffect). every change will be logged with current value
import React, { useEffect } from "react";
export function () {
useEffect(() => {
window.addEventListener('resize', () => {
const myWidth = window.innerWidth;
console.log('my width :::', myWidth)
})
},[window])
return (
<>
enter code here
</>
)
}
@speckledcarp和@Jamesl的答案都很棒。但是,就我而言,我需要一个组件,其高度可以扩展整个窗口高度,这是渲染时的条件。但是在 render()
中调用 HOC 会重新呈现整个子树。巴阿德。
另外,我对将这些值作为道具不感兴趣,而只是想要一个占据整个屏幕高度(或宽度,或两者)的父div
。
所以我写了一个父组件,提供了一个完整的高度(和/或宽度)div. Boom。
一个用例:
class MyPage extends React.Component {
render() {
const { data, ...rest } = this.props
return data ? (
// My app uses templates which misbehave badly if you manually mess around with the container height, so leave the height alone here.
<div>Yay! render a page with some data. </div>
) : (
<FullArea vertical>
// You're now in a full height div, so containers will vertically justify properly
<GridContainer justify="center" alignItems="center" style={{ height: "inherit" }}>
<GridItem xs={12} sm={6}>
Page loading!
</GridItem>
</GridContainer>
</FullArea>
)
下面是组件:
import React, { Component } from 'react'
import PropTypes from 'prop-types'
class FullArea extends Component {
constructor(props) {
super(props)
this.state = {
width: 0,
height: 0,
}
this.getStyles = this.getStyles.bind(this)
this.updateWindowDimensions = this.updateWindowDimensions.bind(this)
}
componentDidMount() {
this.updateWindowDimensions()
window.addEventListener('resize', this.updateWindowDimensions)
}
componentWillUnmount() {
window.removeEventListener('resize', this.updateWindowDimensions)
}
getStyles(vertical, horizontal) {
const styles = {}
if (vertical) {
styles.height = `${this.state.height}px`
}
if (horizontal) {
styles.width = `${this.state.width}px`
}
return styles
}
updateWindowDimensions() {
this.setState({ width: window.innerWidth, height: window.innerHeight })
}
render() {
const { vertical, horizontal } = this.props
return (
<div style={this.getStyles(vertical, horizontal)} >
{this.props.children}
</div>
)
}
}
FullArea.defaultProps = {
horizontal: false,
vertical: false,
}
FullArea.propTypes = {
horizontal: PropTypes.bool,
vertical: PropTypes.bool,
}
export default FullArea
我通过将getWindowDimensions函数包装在useCallback中来更新代码
,略有不同import { useCallback, useLayoutEffect, useState } from 'react';
export default function useWindowDimensions() {
const hasWindow = typeof window !== 'undefined';
const getWindowDimensions = useCallback(() => {
const windowWidth = hasWindow ? window.innerWidth : null;
const windowHeight = hasWindow ? window.innerHeight : null;
return {
windowWidth,
windowHeight,
};
}, [hasWindow]);
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useLayoutEffect(() => {
if (hasWindow) {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}
}, [getWindowDimensions, hasWindow]);
return windowDimensions;
}
在这里,您有投票最多的答案包装在一个节点包(经过测试的打字稿)中,可供使用。
安装:
npm i @teambit/toolbox.react.hooks.get-window-dimensions
用法:
import React from 'react';
import { useWindowDimensions } from '@teambit/toolbox.react.hooks.get-window-dimensions';
const MyComponent = () => {
const { height, width } = useWindowDimensions();
return (
<>
<h1>Window size</h1>
<p>Height: {height}</p>
<p>Width: {width}</p>
</>
);
};
我重新命令使用useSyncExternalStore
import { useSyncExternalStore } from "react";
const store = {
size: {
height: undefined,
width: undefined
}
};
export default function ChatIndicator() {
const { height, width } = useSyncExternalStore(subscribe, getSnapshot);
return (
<h1>
{width} {height}
</h1>
);
}
function getSnapshot() {
if (
store.size.height !== window.innerHeight ||
store.size.width !== window.innerWidth
) {
store.size = { height: window.innerHeight, width: window.innerWidth };
}
return store.size;
}
function subscribe(callback) {
window.addEventListener("resize", callback);
return () => {
window.removeEventListener("resize", callback);
};
}
如果你想试试吧:https://codesandbox.io/s/vibrant-antonelli-5cecpm
即使在调整窗口大小后,也能保持当前尺寸处于该状态的简单方法:
//set up defaults on page mount
componentDidMount() {
this.state = { width: 0, height: 0 };
this.getDimensions();
//add dimensions listener for window resizing
window.addEventListener('resize', this.getDimensions);
}
//remove listener on page exit
componentWillUnmount() {
window.removeEventListener('resize', this.getDimensions);
}
//actually set the state to the window dimensions
getDimensions = () => {
this.setState({ width: window.innerWidth, height: window.innerHeight });
console.log(this.state);
}
这就是实现它并在 React 功能组件中实时获取窗口宽度和高度的方法:
import React, {useState, useEffect} from 'react'
const Component = () => {
const [windowWidth, setWindowWidth] = useState(0)
const [windowHeight, setWindowHeight] = useState(0)
useEffect(() => {
window.addEventListener('resize', e => {
setWindowWidth(window.innerWidth);
});
}, [window.innerWidth]);
useEffect(() => {
window.addEventListener('resize', e => {
setWindowHeight(window.innerHeight);
});
}, [window.innerHeight]);
return(
<h3>Window width is: {windowWidth} and Height: {windowHeight}</h3>
)
}
我使用了投票最多的答案,但是当每次返回不同的值时,useSyncExternalStore
导致超出最大更新getSnapshot
无限循环(即使属性宽度和高度相同,每次都会创建一个新对象),所以我更改为缓存最后一个值并在宽度和高度相同时使用它:
import { useSyncExternalStore } from 'react';
export function useWindowDimensions() {
// the 3rd parameter is optional and only needed for server side rendering
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}
const subscribe = (
callback: (this: Window, ev: WindowEventMap['resize']) => unknown,
) => {
window.addEventListener('resize', callback);
return () => window.removeEventListener('resize', callback);
};
export interface WindowSizes {
width: number;
height: number;
}
const getSnapshot = ((value: WindowSizes | undefined) => () => {
if (
!value ||
value.width !== window.innerWidth ||
value.height !== window.innerHeight
) {
value = { width: window.innerWidth, height: window.innerHeight };
}
return value;
})(undefined);
const getServerSnapshot = (
(
value = {
width: 0,
height: 0,
},
) =>
() => {
return value;
}
)();
你也可以试试这个:
constructor(props) {
super(props);
this.state = {height: props.height, width:props.width};
}
componentWillMount(){
console.log("WINDOW : ",window);
this.setState({height: window.innerHeight + 'px',width:window.innerWidth+'px'});
}
render() {
console.log("VIEW : ",this.state);
}
使用useEffect
useEffect(() => {
window.addEventListener("resize", () => {
updateDimention({
...dimension,
width: window.innerWidth,
height: window.innerHeight
});
console.log(dimension);
})
})
<</div>
div class="answers"> 作为答案来自: bren 但挂钩 useEffect 到 [window.innerWidth]
const [dimension, updateDimention] = useState();
useEffect(() => {
window.addEventListener("resize", () => {
updateDimention({
...dimension,
width: window.innerWidth,
height: window.innerHeight
});
})
},[window.innerWidth]);
console.log(dimension);
React 原生 web 有一个可以使用的 useWindowDimensions 钩子:
import { useWindowDimensions } from "react-native";
const dimensions = useWindowDimensions()
有一个包含 93.000+ 下载的包,名为 useWindowSize()
npm i @react-hook/window-size
import {
useWindowSize,
useWindowWidth,
useWindowHeight,
} from '@react-hook/window-size'
const Component = (props) => {
const [width, height] = useWindowSize()
const onlyWidth = useWindowWidth()
const onlyHeight = useWindowHeight()
...
}
文档
@foad abdollahi 和 @giovannipds 答案的组合帮助我在 Nextjs 中使用带有 useLayoutEffect
的自定义钩子找到了解决方案。
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions()
);
useLayoutEffect(() => {
const isWindow = typeof window !== 'undefined';
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
isWindow && window.addEventListener('resize', handleResize);
console.log(windowDimensions);
return () =>
isWindow && window.removeEventListener('resize', handleResize);
}, [windowDimensions]);
return windowDimensions;
}
与@QoP相同的答案,但在 Remix.run 中实现
import {useState, useEffect} from 'react';
function getWindowDimensions() {
if (typeof window !== 'undefined') {
const {innerWidth: width, innerHeight: height} = window;
return {
width,
height,
};
} else {
return null; // or return an empty object {}
}
}
export default function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions() || {width: 0, height: 0},
);
useEffect(() => {
function handleResize() {
const dimensions = getWindowDimensions();
if (dimensions) {
setWindowDimensions(dimensions);
}
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}
最终代码
import React, { useState, useEffect } from 'react'
export default function App() {
const [screenSize, setScreenSize] = useState(getCurrentDimension());
function getCurrentDimension(){
return {
width: window.innerWidth,
height: window.innerHeight
}
}
useEffect(() => {
const updateDimension = () => {
setScreenSize(getCurrentDimension())
}
window.addEventListener('resize', updateDimension);
return(() => {
window.removeEventListener('resize', updateDimension);
})
}, [screenSize])
return (
<div>
<ul>
<li>Width: <strong>{screenSize.width}</strong></li>
<li>Height: <strong>{screenSize.height}</strong></li>
</ul>
</div>
)
}
- 调整缩放窗口高度提升缩放
- javascript skrollr基于动态内容更新窗口高度
- 当移动地址栏出现/消失时,防止更改窗口高度
- 使用JavaScript更改带有窗口高度的元素样式
- 在 ReactJS 中获取视口/窗口高度
- 如何在angular js中获取窗口高度
- 黑莓网站:窗口大小(窗口高度)在黑莓模拟器中返回不正确的值
- 将“窗口高度”指定为“文档高度”
- 使用jQuery如何获取窗口高度
- 始终具有窗口高度的文本区域
- Javascript 函数调整窗口高度和宽度
- 具有 100% 窗口高度的移动导航栏,无论内容如何
- 页面高度等于窗口高度
- 使用 jQuery Event 调整内容窗口高度
- 动态调整 Chrome 扩展程序弹出窗口高度的大小
- 当 #content 区域长于窗口高度(本机或 Vue.js)时收听
- 厚箱或类似的东西,窗口高度为 100%
- 加载 HTML 网站时,安卓上的窗口高度错误
- 每次刷新页面时,JQuery 都会为窗口高度提供不同的值
- 在不使用jQuery的情况下获取移动设备(尤其是iPhone)上的窗口高度