nuxt3实战:完整的 nuxt3 + vue3 项目创建与useFetch请求封装

news2024/11/13 19:21:51

一. 安装

pnpm dlx nuxi@latest init <project-name>

// or

npx nuxi@latest init <project-name>
  • 如遇到报错
    在这里插入图片描述

手动安装:

  1. 浏览器访问报错https请求地址:
    在这里插入图片描述

  2. 点击tar(项目初始文件的下载地址)对应地址,下载starter-3.tar.gz 包到本地

  3. 本地创建项目文件,将压缩包解压到项目文件内

  4. 安装依赖pnpm i / npm install

  5. 启动项目pnpm dev

二. 服务端和客户端

1. 对比vite项目运行和nuxt项目运行`:
  1. vite
    在这里插入图片描述

  2. nuxt
    在这里插入图片描述

  3. nuxt运行在浏览器
    在这里插入图片描述

  4. 总结:
    - vite创建项目,浏览器访问,返回模板html
    - nuxt创建项目,浏览器访问,请求返回渲染后的html, 输出先是服务端渲染的1111,后是客户端的1111

2. 区分serverclient
const runtimeConfig = useRuntimeConfig()
if (runtimeConfig.apiSecret) {
  console.log('server');
} else {
  console.log('clint');
}

或者

if (import.meta.server) {
  console.log('server');
} else {
  // import.meta.client
  console.log('clint');
}

三. 基础配置nuxt.config.ts

1. 环境变量和私有令牌
export default defineNuxtConfig({
  runtimeConfig: {
    // 只在服务器端可用的私有键
    apiSecret: '123',
    // public中的键也可以在客户端使用
    public: {
      apiBase: '/api'
    }
  }
})

或者

# 这将覆盖apiSecret的值
NUXT_API_SECRET=api_secret_token

这些变量通过useRuntimeConfig()组合函数暴露给应用程序的其余部分。

<script setup lang="ts">
const runtimeConfig = useRuntimeConfig()
</script>
2. 全局样式导入

有一个 sass部分 文件,其中包含颜色变量,供你的Nuxt 页面 和 组件 使用。

$primary: #49240F;
$secondary: #E4A79D;
export default defineNuxtConfig({
  // css:['~/assets/css/base.scss'],
  // 或者
  vite: {
    css: {
      preprocessorOptions: {
        scss: {
          additionalData: '@use "@/assets/_colors.scss" as *;'
        }
      }
    }
  }
})

3. 引入element-plus

安装

npm i element-plus @element-plus/nuxt -D
modules: [
    '@element-plus/nuxt'
  ],

四、路由

1. 创建pages文件夹,内部的.vue文件会自动被创建为路由
  // 路由入口 相当于 router-link
  <NuxtLink to="/">首页</NuxtLink>

  // 路由容器, 相当于 router-view
  <NuxtPage />
2. 命名路由
  • [id].vue一个中括号包裹的文件名,将匹配一个参数化的路由。
  <NuxtLink to="/product/123">产品</NuxtLink>

  <NuxtPage />
  • product/[id].vue
const route = useRoute()
console.log(route.params);
3. 可选路由
  • [[test]] / myTest.vue 两个中括号包裹文件夹名。内部.vue路由访问时test可省略
<NuxtLink to="/test/myTest">可选路由1</NuxtLink><br>
<NuxtLink to="/myTest">可选路由2</NuxtLink>
4. 全局路由
  • [...404].vue 一个中括号...加文件名
5. definePageMeta为你的页面组件定义元数据。
  • login.vue
definePageMeta({
  path: '/login1'
})
  • 访问login会跳转404login1则会跳转login
6. 嵌套路由
  • user.vue同级创建user文件夹,user文件夹内路由为user.vue的子路由

在这里插入图片描述

7. 编程路由

navigateTo在服务器端和客户端均可使用。

if (import.meta.server) {
  navigateTo('/login1')
}
// navigateTo('/login1')
8. 路由中间件
  1. 创建middleware文件夹,内部创建my-middleware.ts,
export default defineNuxtRouteMiddleware((to, from) => {
  console.log("my-middleware", to.path);
  // // 在实际应用中,你可能不会将每个路由重定向到 `/`
  // // 但是在重定向之前检查 `to.path` 是很重要的,否则可能会导致无限重定向循环
  if (to.path === "/about") {
    return navigateTo("/user");
  }
});
  1. 页面使用about.vue
definePageMeta({
  middleware: [
    'my-middleware'
  ]
})
  1. 全局中间件: test.global.ts,必须global结尾
export default defineNuxtRouteMiddleware((to, from) => {
  console.log("全局中间件", to.path);
});
9. 导航守卫
export default defineNuxtRouteMiddleware((to, from) => {
  // console.log("全局中间件", to.path);
  const whiteList = ['/index', '/login', '/404', '/']
  if(!whiteList.includes(to.path)){
    let token = ''
    if(import.meta.client){
      token = localStorage.getItem('token') || ''
    } 
    if(!token){
      return navigateTo({
        path: '/login',
        query: { 
          code: 401,
          message: '请先登录'
         }
      });
    }
  }
});
onMounted(() => {
  const route = useRoute()
  if (route.query.code === '401') {
    ElMessage.error(route.query.message as string)
  }
})

五. 目录结构

  1. components目录是你放置所有 Vue 组件的地方。

Nuxt 会自动导入该目录中的所有组件

  1. 使用composables目录将你的Vue组合式函数自动导入到你的应用程序中
export const useFoo = () => {
  return useState('foo', () => 'bar')
}
<script setup lang="ts">
const foo = useFoo()
</script>

<template>
  <div>
    {{ foo }}
  </div>
</template>

默认导出可使用驼峰文件名进行访问

  1. 使用utils目录在整个应用程序中自动导入你的工具函数。使用当时同composables

六、请求

<script setup lang="ts">
// 在SSR中数据将被获取两次,一次在服务器端,一次在客户端。
const dataTwice = await $fetch('/api/item')

// 在SSR中,数据仅在服务器端获取并传递到客户端。
const { data } = await useAsyncData('item', () => $fetch('/api/item'))

// 你也可以使用useFetch作为useAsyncData + $fetch的快捷方式
const { data } = await useFetch('/api/item')
</script>
  • 完整request.ts
/**
 * @description  useFetch
 * */
import type { NitroFetchRequest } from 'nitropack';

const apiRequest = <T>(url:NitroFetchRequest, options: any): Promise<ResultData<T>> => {
  const config = useRuntimeConfig();
  const nuxtApp = useNuxtApp()

  const contentType =  options.contentType ||  'application/json'

  return new Promise((resolve, reject) => {
    useFetch<ResultData<T>>(url, {
      baseURL: config.public.baseURL,
      onRequest({ options }) {
        let token = "";
        if (import.meta.client) {
          token = useStore().getToken();
        }
  
        options.headers = {
          'Content-Type': contentType,
          'Cookies': `token=${token}`,
          ...options.headers,
        };
  
      },
      
      onResponse({ response }) {
        if(response.status >= 200 && response.status < 300){
          if(response._data.code === 200){
            resolve(response._data)
          } else {
            if(import.meta.client){
              ElMessage.error(response._data.msg)
            } else {
              nuxtApp.runWithContext(()=>{
                navigateTo({
                  path: '/Error',
                  query:{
                    code: response._data.code,
                    message: response._data.msg
                  }
                })
              })
            }
          }
        }
      },
      onResponseError({ response }) {
        if(import.meta.client){
          ElMessage.error(response._data.msg)
        } else {
          nuxtApp.runWithContext(()=>{
            navigateTo({
              path: '/Error',
              query:{
                code: response._data.code,
                message: response._data.msg
              }
            })
          })
        }
      },
  
      ...options
    });
  });
 
};

interface Result {
  code: string;
  msg: string;
}

interface ResultData<T = any> extends Result {
  data: T;
}

export const getApi = <T>(url:NitroFetchRequest, options: any = {}): Promise<ResultData<T>> => {
  return apiRequest(url, {
    method: 'GET',
    ...options
  })
}

export const postApi = <T>(url:NitroFetchRequest, options: any = {}): Promise<ResultData<T>> => {
  return apiRequest(url, {
    method: 'POST',
    ...options
  })
}
  • [[Error]] / index.vue
<script setup lang="ts">
onMounted(() => {
  const route = useRoute();
  switch (route.query.code) {
    case '401':
      ElMessage.error('no login')
      localStorage.removeItem('token')
      break;
    case '501':
      ElMessage.error('Unknown error' + route.query.message)
      break;
    default:
      ElMessage.error(route.query.code + '' + route.query.message)
  }
})
</script>
  • 调用接口
// template
<p v-for="item in list" :key="item.id">{{ item.name }}</p>

// script
const list = ref<Info[]>()
interface Info {
  id: number;
  name: string
}

interface List {
  list: Info[],
  page: number;
  total: number;
}
const handleClick = async () => {
  const { data } = await getApi<List>('/list')
  list.value = data.list
}

七、pinia

  1. 安装pinia
pnpm install pinia @pinia/nuxt
  1. 配置nuxt.config.ts
modules: [
  '@pinia/nuxt',
],
  1. 持久化配置
  • 安装
pnpm i -D @pinia-plugin-persistedstate/nuxt
modules: [
  '@pinia-plugin-persistedstate/nuxt',
],

// 默认存在cookies
// piniaPersistedstate: {
//   storage: 'localStorage'
// },

八、 nuxt错误处理

  1. app.vue同级创建error.vue
<script setup lang="ts">

defineProps({
  error: Object
})

clearError({ redirect: '/login' })
</script>
  1. index.vue
throw createError({ statusCode: 404, message: '404 not found' })
  1. 错误只能从服务端触发

九、SEO优化

useHead函数用于自定义Nuxt应用中单个页面的头部属性。

useHead(
  {
    // title: 'my login',
    meta: [
      {
        name: 'description',
        content: 'my login description'
      },
      {
        name: 'keywords',
        content: 'my login keywords'
      },
    ],
    // titleTemplate: (titleChunk) => {
    //   return titleChunk ? `${titleChunk} - my login` : 'my login'
    // }
    titleTemplate: `%s ${name.value}`
  }
)

十、layout布局

  • layout目录下创建default.vue
<template>
  <div>
    <p>一些在所有页面之间共享的默认布局内容</p>
    <slot />
  </div>
</template>
  • app.vue页面使用layout
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>

  {/* <NuxtLayout :name="其他layout">
    <NuxtPage />
  </NuxtLayout> */}
</template>

  • login.vue页面不使用layout
definePageMeta({
  layout: false
})

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1990347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Android】使用网络技术——WebView的用法、http协议、OKHttp、解析XML、JSON格式数据笔记整理

WebView的用法 新建一个WebView项目 修改activity_main中的代码&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:id"id/main"and…

STM32F1之SysTick系统定时器详细解析

目录 1. 简介 2. SysTick功能框图 3. SysTick寄存器 3.1 SysTick控制及状态寄存器 3.2 SysTick重装载数值寄存器 3.3 SysTick当前数值寄存器 3.4 SysTick校准数值寄存器 4. SysTick定时时间计算 5. SysTick寄存器结构体 6. 写一个us级延时函数 7. 写一个…

240806-RHEL 无法通过 ssh username@ip 远程连接,报错:Connection closed by ip port 22

A. 原因排查 遇到这个错误通常意味着 SSH 服务可能在目标主机上没有正常运行&#xff0c;或有防火墙/网络配置问题。以下是一些排查步骤&#xff1a; 检查 SSH 服务状态&#xff1a; 确认 SSH 服务是否正在目标主机上运行。 sudo systemctl status sshd重启 SSH 服务&#xff…

探索 Python 异步通信的奥秘:WebSockets 库的神奇之旅

文章目录 探索 Python 异步通信的奥秘&#xff1a;WebSockets 库的神奇之旅背景&#xff1a;为何选择 WebSockets&#xff1f;什么是 websockets 库&#xff1f;安装 websockets 库5个简单的库函数使用方法场景应用示例常见问题与解决方案总结 探索 Python 异步通信的奥秘&…

用Manim实现三维坐标系的绘制

1.ThreeDAxes 函数 ThreeDAxes是 Manim 中用于创建三维坐标系的类。在manim中常用的三位坐标绘制函数是&#xff1a; class ThreeDAxes(x_range(-6, 6, 1), y_range(-5, 5, 1), z_range(-4, 4, 1), x_length10.5, y_length10.5, z_length6.5, z_axis_configNone, z_normala…

数据仓库怎么建设?一文详解数仓的建设过程!

随着信息技术的飞速发展&#xff0c;企业不仅需要存储和管理海量数据&#xff0c;更迫切需要从这些数据中提取有价值的信息&#xff0c;以支持复杂的决策制定过程。数据仓库不仅是存储数据的场所&#xff0c;更是支持复杂查询、报告和数据分析的强有力工具&#xff0c;其建设已…

JavaScript异步简介|Promise快速入门

异步&#xff08;Asynchronous, async&#xff09;是与同步&#xff08;Synchronous, sync&#xff09;相对的概念。 异步 JavaScript 简介 异步编程技术使你的程序可以在执行一个可能长期运行的任务的同时继续对其他事件做出反应而不必等待任务完成。与此同时&#xff0c;你…

Linux工具|运维工具rename常用命令详解

&#x1f4eb; 作者简介&#xff1a;「六月暴雪飞梨花」&#xff0c;专注于研究Java&#xff0c;就职于科技型公司后端工程师 &#x1f3c6; 近期荣誉&#xff1a;华为云云享专家、阿里云专家博主、腾讯云优秀创作者、ACDU成员 &#x1f525; 三连支持&#xff1a;欢迎 ❤️关注…

【vulnhub】Wakanda :1靶机

靶机安装 下载地址&#xff1a;https://download.vulnhub.com/wakanda/wakanda-1.ova 运行环境&#xff1a;Virtual Box 信息收集 靶机IP扫描 netdiscover -i eth0 -r 192.168.7.0/24 端口扫描 nmap -A 192.168.7.243 -p- 80端口开启了http服务&#xff0c;在3333端口开启…

案例研究丨盛泰光电携手DataEase实现数据驱动智能制造

盛泰光电科技股份有限公司&#xff08;以下简称为“盛泰光电”&#xff09;是中国第一批摄像头模组制造企业。自成立至今&#xff0c;一直专注于手机摄像头模组的研发、制造、销售与服务&#xff0c;并向非手机包括笔记本、车载、医疗、AIoT等领域延伸&#xff0c;形成以手机摄…

PHP + Laravel + RabbitMQ + Redis 实现消息队列 (二) 消费队列在RabbitMQ和redis中的简单使用

最简单的队列功能 RabbitMQ和消息传递通常会使用一些术语&#xff1a; 生产者&#xff08;Producer&#xff09;意味着发送消息。一个发送消息的程序称为生产者。队列&#xff08;Queue&#xff09;尽管消息通过RabbitMQ和您的应用程序流动&#xff0c;但它们只能存储在队列中…

数据结构(01):数据结构概述(基本术语、逻辑结构和物理结构)

1、数据结构概述 (1)基本术语 A.数据元素 具有一定意义的基本单位。如人类的数据元素是人&#xff08;张三、李四等&#xff09;。 B.数据项 可以看作是数据元素的属性。如人的属性&#xff08;姓名、年龄、身高等&#xff09; C.数据对象 性质相同的数据元素的集合。如某一栋…

群聊的创建 表情包发送 图片发送

目录 群聊&#xff1a; ​编辑 表情包发送&#xff1a; 图片发送&#xff1a; 群聊&#xff1a; 1.群资料的表groupinformation 字段&#xff1a;GroupId 群id&#xff0c;GroupName 群名&#xff0c;CreatTime 创群时间&#xff0c;CreatUserId 创群的人&#xff0c;…

萤石云 ezuikit-js创建的播放器实例esc取消全屏后变黑屏

原因&#xff1a;上层页面重新设置了容器的宽高&#xff0c;导致uikit退出全屏时宽高计算异常 解决方法&#xff1a;实例初始化的时候会传入宽高width、height&#xff0c;播放器的画面尺寸是根据这两个参数设置的&#xff0c;然后退出全屏会回到这两个值

计算机的错误计算(五十五)

摘要 展示大数的余弦函数值的错误计算。 根据国际IEEE 754 标准[1]&#xff0c;包括余弦在内的三角函数的定义域是整个实数范围&#xff1a; 但是&#xff0c;实际情况怎样呢&#xff1f; 例1. 计算 . 在 Python下计算&#xff1a; x30**65 print(x) import math print(ma…

只强的Java学习之路8-7

一. 安装配置nodejs npm create vitelatest npm install vue-router npm install axios npm install element-plus --save npm run dev https://element-plus.org/zh-CN/#/zh-CN 新建项目&#xff1a; easy.vue <script setup></script><!--绑定数据-->…

在vue中页面使用了动态组件组件导致首次页面加载时子组件样式不显示,刷新后才正常

问题&#xff1a; 在vue中页面使用了动态组件组件导致首次页面加载时子组件样式不显示&#xff0c;刷新后才正常。 原因&#xff1a; 因为动态组件的延迟加载&#xff0c;如果使用了Vue的动态组件&#xff08;如<component :is"...">&#xff09;&#xff0c;…

【代码随想录】有序数组的平方

本博文为《代码随想录》的学习笔记&#xff0c;原文链接&#xff1a;代码随想录 题目 977. 有序数组的平方 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&…

6种常用的AR跟踪方法

增强现实 (AR) 是一项令人着迷的技术&#xff0c;可将虚拟内容与现实世界无缝集成。实现这种无缝集成的关键组件之一是跟踪。各种类型的跟踪用于确定 AR 内容在环境中的准确位置和方向。本文介绍 AR 最常见的6种跟踪方法。 NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - Y…

ctfshow-web入门-sql注入(web191-web195)

目录 1、web191 2、web192 3、web193 4、web194 5、web195 1、web191 过滤了 ascii 使用 ord 代替&#xff1a; import requests import string url "http://a585c278-320a-40e7-841f-109b1e394caa.challenge.ctf.show/api/index.php" out for j in range(1…