2023-02-07
温故知新
00

目录

前言
Vue3构建前端项目
创建项目
启动项目
结果
Vue3新建内容并显示
新建Components
将新建的文件添加到页面
启动测试
Vue3使用接口获取并展示数据
创建接口调用方法
编写Http工具
编写接口调用方法
调用接口方法
启动测试:失败!
解决跨域问题
理论解决
最终解决
Vue3异步组件调用特殊引用
解决异步引用
启动测试:成功!!!

前言

本篇文章主要介绍一个后端开发(我),是如何一步一个坑的使用前端技术Vue3搭建前端项目的。

首先提一下技术选型,现在前端技术框架真的是如雨后春笋啊!对于我这种半吊子来说,了解的越多越迷茫,最后还是选则了以前有用过的vue,使用了比较新的vue3,用起来才发现,和以前的vue2差别好大呀!完全有点无从下手,还专门找了个B站教学视频简单了看了一下(【vue3+Typescript项目实战】ps:感觉老师单词老是打错😂)。

Vue3构建前端项目

创建项目

sh
# 初始化vue项目。没有vue环境会提示安装,选择`y`,自动安装 npm init vue@latest
  • 输出
sh
Need to install the following packages: [email protected] Ok to proceed? (y) y # 会让你先输入项目名,此处输入books # 下列为选择环境安装,根据自身所需选择 yes or no 即可 √ Add TypeScript? ... No / Yes √ Add JSX Support? ... No / Yes √ Add Pinia for state management? ... No / Yes √ Add Vitest for Unit Testing? ... No / Yes √ Add Cypress for both Unit and End-to-End testing? ... No / Yes √ Add ESLint for code quality? ... No / Yes √ Add Prettier for code formatting? ... No / Yes Scaffolding project in E:\code\DingDangDog_sapce\ddd-cashbook\books... Done. Now run: cd books npm install npm run dev

启动项目

  • 进入books文件夹(上一步创建时,根据输入的项目名自动创建的源码文件夹),执行以下命令
sh
# 1、安装依赖 npm install # 输出 added 258 packages in 16s # 2、运行 npm run dev # 输出 > [email protected] dev > vite VITE v3.2.2 ready in 433 ms ➜ Local: http://localhost:5173/ ➜ Network: use --host to expose
  • 访问浏览器,Yes,You did it! (有点尬😂)

image-20221102171938164

结果

  • 感觉还行,先用这个试试吧

Vue3新建内容并显示

新建Components

  • 新建文件/src/components/FlowTable.vue
  • 其中<script setup lang="ts">这个叫做语法糖新东西?着实难为了我好久!!!
html
<template> <div>{{ flowPage }} </div> </template> <script setup lang="ts"> import type { FlowPage } from '../types/flow'; // 初始化假数据,用于展示验证 const flowPage: FlowPage = { pageNum: 1, pageSize: 1, dataList: [{ id: 1, day: new Date(), name: "测试", description: "测试流水", money: 1, type: "测试类型", }], totalNum: 1 }; // 将需要对外暴露的方法和对象添加到这里 defineExpose({ flowPage }); </script> <style scoped> </style>

将新建的文件添加到页面

  • /src/App.vue文件中添加刚才新建的文件,并使用,如下代码中的import FlowTable from './components/FlowTable.vue'<FlowTable/>
html
<script setup lang="ts"> import HelloWorld from './components/HelloWorld.vue' import TheWelcome from './components/TheWelcome.vue' import FlowTable from './components/FlowTable.vue' </script> <template> <header> <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" /> <div class="wrapper"> <FlowTable/> <HelloWorld msg="You did it!" /> </div> </header> <main> <TheWelcome /> </main> </template> <style scoped> header { line-height: 1.5; } .logo { display: block; margin: 0 auto 2rem; } @media (min-width: 1024px) { header { display: flex; place-items: center; padding-right: calc(var(--section-gap) / 2); } .logo { margin: 0 2rem 0 0; } header .wrapper { display: flex; place-items: flex-start; flex-wrap: wrap; } } </style>

启动测试

  • 项目根目录下,直接执行npm run dev即可

image-20221102215544987

