รับวิวพอร์ต / ความสูงของหน้าต่างใน ReactJS


160

ฉันจะรับความสูงวิวพอร์ตใน ReactJS ได้อย่างไร ในจาวาสคริปต์ปกติฉันใช้

window.innerHeight()

แต่ใช้ ReactJS ฉันไม่แน่ใจว่าจะรับข้อมูลนี้ได้อย่างไร ความเข้าใจของฉันคือ

ReactDOM.findDomNode()

ใช้งานได้กับส่วนประกอบที่สร้างขึ้นเท่านั้น อย่างไรก็ตามนี่ไม่ใช่กรณีสำหรับdocumentหรือbodyองค์ประกอบซึ่งอาจให้ความสูงของหน้าต่าง

คำตอบ:


245

คำตอบนี้คล้ายกับของ 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 });
}

3
คุณสามารถลบออก.bind(this)จากการโต้แย้งกลับเพราะมันถูกผูกไว้โดยตัวสร้าง
Scymex

1
Nitpick: โค้ดใน Constructor อาจเป็นไปได้this.state = { width: 0, height: 0 };ว่า state vars จะไม่เปลี่ยนชนิดของมัน (ถ้าฉันเข้าใจwindow.innerWidth เป็นจำนวนเต็มอย่างถูกต้อง) ไม่เปลี่ยนแปลงอะไรเลยนอกจากทำให้เข้าใจรหัส IMHO ได้ง่ายขึ้น ขอบคุณสำหรับคำตอบ!
johndodo

1
@johndodo อ๊ะ แก้ไข
speckledcarp

7
ทำไมไม่this.state = { width: window.innerWidth, height: window.innerHeight };เริ่ม?
Gerbus

1
อาจไม่ใช่ความคิดที่ดีที่สุดให้ใช้การโทรกลับเพื่อกำหนดเป้าหมายเหตุการณ์การปรับขนาดของหน้าต่างจากนั้นกำหนดเป้าหมายวัตถุหน้าต่างสากลภายในการโทรกลับ เพื่อประสิทธิภาพการอ่านและการประชุมฉันจะอัปเดตเพื่อใช้ค่าเหตุการณ์ที่กำหนด
GoreDefex

177

ใช้ hooks (ตอบสนอง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เพื่อรับความสูงของวิวพอร์ตปัจจุบัน

อย่างที่คุณเห็นนี่


2
window.innerHeight ไม่ใช่ฟังก์ชันมันเป็นคุณสมบัติ
Jairo

2
ดูเหมือนว่า Kevin Danikowski จะแก้ไขคำตอบแล้วการเปลี่ยนแปลงนั้นก็ได้รับการอนุมัติ ตอนนี้ได้รับการแก้ไขแล้ว
QoP

3
@FeCH มันจะลบ listener เหตุการณ์เมื่อส่วนประกอบถูกถอดออก มันเรียกว่าcleanupฟังก์ชั่นคุณสามารถอ่านได้ที่นี่
QoP

1
มีแนวคิดใดที่จะได้รับแนวทางเดียวกันกับ SSR (NextJS)
roadev

1
@roadev ที่ NextJS คุณยังสามารถตรวจสอบว่าเสาของที่มีอยู่บนreq getInitialPropsถ้าเป็นมันทำงานบนเซิร์ฟเวอร์คุณจะไม่มีตัวแปรหน้าต่าง
giovannipds

54
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} ในเทมเพลตการแสดงผล


13
โซลูชันนี้จะไม่อัปเดตหากมีการปรับขนาดหน้าต่างเบราว์เซอร์
speckledcarp

1
FYI การอัปเดตสถานะหลังจากการเมาท์ส่วนประกอบจะทำให้เกิดการเรียกใช้การแสดงผลครั้งที่สอง () และสามารถนำไปสู่คุณสมบัติ / รูปแบบการเฆี่ยนตี github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/…
Haukur Kristinsson

1
@HaukurKristinsson วิธีการเอาชนะนี้
Richard

1
@JabranSaeed ทำไมไม่ลองทำต่อไปและตั้งค่าความสูงของคอนสตรัคเตอร์แทนที่จะทำการอัพเดตบน mount? height: window.innerHeight || props.heightหากคุณจำเป็นต้องใช้อุปกรณ์ประกอบฉากในการพิจารณาคุณสามารถเริ่มต้นค่าเป็นเช่นนี้ สิ่งนี้จะไม่เพียง แต่ทำให้รหัสง่ายขึ้น แต่ยังลบการเปลี่ยนแปลงสถานะที่ไม่จำเป็น
JohnnyQ

componentWillMountไม่แนะนำอีกต่อไปให้ดูreactjs.org/docs/react-component.html#unsafe_componentwillmount
holmberd

26

ฉันได้แก้ไขเพียงQoP 's คำตอบปัจจุบันเพื่อสนับสนุน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>
  );
}

ทางออกที่ดี
Jeremy E

ฉันพยายามทำสิ่งนี้กับ NextJS แต่ดูเหมือนว่าจะมีขนาดที่ถูกต้องหลังจากปรับขนาดหน้าจอ ฉันคิดว่ามันเป็นเพราะการแสดงผลฝั่งเซิร์ฟเวอร์ถัดไป JS คุณมีความคิดใด ๆ
herohamp

15

คำตอบของ @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);

นอกจากนี้คุณยังสามารถ "สแต็ค" HOCs หากคุณมีที่อื่นที่คุณต้องการใช้เช่น withRouter(withWindowDimensions(MyComponent))

แก้ไข: ฉันจะไปทำปฏิกิริยากับเบ็ดในปัจจุบัน ( ตัวอย่างข้างต้นที่นี่ ) ขณะที่พวกเขาแก้ปัญหาบางส่วนของปัญหาขั้นสูงที่มี HOCs และการเรียน


1
Good job @James
Manish sharma

8

ฉันเพิ่งใช้เวลาบางอย่างในการหาบางสิ่งด้วยการโต้ตอบและเลื่อนเหตุการณ์ / ตำแหน่ง - ดังนั้นสำหรับผู้ที่ยังคงดูนี่คือสิ่งที่ฉันพบ:

ความสูงวิวพอร์ตสามารถพบได้โดยใช้ 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
        });
      }
    }

(navbar ของฉันคือ 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);

ต๊าย! หวังว่ามันจะช่วยให้ใครบางคน!


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

1
ยินดีต้อนรับสู่ Stack Overflow การทิ้งโค้ดโดยไม่มีคำอธิบายใด ๆ นั้นไม่ค่อยมีประโยชน์ Stack Overflow เป็นเรื่องเกี่ยวกับการเรียนรู้ไม่ได้ให้ตัวอย่างเพื่อคัดลอกและวางสุ่ม โปรดแก้ไขคำถามของคุณและอธิบายวิธีการทำงานได้ดีกว่าสิ่งที่ OP ให้ไว้
Chris

2

คำตอบโดย @speckledcarp และ @Jamesl นั้นทั้งยอดเยี่ยม อย่างไรก็ตามในกรณีของฉันฉันต้องการส่วนประกอบที่ความสูงสามารถขยายความสูงหน้าต่างแบบเต็มโดยมีเงื่อนไข ณ เวลาการเรนเดอร์ .... แต่เรียก HOC ภายในrender()การแสดงทรีย่อยทั้งหมด BAAAD

นอกจากนี้ฉันไม่สนใจที่จะรับค่าเป็นอุปกรณ์ประกอบฉาก แต่ต้องการเพียงผู้ปกครอง 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

0

คุณสามารถลองสิ่งนี้:

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);
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.