如何在Nuxt应用初始化前获取存储窗口宽度,解决设备判定异常问题
问题根源
你遇到的问题本质是对nuxtServerInit的执行逻辑认知错误:
nuxtServerInit仅在服务端渲染阶段运行在服务端,此时process.browser值为false,你写的设置device_width的逻辑完全不会执行,state中的device_width保持初始值nullnull和数字做比较时会隐式转换为0,所以服务端判断device_width < 768永远为真,会话请求的device_type永远是mobile,服务端返回的HTML也是移动端UI,自然影响桌面端SEO- 等到客户端hydration完成后,才会触发浏览器端的逻辑更新
device_width,中间就会出现几秒的移动端UI闪烁
最优解决方案(兼容SEO+会话请求正确性)
服务端无法直接获取客户端窗口宽度,我们改用请求头的User-Agent判断设备类型,完全在服务端完成判定,无闪烁、SEO正常、会话参数正确:
- 先安装UA解析工具:
npm i ua-parser-js
- 修改store代码:
// store/index.js import UAParser from 'ua-parser-js' import axios from 'axios' export const state = () => ({ device_type: null, session_data : {}, }) export const mutations = { set_device_type(state, payload) { state.device_type = payload }, set_session_data(state, payload){ state.session_data = payload } } export const actions = { async nuxtServerInit({ commit }, { req }) { let device_type = 'desktop' // 服务端从请求头拿UA判断设备类型 if (process.server && req) { const userAgent = req.headers['user-agent'] const parser = new UAParser(userAgent) const deviceInfo = parser.getDevice() device_type = ['mobile', 'tablet'].includes(deviceInfo.type) ? 'mobile' : 'desktop' } // 兼容SPA模式下的客户端判断 else if (process.client) { device_type = window.innerWidth < 768 ? 'mobile' : 'desktop' } commit('set_device_type', device_type) // 发送会话请求,此时device_type已经是正确值 const sessionData = await axios({ // 你的接口地址等配置 headers: { 'X-Device-Type': device_type } }) commit('set_session_data', sessionData) } }
- 修改模板中的判断逻辑:
computed:{ isMobile(){ return this.$store.state.device_type === 'mobile' } }
- 可选:如果需要响应窗口拖拽缩放的设备类型切换,在全局布局(比如
layouts/default.vue)添加resize监听:
mounted() { window.addEventListener('resize', this.handleDeviceResize) }, beforeDestroy() { window.removeEventListener('resize', this.handleDeviceResize) }, methods: { handleDeviceResize() { const currentType = window.innerWidth < 768 ? 'mobile' : 'desktop' if (currentType !== this.$store.state.device_type) { this.$store.commit('set_device_type', currentType) // 如需重新拉取会话数据可在此处调用对应action } } }
替代方案(仅适用于不需要SEO的场景)
如果你一定要用窗口宽度判定、不接受UA判断的误差,可以把首屏判断逻辑放到客户端执行,首屏先渲染全局骨架屏,拿到窗口宽度后再渲染对应组件,该方案会导致服务端返回的内容为空,损失SEO收益。
内容的提问来源于stack exchange,提问作者adeab
相关产品推荐
相关产品推荐

