搭建nuxt3工程

245 阅读3分钟

创建 Nuxt3 应用

npx

npx nuxi@latest init <project-name>

pnpm

yarn dlx nuxi@latest init <project-name>

踩坑1:

在墙内的同学,应该都会由于网络原因而失败

最简洁的项目目录结构

项目集成

tailwindcss (css原子化)官网链接

  • 对于繁杂的css语句做到极致的缩减化
  • 不需要为起类名而产生心智负担
  • Tailwind 在为生产环境构建时会自动删除所有未使用的 CSS,这意味着你的最终 CSS 包可能是最小的。 事实上,大多数 Tailwind 项目向客户交付的 CSS 不到 10kB
  • 只需复制并粘贴类名称列表,即可使用 Tailwind 的 @apply 指令将重复的工具模式提取到自定义 CSS 类中。
  • 更便携的响应式断点
  • 安装命令
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init
  • nuxt.config.ts下添加
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },
  postcss: {
    plugins: {
      tailwindcss: {},
      autoprefixer: {},
    },
  },
})
  • tailwindcss.config.js下添加
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    './components/**/*.{js,vue,ts}',
    './layouts/**/*.vue',
    './pages/**/*.vue',
    './plugins/**/*.{js,ts}',
    './app.vue'
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
  • 在项目静态目录下(没有就创建static/css/main.css
@tailwind base;
@tailwind components;
@tailwind utilities;
  • nuxt.config.ts下添加
// https://nuxt.com/docs/api/configuration/nuxt-config
export default defineNuxtConfig({
  devtools: { enabled: true },
  css: ['~/static/css/main.css'],// 这一句
  postcss: {
    plugins: {
      tailwindcss: {},
    },
  },
})

拓展:

  • unocss 更深层次的css框架 由 antfu开发
  • windicss 下一代实用优先的 CSS 框架。
  • flex.css 一款移动端快速布局的神器

响应式断点: 官网解释

eslint

npm i -g eslint
eslint --init

@nuxt/image

适用于 Nuxt 应用的即插即用图像优化。使用内置优化器或您最喜欢的图像 CDN 调整图像大小并进行转换

文档:image.nuxt.com/get-started…

网络请求封装-fetch

nuxt3数据获取

推荐项目根目录新建 composables->useFetch.ts

interface FetchResponse<T = any> {
  data: Ref<T | null>
  error: FetchError<T>
  status: Ref<string>
  pending: Ref<boolean>
  refresh: () => Promise<void>
}

interface FetchError<T = any> {
  error?: Ref<boolean>
  message?: Ref<string>
  statusCode?: Ref<number | null>
  data?: Ref<T | null>
}

// 请求的配置
const config = reactive({
  timeOut: 5000, // 超时时间
  retryCount: 0 // 重试次数
})

export const fsFetch = async <T>(
  url: string,
  params: Record<string, any> = {}
): Promise<FetchResponse<any>> => {
  let controller: AbortController

  const fetchWithRetry = async (): Promise<FetchResponse<T>> => {
    controller = new AbortController() // 创建一个新的控制器
    const signal = controller.signal

    // 发起请求
    try {
      // 超时终止
      setTimeout(() => {
        controller.abort()
      }, config.timeOut)

      // 发起请求
      const res = await useFetch<T>(url, {
        params,
        signal
      })

      // 如果请求成功且存在错误,则重试
      if (res.status.value !== 'success' && config.retryCount < 5) {
        config.retryCount++
        return fetchWithRetry()
      }

      return res as FetchResponse<T>
    } catch (error) {
      console.log(`请求失败,错误信息:${error}`)
      if (config.retryCount < 5) {
        config.retryCount++
        return fetchWithRetry()
      } else {
        throw error // 重试次数达到上限或非超时错误,抛出错误
      }
    } finally {
      if (controller.signal.aborted) {
        console.log('请求已取消,重试次数:', config.retryCount)
      }
    }
  }

  return fetchWithRetry()
}

使用

/**
 * @function 获取新闻列表
 */
const getList = async () => {
  const res = await fsFetch('/front/get-news', {
    page: params.page,
    size: 500
  })

  const {
    data: {
      value: { data }
    },
    status
  } = res

  if (status.value === 'success' && data && data.list) {
    console.log('数据更新了-->', data.list)

    resStatus.value = status.value

    newsList.value = data.list as INewsList[]
  }
}

onMounted(() => {
  console.log('新闻列表页面')
  getList()
})

pinia

安装pinia并添加至nuxt.config.ts->modules[]

yarn add pinia @pinia/nuxt -D

根目录新建stores文件夹,并新建所需模块文件

import { defineStore } from 'pinia'
import type { ILanguageState } from '~/types/global'

export const useLangStore = defineStore('languageStore', {
  state: () => ({
    language: ''
  }),
  actions: {
    setLanguage(language: string) {
      console.log('要存储的值', language)
      this.language = language

      // 只在客户端调用否则服务端是没有localStorage的
      if (process.client) {
        localStorage.setItem('language', language)
      }
    }
  },
  getters: {
    getLanguage: (state)  => {
      if (process.client) {
        return state.language as ILanguageState || localStorage.getItem('language') as ILanguageState
      }
    }
  }
})

新增模块中转站

export * from './language'

使用

import {useLangStore} from '~/stores'

/**
 * 判断当前环境是否为中文环境
 */
export const isChineseEnvironment = () =>{

  const store = useLangStore()

  // 本地存储中存在语言设置,则直接返回
  if(localStorage.getItem('language')) return 

  /**
   * @description 如果是分享的链接是英文版,则首次打开是英文链接,这里直接将语言设置为英文
   * @waring 这里不能直接使用i18n 
   */
  if (window.location.href.includes('en')) {
    return store.setLanguage('en')
  }
  
  const language = navigator.language
  
  //是否为中文
  const isZH = language.startsWith('zh')
    
  // 中文 排除中文之外全部使用英文
  if (isZH) {
    store.setLanguage('zh')
    console.log('浏览器环境为中文')
  } else {
    store.setLanguage('en')
    console.log('浏览器环境为英文') 
  }
}