【问题标题】:Get viewport/window height in ReactJS在 ReactJS 中获取视口/窗口高度
【发布时间】:2016-08-20 03:05:11
【问题描述】:

如何在 ReactJS 中获取视口高度?在我使用的普通 JavaScript 中

window.innerHeight()

但使用 ReactJS,我不确定如何获取此信息。我的理解是

ReactDOM.findDomNode()

仅适用于创建的组件。但是,documentbody 元素并非如此,这可能会给我窗口的高度。

【问题讨论】:

    标签: javascript reactjs window viewport


    【解决方案1】:

    使用 Hooks (React 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>
      );
    }
    

    Working example

    原答案

    在 React 中也是一样,你可以使用window.innerHeight 来获取当前视口的高度。

    如你所见here

    【讨论】:

    • window.innerHeight 不是函数,而是属性
    • 看起来 Kevin Danikowski 编辑了答案,并且不知何故该更改已获得批准。现在已经修好了。
    • @FeCH 在组件卸载时移除事件监听器。它被称为cleanup 函数,你可以阅读它here
    • 有什么想法可以使用 SSR (NextJS) 获得相同的方法吗?
    • 这样一个写得很好的答案。希望更多的人写出这样的 stackoverflow 答案,而不是发布 npm 模块。
    【解决方案2】:

    这个答案类似于 Jabran Saeed 的答案,除了它也处理窗口大小调整。我是从here 那里得到的。

    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 });
    }
    

    【讨论】:

    • 你可以从回调参数中移除.bind(this),因为它已经被构造函数绑定了。
    • Nitpick:构造函数中的代码应该是this.state = { width: 0, height: 0 };,这样状态变量就不会改变它们的类型(如果我理解正确的话window.innerWidth is integer)。除了使代码更容易理解恕我直言之外,不会改变任何东西。感谢您的回答!
    • 为什么不this.state = { width: window.innerWidth, height: window.innerHeight }; 开始?
    • @Gerbus:+1。这就是它在初始页面加载时对我有用的原因。
    • 使用回调来定位窗口的调整大小事件,然后在回调中重新定位全局窗口对象,这可能不是最好的主意。出于性能、可读性和约定的考虑,我将对其进行更新以使用给定的事件值。
    【解决方案3】:
    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} 的形式使用视口高度

    【讨论】:

    • 如果调整浏览器窗口大小,此解决方案不会更新
    • 仅供参考,在组件挂载后更新状态将触发第二次 render() 调用,并可能导致属性/布局抖动。 github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/…
    • @HaukurKristinsson 如何克服这个问题?
    • @JabranSaeed 为什么不直接在构造函数上设置高度而不是在安装时更新它?如果你需要考虑 props,你可以像这样默认它的值:height: window.innerHeight || props.height。这不仅会简化代码,还会消除不必要的状态更改。
    【解决方案4】:

    我刚刚编辑了 QoPcurrent answer 以支持 SSR 并将其与 Next.js 一起使用(React 16.8.0+): p>

    /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>
      );
    }
    

    【讨论】:

    • 很好的解决方案。
    • 我尝试使用 NextJS 执行此操作,但它似乎只有在调整屏幕大小后才具有正确的大小。我认为这是因为 nextJS 服务器端渲染。你有什么想法吗?
    • 这个答案不起作用,因为它不会在不调整大小的情况下设置大小。请参阅我之前的评论,请进行编辑
    • @giovannipds 抱歉,我一定是看错了,这行得通
    • 您好乔瓦尼,感谢您的回答。是的,我了解您的代码在做什么。我的意思是向其他人表明,使用最新版本的 Next 会触发警告(我同意你的观点,它仍然有效,只是警告)。我在文档中的任何地方都找不到以下方法: 1. 在 Next 中轻松忽略此警告。 2. 调整代码使其不会触发它。以后如果您有任何指针,请告诉我;-)
    【解决方案5】:

    我发现了一个使用 React Hooks 和调整大小功能的 QoP 和 speckledcarp 的简单组合,代码行数略少:

    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 事件是双引号,而不是单引号。那个让我有点;)

    【讨论】:

    • 单引号有什么问题?
    【解决方案6】:

    @speckledcarp 的答案很棒,但如果您需要在多个组件中使用此逻辑,则可能会很乏味。您可以将其重构为 HOC (higher order component) 以使此逻辑更易于重用。

    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 钩子 (example above here),因为它们解决了一些 advanced issues with HOCs and classes

    【讨论】:

    • 干得好@James
    【解决方案7】:

    用一点打字稿

    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;
      }

    【讨论】:

      【解决方案8】:

      为多样性和简洁的方法添加这个。

      此代码使用函数式方法。如其他答案中所述,我使用了 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>
          </>
        );
      }
      

      【讨论】:

      • 如果您收到类似以下错误的小更新:“未定义窗口”。将状态 x 和 y 的初始值设置为 0,一切正常。
      • 很好的解决方案!
      【解决方案9】:

      我刚刚花了一些时间用 React 和滚动事件/位置来解决一些问题 - 所以对于那些仍在寻找的人,这就是我发现的:

      可以使用 window.innerHeight 或 document.documentElement.clientHeight 找到视口高度。 (当前视口高度)

      整个文档(body)的高度可以通过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);
      

      哇!希望它可以帮助某人!

      【讨论】:

        【解决方案10】:
        // 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
           </>
          )
        }
        

        【讨论】:

        • 欢迎来到 Stack Overflow。没有任何解释的代码转储很少有帮助。 Stack Overflow 是关于学习的,而不是提供 sn-ps 来盲目复制和粘贴。请edit您的问题并解释它如何比OP提供的更好。
        • 小心,这段代码永远不会移除它创建的事件监听器。 stackoverflow.com/a/36862446/867600 是一个更好的钩子方法。
        【解决方案11】:

        早安,

        我知道我参加这个聚会迟到了,但让我告诉你我的答案。

        const [windowSize, setWindowSize] = useState(null)
        
        useEffect(() => {
            const handleResize = () => {
                setWindowSize(window.innerWidth)
            }
        
            window.addEventListener('resize', handleResize)
        
            return () => window.removeEventListener('resize', handleResize)
        }, [])
        

        更多详情请访问https://usehooks.com/useWindowSize/

        【讨论】:

        • 您是否应该在效果中调用 handleResize() 以设置原始浏览器窗口大小? window.innerHeight 也会得到高度
        【解决方案12】:

        @speckledcarp 和@Jamesl 的回答都很出色。然而,在我的情况下,我需要一个高度可以扩展整个窗口高度的组件,在渲染时有条件......但是在render() 中调用 HOC 会重新渲染整个子树。糟糕。

        另外,我对获取值作为道具不感兴趣,而只是想要一个父 div 占据整个屏幕高度(或宽度,或两者)。

        所以我编写了一个父组件,提供了一个完整的高度(和/或宽度)div。轰隆隆。

        一个用例:

        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
        

        【讨论】:

          【解决方案13】:

          你也可以试试这个:

          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);
          }
          

          【讨论】:

            【解决方案14】:

            保持当前尺寸状态的简单方法,即使在调整窗口大小后:

            //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);
            }
            

            【讨论】:

              【解决方案15】:

              useEffect很容易搞定

              useEffect(() => {
                  window.addEventListener("resize", () => {
                      updateDimention({ 
                          ...dimension, 
                          width: window.innerWidth, 
                          height: window.innerHeight 
                      });
                      console.log(dimension);
                  })
              })
              

              【讨论】:

                【解决方案16】:

                作为回答: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);
                

                【讨论】:

                • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
                【解决方案17】:

                React 原生 web 有一个可以使用的 useWindowDimensions 钩子:

                    import { useWindowDimensions } from "react-native";
                    const dimensions = useWindowDimensions()
                

                【讨论】:

                • 适用于 react-native-web 或 expo *
                【解决方案18】:

                这是您如何实现它并在 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>
                  )
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2015-04-27
                  • 1970-01-01
                  • 2021-04-03
                  • 1970-01-01
                  • 2013-11-12
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多