17

我有一个使用 ReactJS 构建的响应式 Web 应用程序,我希望有一天能够支持服务器端渲染。

根据视口大小,应用程序布局/行为会发生变化。但是所有这些改变不仅可以通过纯 CSS 媒体查询来完成:JS 行为,而且底层的 HTML 结构也必须根据宽度进行更改。

例如我可以有:

在 800px 宽度下

<div class="app">
  <div class="menu-mobile">...</div>
  <div class="content">...</div>
  <div class="mobile-left-menu">...</div>
  <div class="footer-mobile">...</div>
</div>

宽度超过 800 像素

<div class="app">
  <div class="menu">...</div>
  <div class="main">
    <div class="left-menu">...</div>
    <div class="content">...</div>
    <div class="right-menu">...</div>
  </div>
  <div class="footer">...</div>
</div>

现在,我想为该应用程序使用服务器端渲染。但是在服务器上我没有宽度,所以我不知道返回给客户端的 HTML 结构。

请注意,我不是在寻找使用静态默认服务器端断点的解决方案,而是在客户端更正应用程序。我正在寻找一种解决方案,可以根据其设备向客户端返回正确的 html 结构。因此,如果他在浏览器上禁用 javascript,它应该可以正常工作。


有人可能会争辩说,我可以渲染两者所需的 html,并使用纯 CSS 媒体查询和隐藏/显示所需的部分display: none,但这会使应用程序复杂化并使其渲染许多未使用的 html 元素,因为通常用户不太可能移动断点上方/下方(我的意思是,如果他有移动设备,则永远不会使用桌面的 html 元素)

此外,如果我想使用内联样式,它会变得复杂,因为我必须在服务器上渲染这些内联样式以获得正确的宽度。

看到有些人正在考虑嗅探浏览器 UA 以估计他们的视口大小。但即使有一些不安全的屏幕尺寸检测,我也不确定我们能否知道服务器端的设备屏幕方向。

我可以做些什么来解决这个问题吗?

4

2 回答 2

3

我认为 Artsy 找到了解决这个问题的最佳方法。

他们在服务器上渲染所有内容,然后只在前端渲染所需的布局。

如果在服务器上他们确定设备具有某些边界,他们最终会通过仅渲染所需的布局来优化 SSR。

https://artsy.github.io/blog/2019/05/24/server-rendering-responsively/

于 2019-07-05T09:53:32.003 回答
1

我认为这就是你想要的,但这不是一个完美的解决方案

1.重要的是什么

您希望移动用户在 PC 版中直接获取移动页面,而不需要 html,反之亦然,这确保不需要 css(而不是内联样式),并且网络更少

2.我是怎么解决的

使用浏览器用户代理检测手机或平板电脑,您可以在服务器上进行预测和渲染,当客户端全部加载时,重新检查屏幕解决方案,如果您有错误的预测,请再次渲染。

您可以将回调绑定到窗口调整大小和方向更改,更改您的 redux 并自动渲染

3.镜头来袭

网络越少,越少意味着非常非常少

可能会发生错误预测,当它发生时页面可能会在加载时刷新

//server side detect and show different, if got force param, use force solution
const detected = bowser._detect(req.get('User-Agent'))
const initState = req.query.force ? {
  [req.query.force]: true,
} : {
  bowser: {
    mobile: detected.mobile,
    tablet: detected.tablet,
  }
}
const redux = initStore(initState)
serverRender(redux)

//component X, show different content
const X = ({
  mobile
}) => (<div>
  {!!mobile?(<div>mobile</div>):(<div>pc</div>)}
</div>)

export default connect((state) => {
  return {
    mobile: detected.mobile,
    tablet: detected.tablet,
  }
})(X)

//top level component 
componentDidMount() {
  const reflow = () => {
    switch ($(window).width()) {
      case >800:
        this.props.dispatch(setSolution('pc'))
      default:
        this.props.dispatch(setSolution('mobile'))
    }
  }
  if (typeof window != 'undefined') {
    reflow()
  }
  $(window).resize(() => {
    reflow()
  })
  $(window).on("orientationchange", () => {
    reflow()
  })
}

于 2017-09-05T06:23:02.253 回答