一般使用场景
1、在tailwind.config.ts配置小于等于1023px为mobile端,大于等于1024px为pc端
//~ tailwind.config.ts
const config: Config = {
...
theme: {
...
screens: {
mobile: { max: '1023px' },
pc: { min: '1024px' },
},
}
...
}
2、在业务组件里面使用如下图
通过上述步骤,能达到pc端与mobile端表现不同样式的效果,但如果某一块样式pc端与mobile端差异很大,这时候通过这种方式就很难实现了。
特殊使用场景
方案一
遇到前面提到的场景,我们通常会写2套组件,pc端1套,mobile端1套,然后再通过判断用户当前使用的设备再去加载相应组件。
import { useMediaQuery } from 'react-responsive';
import A from '../A.tsx'
import B from '../B.tsx'
const Test = () => {
const isPC = useMediaQuery({ minWidth: 1024 });
return isPC ?<A/> : <B/>;
}
这样貌似很完美,但存在3个问题:
- 服务端无法使用hooks,传输到客户端的html组件A与组件B渲染的内容都不会存在
- 在本地开发环境会报水合错误,因为服务端渲染的内容与客户端渲染的内容差异较大
- 不利于seo优化,如果组件A与组件B存在重要内容给搜索引擎爬取,而这部分内容传下载下来却丢失了
方案二
前面我们是在客户端判断设备类型,因此存在问题,那我们将判断设备类型这一步放到服务端去做呢
import A from '../A.tsx'
import B from '../B.tsx'
const MOBILE_REG = '.*iPhone|Android|SymbianOS|Windows Phone|iPod{1,}.*';
export const getServerSideProps: GetServerSideProps = async (context) => {
const { params } = context;
const ua = context.req.headers['user-agent'];
let isMobile = true;
if (ua && ua.match(MOBILE_REG)) {
isMobile = true;
} else {
isMobile = false;
}
return {
props: {
isMobile,
},
};
};
const Test = ({isMobile}) => {
return isMobile ?<B/> : <A/>;
}
这样做解决了服务端返回html中组件内容为空的问题,但仅适用于服务端渲染,静态生成在构建时就生成页面了,这时显然无法判断设备类型。
方案三
如果将组件A与组件B的内容都生成下来,再通过display去控制是否展示其内容,这样前面提到的问题就都得到解决了。
import A from '../A.tsx'
import B from '../B.tsx'
const PC: React.FC<{ children: React.ReactElement }> = ({ children }) => {
return React.cloneElement(children, {
...children.props,
className: `${children.props.className || ''} pc:block mobile:hidden`,
});
};
const Mobile: React.FC<{ children: React.ReactElement }> = ({ children }) => {
return React.cloneElement(children, {
...children.props,
className: `${children.props.className || ''} pc:hidden mobile:block`,
});
};
const Test = () => {
return (
<>
<PC>
<A/>
</PC>
<Mobile>
<B/>
</Mobile>
</>
)
}
这样做唯一的坏处是首次就加载了pc端与mobile端的代码,但总体来说好处多于坏处:
- 解决了报水合错误的问题
- 无论是pc端的内容还是mobile端的内容都加载了进来,搜索引擎能够爬取所有内容
- 能同时支持静态生成与服务端渲染