nuxt3官网搭建,适配pc和移动端支持一键切换中英文,使用pinia和持久化插件

、1使用命令行创建项目脚手架

npx nuxi@latest init may-app // my-app你的项目名称

一般情况下都会创建失败,这里有一个项目的模版,可以自行下载使用
Nuxt基础配置模板地址:https://github.com/Seven7v/Nuxt3-vue3-project

2、如何适配pc端和移动端?

  1. 文件middleware/auth.global.ts // 加上global后缀,默认全局中间件,进入所有路由都会通过这里
  2. 在中间件文件中判断是什么设备,跳转至对应的路由
export default defineNuxtRouteMiddleware((to, from) => {
  if (process.server){ // 在服务器端处理路由
    const nuxtApp = useNuxtApp()
  } else { // 在客户端处理路由
    // 是否是移动端设备
    const isMobile = /(Android|webOS|iPhone|iPod|tablet|BlackBerry|Mobile)/i.test(navigator.userAgent)
    // 是否是手机端路由
    const isRouterMobile = /^\/m\//.test(to.fullPath);
    // 移动端并且 不是/m开头路由
    if(isMobile && !isRouterMobile){
      return navigateTo(`/m${to.fullPath}`)
    }
    // 不是移动端 是/m开头路由
    if( !isMobile && isRouterMobile){
      return navigateTo(`${to.fullPath.replace('/m','')}`)
    }
  }
})
  1. 适配移动端,使用插件 postcss-px-to-viewport 在nuxt.config.ts文件中设置css如下
 css: {
      postcss: {
        plugins: [
          postcsspxtoviewport({
            unitToConvert: 'px', // 要转化的单位
            viewportWidth: 750, // UI设计稿的宽度
            unitPrecision: 6, // 转换后的精度,即小数点位数
            propList: ['*'], // 指定转换的css属性的单位,*代表全部css属性的单位都进行转换
            viewportUnit: 'vw', // 指定需要转换成的视窗单位,默认vw
            fontViewportUnit: 'vw', // 指定字体需要转换成的视窗单位,默认vw
            selectorBlackList: ['el-'], // 指定不转换为视窗单位的类名,例如van-(vantUI组件),
            minPixelValue: 1, // 默认值1,小于或等于1px则不进行转换
            mediaQuery: true, // 是否在媒体查询的css代码中也进行转换,默认false
            replace: true, // 是否转换后直接更换属性值
            exclude: [/node_modules/], // 设置忽略文件,用正则做目录名匹配,最好不要排除node_modules 文件,排除后在项目中会发现字体不能跟随页面放大
            landscape: false // 是否处理横屏情况
          })
        ]
      }
    }

3、如何实现一键切换中英文?

  1. 安装@intlify/unplugin-vue-i18nvue-i18n两个依赖,如果安装不上,请使用强制命令 --force
npm i @intlify/unplugin-vue-i18n vue-i18n
  1. 配置 nuxt.config.ts 文件
 import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'url'
import VueI18nVitePlugin from '@intlify/unplugin-vue-i18n/vite'

export default defineNuxtConfig({
  build: {
  transpile: [/vue-i18n/]
},
  vite: {
    resolve: {
      alias: {
        'vue-i18n': 'vue-i18n/vue-i18n.runtime.esm-bundler.js'
      }
    },
    plugins: [
      VueI18nVitePlugin({
        include: [
          resolve(dirname(fileURLToPath(import.meta.url)), './locales/*.json')
        ]
      })
    ]
  }
})
  1. plugins中将i18n在vue中使用,配置好后 在plugins目录下创建i18n.ts文件。 因为需要在plugins中将i18n挂到vue上
// 目录结构
|- plugins
    |-- i18n.ts
|- i18n
    |-- zh.ts
    |-- en.ts

zh.ts en.ts 配置国际化匹配的内容

// zh.ts
export default {
    home: '主页',
  }
//en.ts
export default {
    home: 'HomePage',
  }

plugins目录下创建i18n.ts

