纯分享:基于Nuxt3搭建PC端与移动端集成一体的多页面项目框架

1,407 阅读3分钟

一、前言

随着Nuxtjs被广大开发者运用在实际项目中,如何在同一项目中将PC端和移动端集成在一套代

码体系中, 这是在最近思考的一个问题。

机缘巧合看到一篇技术文章->Nuxt3优雅地在一个项目中集成pc端、移动端多套页面,有感于

此文,直接动手Coding, 搭建一个开箱即用的代码模板(暂不涉及后端)。

二、基本要求

代码模板应满足以下基本要求:

       基于Nuxt3,可以集成常见的技术框架,如Element-plus, VantUi等;

       代码统一部署,同一访问路径,不同终端加载不同页面资源;

       PC端和移动端对应的资源、代码独立分开, 互不影响;

       移动端需要适配不同屏幕宽度,并且不影响PC端;

三, 对应方案

要求1: 

     基于Nuxt3,可以集成常见的技术框架,如Element-plus, VantUi等;

解决方案:

    在项目直接下载安装Nuxt3, 可参考:www.nuxtjs.cn/guide/insta…

    Nuxt配置Element-plus, 可参考: element-plus.org/zh-CN/guide…

    Nuxt配置Vant, 可参考: vant-ui.github.io/vant/#/zh-C…

    其他技术框架,可参考其官方文档。

要求2:

     代码统一部署,同一访问路径,不同终端加载不同页面资源;

 解决方案:  

    配置Nuxt3, 配置自定义路由表, 在app/router.options.ts, 根据不同终端,返回不同路由      资源。

关键代码:

  routers/index.ts

/* routers/index.ts */

/* 公共路由 */
const commonRouters = [  {    path: '/',    redirect: '/index'  }]

/* 注意 PC 与 Mobile 的路由的Path name 须保持一致 */
/* PC  */
const PC_Routers = [
 {  
   name: 'index',   
   path: '/index',
   component: () => import('../PC/views/index.vue')
 }
]

/* Mobile */
const Mobile_Routers = [
  { 
     name: 'index',  
     path: '/index',
     component: () => import('../mobile/views/index.vue')
  }
]

export default {
  PC: [ ...PC_Routers, ...commonRouters ], 
  mobile: [ ...Mobile_Routers, ...commonRouters ]
}

  app/router.options.ts

import type { RouterConfig } from '@nuxt/schema'
import routersMap from '~/routers/index'
import { getDeviceType } from '~/utils/index'

/* 根据终端,返回不同路由资源 */
export default <RouterConfig> {  
   routes: (_routes) => {    
     const deviceType = getDeviceType() // pc mobile    
     console.log('终端', deviceType.value)    
     return routersMap[deviceType.value] ?? routersMap.PC  
   }
}

utils/index.ts

import { ref } from 'vue'
/* 判断终端是 PC or mobile  参考 https://juejin.cn/post/7326268915100794906 */
export const getDeviceType = () => {  
   let UA: string  
   if (process.client) // 如果是在客户端执行,则通过 navigator 获取 user-agent   
      UA = navigator.userAgent 
    else // 如果是在服务端执行,则通过请求头获取 user-agent 
      UA = useRequestHeader('user-agent') as string  const type = ref<'mobile' | 'pc'>('pc')  // 通过 UA 来判断设备类型是 pc 还是 mobile  
   if (/(Android|webOS|iPhone|iPod|tablet|BlackBerry|Mobile)/i.test(UA))    
     type.value = 'mobile' 
   else    
     type.value = 'pc' 
   return type}

要求3:

   PC端和移动端对应的资源、代码独立分开, 互不影响;

解决方案:  

   根据终端的不同,加载不同的入口文件。如

    PC: /PC/layout.vue;

    mobile: /mobile/layout.vue;

    PC端,移动端的对应的资源分别放在PC文件,mobile文件下。

关键代码:

app.vue

<template> 
   <!-- PC --> 
   <PCLayout v-if="deviceType === 'pc'"></PCLayout>   
   <!-- mobile -->  
   <MobileLayout v-if="deviceType === 'mobile'"></MobileLayout>
 </template>
<script lang="ts" setup>

import PCLayout from './PC/layout.vue'
import MobileLayout from './mobile/layout.vue'

import { getDeviceType } from '~/utils/index'
import '~/styles/common.css'

const deviceType = getDeviceType()
</script>
<style lang="scss"></style>

PC/layout.vue

<template>
  <div class="cmk-pc-warp">   
    <NuxtLayout>     
       <el-config-provider :locale="zhCn">    
          <NuxtPage />    
        </el-config-provider>   
    </NuxtLayout> 
   </div>
</template>

<script lang="ts" setup>

/* element-plus 使用中文 */
import zhCn from 'element-plus/es/locale/lang/zh-cn'

</script>
<!-- 不使用 scoped -->
<style lang="scss">

/* PC端的公共样式必须包裹在 .cmk-pc-warp */

@use './style/base.scss';

</style>

mobile/layout.vue

<template> 
   <div class="cmk-mobile-warp">   
      <NuxtLayout>      
        <NuxtPage />  
      </NuxtLayout>  
  </div>
</template>
<script lang="ts" setup>

/* vant Ui */
import 'vant/lib/index.css';

</script>
<!-- 不使用 scoped -->
<style lang="scss" >
/* 移动端的公共样式必须包裹在 .cmk-mobile-warp */
@use './style/base.scss';
</style>

要求4:

   移动端需要适配不同屏幕宽度,并且不影响PC端

解决方案:

   移动端端适配, 使用 postcss-pxtorem ,lib-flexible

  为了不影响到PC端的代码,需要配置nuxt.config.ts,如下

postcss: {   
  plugins: {  
     'postcss-pxtorem': {  
        rootValue({ file = '' }) {  
           return file.indexOf('vant') !== -1 ? 37.5 : 75;   
        },        
        propList: ['*'],     
        mediaQuery: false,      
        exclude: (file = '') => {   
          // 只对 移动端的 /mobile/、vantUi 文件夹中的文件进行 px 转 rem,其他文件不转换     
          const needRemArr = ['/mobile/', 'vant']         
          const bl = needRemArr.find(item => file?.includes(item))  
          if (bl) return false     
          return true;       
        }     
     },    
  }  
}

到此, 很好地满足上述基本要求。但还有以下不足:

1,PC端,移动端虽然在项目代码地角度已独立,但集成时,各自使用地框架,资源还是集成在一起。因此,项目过大的话,打包后的代码可能会过大,但是由于Nuxt3的SSR(服务器渲染),问题不大。

2, 各终端的公共样式,需要考虑样式最终打包在一起,因此要在最上层加于区分。

3,该模板适合,PC端与移动端的业务相似度比较高,如果各自差异较大,还是不集成更好。

四, 展示效果

完整代码 github:nuxt3-pc-mobile-template

项目部分结构:

PC端 /index 页面

移动端 /index 页面