最近我的团队开始了一个落地页的项目,为了有好的SEO,我们选择了使用Gatsby。在我们项目的某一个环节,设计师把移动端的布局改成了SPA,和桌面端的布局还是有不同的路线和页面。
参考那个例子。
由于Gatsby在构建的时候就会创建页面,我们不知道环境是移动端还是桌面端,所以很难想办法处理这种行为。
我们团队认为暂时解决这个问题的一个快速方法是 map
节之间和隐藏比在桌面屏幕。而最大的问题是。在第一次加载页面时,内容几乎需要一秒钟的时间来加载,因为它不再是静态的了。
<div>
{
breakpoints.md
? pages.map((page) => renderPage(page))
: renderPage(selectedPageRef.current)
}
</div>
我想讨论的是一个解决方案,它可以改变页面在桌面和移动端的行为,而不会扼杀应用的SEO。
首先,可以借助CSS媒体查询实现以下功能(隐藏侧边栏或将其转化为顶部导航)。
然后,你可以设置一个useMediaQuery钩子(比如这里有一个 实施)来有条件地呈现 About
和 Events
组件的导入,可以采用以下两种方式之一。
A) 如果大多数用户使用的是桌面版,你可以在移动视图中用以下方法推迟导入其他两个组件(关于和事件): 1) 如果用户使用的是桌面版,你可以用以下方法推迟导入其他两个组件(关于和事件)。可加载组件:
索引页将看起来像这样。
import React from "react"
import Loadable from "@loadable/component"
import useMediaQuery from "use-media-query-hook"
import Sidebar from "../components/Sidebar"
import Home from "../components/Home"
const LoadableAbout = Loadable(() => import("../components/About"))
const LoadableEvents = Loadable(() => import("../components/Events"))-
const IndexPage = () => {
const isMobile = useMediaQuery("(max-width: 425px)")
return (
<div>
<Sidebar />
<Home />
{isMobile && <LoadableAbout />}
{isMobile && <LoadableEvents />}
</div>
)
}
export default IndexPage
B) 如果大多数用户使用移动设备,你可以在构建时将这两个组件包含在主捆绑包中。
索引页将看起来像这样。
import React from "react"
import useMediaQuery from "use-media-query-hook"
import Sidebar from "../components/Sidebar"
import Home from "../components/Home"
import About from "../components/About"
import Events from "../components/Events"
const IndexPage = () => {
const isMobile = useMediaQuery("(max-width: 425px)")
return (
<div>
<Sidebar />
<Home />
{isMobile && <About />}
{isMobile && <Events />}
</div>
)
}
export default IndexPage
关于SEO,搜索引擎将只看到主要组件("主页 "在路由""中,"关于 "在 "about "中,等等),因为...。isMobile
默认为 null
在上述实现中,在构建时。
关于速度,主要组件在HTML中是静态渲染的。只有在移动SPA视图中,才需要加载其他部分。
如果你不能通过使用 mediaqueries
而你必须显示两个不同的组件,而不是相同的样式。解决这个问题的变通方法是检查什么是 window
大小,并显示一个或另一个布局。它会在显示头之前产生一个最小的延迟(如果是缓存的话微不足道),但这是我能够猜测的唯一方法。
因此,使用Gatsby的默认结构在 <Layout>
组件,你应该有这样的东西。
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div>
<main>{children}</main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</footer>
</div>
</>
)
所以,在你的 <Header>
你应该检查你的 window
大小,并渲染一个组件或另一个组件。
export const Header = (props) => {
let currentWidth;
if (typeof window !== 'undefined') currentWidth = useWindowWidth();
return typeof window !== 'undefined' ? currentWidth >= 768 ? <DesktopPane /> : <MobilePane /> : null;
};
正如你所看到的,在返回时我检查了一下 window
是在三元链条件下定义的。如果 window
未定义(即 undefined
)它返回一个 null
. 如果定义了它,它就会检查当前窗口的宽度(currentWidth
),还有一个三元条件,显示移动或桌面菜单。
作为一个最佳实践,链式三元不是最干净的解决方案,它们很难读取和维护,但目前,这个解决方案是可行的(当然必须重构)。
在这种情况下。useWindowWidth()
是一个自定义的钩子,在每个 window
但你可以使用任何你喜欢的尺寸。它看起来像。
import {useEffect, useState} from 'react';
const getWidth = () => window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
export const useWindowWidth = () => {
let [width, setWidth] = useState(getWidth());
useEffect(() => {
let timeoutId = null;
const resizeListener = () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => setWidth(getWidth()), 150);
};
window.addEventListener('resize', resizeListener);
return () => {
window.removeEventListener('resize', resizeListener);
};
}, []);
return width;
};
代码提供: https:/usehooks.com使用窗口大小。
请注意,在Gatsby的项目中,通常会检查是否有 window
是 !==
比 undefined
由于你所论证的观点。在compilationbuild点还没有定义。你可以查看更多关于 调试他们文档中的HTML Builds.