import { createI18n } from 'vue-i18n'
import en from '../i18n/en'
import zh from '../i18n/zh'

export default defineNuxtPlugin(({ vueApp }) => {
    // 这里设置了默认启动时从cookie获取语言配置。至于为什么是cookie ,是因为nuxt 的首屏服务端加载原因
  const language = useCookie('lang').value || 'zh'
  const i18n = createI18n({
    fallbackLocale: 'zh',
    locale: language,
    messages: {
      zh,
      en
    },
  })
  vueApp.use(i18n)
})
  1. 在components文件夹中创建Lang.vue组件
<template>
  <div>
    <select v-model="$i18n.locale" @change="handleChange">
      <option value="zh">中文</option>
      <option value="en">English</option>
    </select>
  </div>
</template>
<script setup>
import { useI18n } from 'vue-i18n'

const { locale } = useI18n()
const handleChange = () => {
  const cookieLang = useCookie('lang')
  cookieLang.value = locale.value
}
</script>
<style lang="less" scoped>
select {
    outline: none
}
</style>
  1. 在页面中直接使用 : $t('home')
<template>
  <div> {{ $t('home') }}</div>
</template>

4. 如何使用pinia和持久化插件

  1. 按装pinia和pinia-plugin-persistedstate
npm install pinia @pinia/nuxt
npm i pinia-plugin-persistedstate
  1. nuxt工程代码中注册插件(/plugis/pinia.ts文件中)
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
export default defineNuxtPlugin((nuxtApp) => {
    nuxtApp.$pinia.use(piniaPluginPersistedstate)
})
  1. 配置nuxt.config.ts中的modules
modules: [ '@pinia/nuxt' ],
  1. 定义一个store(/store/counter.ts文件中)
import { defineStore } from 'pinia'
 
interface CounterState {
  times: number
  name: string
}
 
export const useCounter = defineStore('counter', {
  state: (): CounterState => ({
    times: 5,
    name: 'jjww'
  }),
  actions: {
    increment() {
      this.times++
    },
    clearName(){
        this.name = ''
    }
  },
  persist: process.client && {
    storage: localStorage,
    paths: ['times','name']
  }
})
// 注意:persist定义要做判断,因为localStorage是客户端参数,所以需要加process.client
  1. 在页面只中使用pinia的store
<script setup lang="ts">
import { useCounter } from '~/store/counter'
const counter = useCounter()
</script>
 
<template>
  <div style="padding-top: 200px;padding-left: 50px;">
    <div style="margin-bottom: 30px;">
      <pre>{{ counter.$state }}</pre>
      <p>
        times: {{ counter.times }}
        <br>
        name: {{ counter.name }}
      </p>
 
      <input v-model="counter.name" type="text">
      <br>
      <input v-model="counter.times" type="number">
    </div>
    <button @click="counter.increment()">
      +1 number click
    </button>
    <br>
    <button @click="counter.clearName()">clearName</button>
  </div>
</template>

5. nuxt中间件的使用方法

  1. 单页面的路由中间件的写法
  <!-- 对单页面的路由守卫 -->
<script setup lang="ts">
 definePageMeta({
  middleware: (to, from,next) => {
    if (!localStorage.getItem('token')) {
      return navigateTo('/login') //一定要写return
    }
  }
})
</script>
  1. 命名中间件:如果多个页面需要配置守卫,可以将单页的内容 抽出
// 1 新建文件
|- middleware
   |-- auth.ts // 中间件名称自定义
// 2 auth.ts中写入
export default defineNuxtRouteMiddleware((to, from) => {
  if (!localStorage.getItem('token')) {
    return navigateTo('/login') //一定要写return
  }
})
// 3 页面如果需要用到中间件的地方只需要配置,就可以实现导航守卫功能
<script setup lang="ts">
definePageMeta({
  middleware: 'auth'
})
</script>
  1. 全局中间件(注意命名方式,要加上global)
// 1 新建文件
|- middleware
   |-- auth.global.ts // 加上global后缀,默认全局中间件,进入所有路由都会通过这里