Vue3使用接口获取并展示数据

建议先具备一个正常访问的后端服务,后续会有跨域调用测试。

经过以上步骤,基本架构路线只差最后一步,就是调用真实的数据接口,将上一步展示的数据替换成接口获取到的数据,如果这一步走通了,剩下的就是填充代码的问题了。接下来就来做这一步吧!

创建接口调用方法

编写Http工具

  • 新建/src/api/index.ts
  • 去百度搜axios-http调用工具封装应该能找到很多类似的源码,以下代码是我看了个教程自己手打:
typescript
/** * 封装http请求工具 */ import axios from 'axios' import { ElMessage } from 'element-plus' // 创建http调用者 const $http = axios.create({ // 服务地址 baseURL: 'http://localhost:3000/api', timeout: 2000, headers: { "Content-Type": "application/json;chartset=utf-8" } }) // 拦截请求,为请求header中增加token【暂时无用】 $http.interceptors.request.use(config => { // baseURL/headers 属性可能不存在,若不存在设置默认值 config.baseURL = config.baseURL || ''; config.headers = config.headers || {}; // 如果访问登录接口,则清除当前缓存token if (config.baseURL?.indexOf('/login') >= 0) { localStorage.removeItem('token'); config.headers.token = null; return config; } if (localStorage.getItem('token')) { config.headers.token = localStorage.getItem('token') || ''; } return config; }) // 响应拦截:解析响应结果,返回数据或捕获异常 $http.interceptors.response.use(res => { if (res.data.code != 200) { ElMessage.error(res.data.message); return Promise.reject(res.data); } return res.data }, err => { console.log(err); }) export default $http;

编写接口调用方法

  • 新建/src/api/api.ts
typescript
import $http from './index' import type { FlowPage } from '../types/flow'; /** * 查询流水 * @returns FlowPage */ export async function getFlows(): Promise<FlowPage> { return $http({ url: "/flow/getAll", method: "get" }) }

调用接口方法

  • 修改FlowTable.vue文件
html
<template> <div>{{ flowPage }} </div> </template> <script setup lang="ts"> import { getFlows } from '../api/api' import type { FlowPage } from '../types/flow'; // 初始化假数据,用于展示验证 // const flowPage: FlowPage = { // pageNum: 1, // pageSize: 1, // dataList: [{ // id: 1, // day: new Date(), // name: "测试", // description: "测试流水", // money: 1, // type: "测试类型", // }], // totalNum: 1 // }; const flowPage: FlowPage = await getFlows(); // 将需要对外暴露的方法和对象添加到这里 defineExpose({ flowPage }); </script> <style scoped> </style>
  • 这里发现个坑,vue内引用其他typescript文件不能写src/api,启动会报找不到文件的错,所以我都改成了../api,报错如下:
