html 如何根据设备大小使用组件?

b09cbbtk  于 2022-12-09  发布在  其他
关注(0)|答案(2)|浏览(99)

我们如何根据设备的大小显示不同的html元素或组件在react中可以使用一个叫做react-responsive的包但是在Next中我使用这个包的每个组件中ssr并没有在那个组件上运行你通常对此做些什么毕竟很多时候呈现在例如Windows显示与移动的上应该显示的东西有很大不同,应该使用其他html代码。

qnzebej0

qnzebej01#

好的,如果我理解了你的问题,你试图呈现一个页面,其中包含所有与设备相关的组件,但只显示(使用css)当前设备的组件。

我的方法是:

在页面组件中:

// imports

const PageComponent = () => {
    const resizeTimoutRef = useRef(null)

    const [screenSizeState, setScreenSizeState] = useState(null) // initialized at null because on the server you don't have the DOM

    // basic function to get the breakpoint as a string based on the width of the window
    const getScreenSize = windowWidth =>
        windowWidth < 768
        ? "sm"
        windowWidth < 1024
        ? "md"
        : windowWidth < 1280
        ? "lg"
        : "xl"

    useEffect(() => {
        // here i set the current screen breakpoint immediately on the page load
        setScreenSizeState(getScreenSize(window.innerWidth))

        // here i add a listener for the resize event of the window
        window.addEventListener('resize', () => {
            // if a resize timout exists i clear it to prevent calling setState too many times
            if(resizeTimeoutRef.current) clearTimeout(resizeTimeoutRef.current)

            // here i set the timeout ref to the function that will be executed 150ms after the last resize event, again, to prevent calling setState too many times
            resizeTimeoutRef.current = setTimeout(() => setScreenSizeState(getScreenSize(window.innerWidth)), 150)
        })
    }, []) // empty array means that this hook will be called only once on the first page load

    return (
        <>
            <div style={{ display: screenSizeState === 'sm' ? 'block' : 'none' }}>
                Always present in the DOM but displayed only on 'sm' breakpoint
            </div>
            <div style={{ display: ['md', 'lg'].includes(screenSizeState) ? 'block' : 'none' }}>
                Always present in the DOM but displayed only on 'md' and 'lg' breakpoints
            </div>
        </>
    )
}

export default PageComponent

当然,您可以将此代码修改为自定义钩子,使其可重用,只需执行以下操作:

// hooks/useScreenSize.js
// imports

export const useScreenSize = () => {
    const resizeTimoutRef = useRef(null)

    const [screenSizeState, setScreenSizeState] = useState(null)

    const getScreenSize = windowWidth =>
        windowWidth < 768
        ? "sm"
        windowWidth < 1024
        ? "md"
        : windowWidth < 1280
        ? "lg"
        : "xl"

    useEffect(() => {
        setScreenSizeState(getScreenSize(window.innerWidth))

        window.addEventListener('resize', () => {
            if(resizeTimeoutRef.current) clearTimeout(resizeTimeoutRef.current)

            resizeTimeoutRef.current = setTimeout(() => setScreenSizeState(getScreenSize(window.innerWidth)), 150)
        })
    }, [])

    return screenSizeState
}

这样您就可以在页面组件中使用它,如下所示:

// pages/index.jsx
// imports

const PageComponent = () => {
    const breakpointState = useScreenSize()

    return (
        <>
            <div style={{ display: breakpointState === 'sm' ? 'block' : 'none' }}>
                Always present in the DOM but displayed only on 'sm' breakpoint
            </div>
            <div style={{ display: ['md', 'lg'].includes(breakpointState) ? 'block' : 'none' }}>
                Always present in the DOM but displayed only on 'md' and 'lg' breakpoints
            </div>
        </>
    ) 
}

export default PageComponent
ztyzrc3y

ztyzrc3y2#

由于NextJs是服务器端呈现的,因此服务器无法知道它将生成的html发送到什么屏幕大小。
现在'useEffect'来拯救,因为useEffect只在客户端运行。
一旦页面加载到浏览器上,我们就可以使用它来获取屏幕大小类型。
您可以按以下方式使用“react-device-detect”。

import { isMobile } from 'react-device-detect';

  // declare a state
  const [stateMobile, setState] = useState(false);

  useEffect(() => {
    if (!isMobile && typeof window !== 'undefined') {
      setState(stateMobile);
    } else {
      setState(!stateMobile);
    }
  }, []);

那你回来的时候

return (
    <>
      {isMobile ? (
        <div> Mobile html here </div> 
       ) : (
        <div> Desktop html here </div>
      )}
    </>
  );

在app.js文件中使用此方法一次,并将其作为props传递给layout,而不是在每个组件中使用useeffect。

相关问题