// 2  auth.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
  const limitList = ['/article', '/home', '/product'] // 配置适配 路由
  if (limitList.includes(to.fullPath)) {
    if (!localStorage.getItem('token')) { // !!!!这里有个大坑
      return navigateTo('/login') //一定要写return
    }
  }
})

这样写如果从不做验证的页面进如,后跳转到/home时完全没有问题的,但是如果,路由地址中直接写**/home**回车,页面会加载不出来,提示500报错,没有localStorage。此时/home时首页,首页渲染时服务端返回,所以没有localStorage,可以将token
放到cookie中解决 也可以使用 proess.server来判断,此代码是否是在服务端
运行的,如果时true,可以做对应处理。

打印后,在启动项目的终端会打印出true 将token储存在cookie中,使用useCookie

useCookie可以实现如下操作

if (process.server) {
      // 从服务端的cookie中获取token
    } else {
      // js 使用从浏览器的cookie中获取token
    }

从而可以写成,这样从/home直接进入的话就不会报错了

export default defineNuxtRouteMiddleware((to, from) => {
  const limitList = ['/article', '/home', '/product']
  if (limitList.includes(to.fullPath)) {
    const token = useCookie('token')
    if (!token.value) {
      return navigateTo('/login') //一定要写return
    }
  }
})

页面重定向 现在进入页面 直接加载会显示404,这时可以进行重定向

|- middleware
   |-- redirect.global.ts // 中间件名称自定义
export default defineNuxtRouteMiddleware((to, from) => {
  if (to.fullPath === '/') {
    return navigateTo('/home')
  }
})

6. Nuxt3 反向代理配置

由于Nuxt的首屏服务端渲染,以及只有浏览器才受同源限制 的问题,在面对跨域请求时,需要对客户端和服务端都进行代理

最优处理方法 ,在nuxt.config.ts中进行如下配置

export default defineNuxtConfig({
  devtools: { enabled: true },
  //   反向代理
  nitro: {
      // 用于客户端代理
    devProxy: {
      '/api': {
        target: 'https://xxx.com/api', // 这里是接口地址
        changeOrigin: true,
        prependPath: true
      }
    },
    // 该配置用于服务端请求转发
    routeRules: {
      '/api/**': {
        proxy: 'https://xxx.com/api/**'
      }
    }
  }
})

不配置routeRules 的话
请求数据时就可以写成,如果不配置routeRules,会使页面首屏加载时,请求错误。

const { data } = await useLazyFetch(
  '/api/xxxxx/xxx/xx',
  {
    // baseURL: process.server ? 'https://i.maoyan.com/api' : '', 如果不配置routeRules,兼容服务端与客户端请求可以这样写
  }
)

7. 项目打包部署

  1. 使用 npm run build 命名进行打包,会在项目的根目录下产生一个.output 文件夹
  2. .output 文件夹复制到D盘下,切换至D盘 d: (自己的任意盘下)
  3. 使用命名 node .output/server/index.mjs即可启动项目
  4. 在浏览器中输入 http://localhost:3000/打开项目
    在这里插入图片描述
    注意:关掉命令窗口,服务就停止了,可以使用pm2

按键盘快捷键"win + R",输入“cmd”,再按快捷键“ctrl+shift+enter”,出来的cmd窗口就已经是管理员身份了。
安装npm i pm2 -g 用管理员身份安装

在刚才的D盘下的output文件夹下新建 ecosystem.config.js文件

// ecosystem.config.js
// 运行生产环境
module.exports = {
    apps: [
      {
        name: '晋百慧',
        script: './server/index.mjs',
        env:{
            NODE_ENV:'production',
            PORT:'8080'
         }
      }
    ]
  }

在打开的命令行窗口中切换到D盘(d:),切换至.output文件夹(cd .output)

运行项目命令: `pm2 start`
停止项目命令: `pm2 stop`
清除项目命令: `pm2 deleta`
也可以运行某个项目,使用id: `pm2 start 1`