sh
21:48:26 [vite] Internal server error: Failed to resolve import "src/api/api" from "src\components\FlowTable.vue". Does the file exist? Plugin: vite:import-analysis File: E:/code/DingDangDog_sapce/ddd-cashbook/books/src/components/FlowTable.vue:7:25 1 | import { withAsyncContext as _withAsyncContext, defineComponent as _defineComponent } from "vue"; 2 | import { getFlows } from "src/api/api"; | ^ 3 | const _sfc_main = /* @__PURE__ */ _defineComponent({ 4 | __name: "FlowTable", at formatError (file:///E:/code/DingDangDog_sapce/ddd-cashbook/books/node_modules/vite/dist/node/chunks/dep-c842e491.js:41168:46) at TransformContext.error (file:///E:/code/DingDangDog_sapce/ddd-cashbook/books/node_modules/vite/dist/node/chunks/dep-c842e491.js:41164:19) at normalizeUrl (file:///E:/code/DingDangDog_sapce/ddd-cashbook/books/node_modules/vite/dist/node/chunks/dep-c842e491.js:38032:33) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async TransformContext.transform (file:///E:/code/DingDangDog_sapce/ddd-cashbook/books/node_modules/vite/dist/node/chunks/dep-c842e491.js:38165:47) at async Object.transform (file:///E:/code/DingDangDog_sapce/ddd-cashbook/books/node_modules/vite/dist/node/chunks/dep-c842e491.js:41421:30) at async loadAndTransform (file:///E:/code/DingDangDog_sapce/ddd-cashbook/books/node_modules/vite/dist/node/chunks/dep-c842e491.js:37808:29)

启动测试:失败!

  • 依然是直接执行npm run dev
  • 如下图,你会发现启动正常,但是页面并没有展示出来数据。此时用处你前端技术的基本功:F12,可以看到接口报错了,但是你又会发现,错误码是200,什么鬼,200不是成功吗?此时就是遇到了前后端分离必然的、闻名不如见面的跨域问题

image-20221102220647992

  • 接口我已经偷偷摸摸的写了,不是接口有问题,就是跨域问题Postman截图为证:

image-20221102220514815

解决跨域问题

理论解决

最终解决

vue技巧(九)跨域及跨域配置不生效原因探究】感谢这篇博客最后的总结!!!

推荐再axios请求发送时不要添加ip port,而是再代理转发时通过target参数配置

  • 修改index.ts文件,把baseURL中的http://localhost:3000删掉即可,修改后如下

    typescript
    /** * 封装http请求工具 */ import axios from 'axios' import { ElMessage } from 'element-plus' // 创建http调用者 const $http = axios.create({ baseURL: '/api', timeout: 2000, headers: { "Content-Type": "application/json;chartset=utf-8" } }) // 拦截请求,为请求header中增加token $http.interceptors.request.use(config => { // baseURL/headers 属性可能不存在,若不存在设置默认值 config.baseURL = config.baseURL || ''; config.headers = config.headers || {}; // 如果访问登录接口,则清除当前缓存token if (config.baseURL?.indexOf('/login') >= 0) { localStorage.removeItem('token'); config.headers.token = null; return config; } if (localStorage.getItem('token')) { config.headers.token = localStorage.getItem('token') || ''; } return config; }) // 响应拦截:解析响应结果,返回数据或捕获异常 $http.interceptors.response.use(res => { if (res.data.code != 200) { ElMessage.error(res.data.message); return Promise.reject(res.data); } return res.data }, err => { console.log(err); }) export default $http;
  • 修改vite.config.ts文件

    typescript
    import { fileURLToPath, URL } from 'node:url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }, server: { // 本服务暴露的端口 host: '127.0.0.1', port: 8080, // 跨域配置 proxy: { // /api相关接口跨域配置 '/api': { //实际请求地址 target: 'http://127.0.0.1:3000/api', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, "") }, } } })

启动测试:失败!

  • 经过解决跨域问题最终是把跨域问题解决了,但是又出现了新的问题,那就是数据请求出来了,但是没有展示出来。。。我就不说问题发现和解决的详细经过了,直接放问题原因和解决办法。

Vue3异步组件调用特殊引用

解决异步引用

  • 修改App.vue(即引用异步组件的文件),FlowTable.vue的引用和使用方式均有改变。。
html
<script setup lang="ts"> import HelloWorld from './components/HelloWorld.vue' import TheWelcome from './components/TheWelcome.vue' import { defineAsyncComponent } from 'vue' const FlowTable = defineAsyncComponent(() => import("./components/FlowTable.vue")); </script> <template> <header> <img alt="Vue logo" class="logo" src="./assets/logo.svg" width="125" height="125" /> <div class="wrapper"> <Suspense> <template #default> <FlowTable/> </template> <template #fallback> <div>加载中...</div> </template> </Suspense> <HelloWorld msg="You did it!" /> </div> </header> <main> <TheWelcome /> </main> </template> <style scoped> header { line-height: 1.5; } .logo { display: block; margin: 0 auto 2rem; } @media (min-width: 1024px) { header { display: flex; place-items: center; padding-right: calc(var(--section-gap) / 2); } .logo { margin: 0 2rem 0 0; } header .wrapper { display: flex; place-items: flex-start; flex-wrap: wrap; } } </style>

启动测试:成功!!!

  • 直接上图吧,乏了。。。

image-20221102230638541

如果对你有用的话,可以打赏哦
打赏
ali pay
wechat pay

本文作者:DingDangDog

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!