Skip to main content

One post tagged with "前后端分离"

View All Tags

· 10 min read
tjuzyp

本系列文章适用于前端开发初学者,我将从环境搭建开始,逐步介绍如何开发一个基于 Vue 3.x & Ant Design Vue 4.x 的网站,如果哪位朋友发现其中存在技术错误或其他不当之处,请及时指出,如果有任何疑问或需要帮助,也可以在评论区留言,我将尽我所能一一解答,谢谢。

本篇文章将介绍前后端分离项目中前端是如何请求后端接口数据的:接口方法怎么写、页面怎么集成、后端服务怎么配置?与此同时,我已经开发完成三国演义人物大全页面,大家可以在三国史诗馆网站看到更新,但细节将推迟到下一章中再进行介绍。

本章更新内容:

  1. 安装 axios 插件
  2. 安装 ant-design/icons 图标
  3. 增加接口请求相关内容
  4. 增加人物大全页面并将其设置为首页
  5. 增加后端服务配置

安装 axios 插件

Axios 是一个基于 promise 的网络请求库,作用于 node.js 和浏览器中,通常用于 Vue 项目访问后端接口,在 sanguo-ui 目录下执行下方命令进行安装:

# 安装 axios
npm install axios --save

操作截图如下:

安装 axios

安装 ant-design/icons 图标

Ant Design 图标是语义化的矢量图形,需要安装 @ant-design/icons-vue 图标组件包,在 sanguo-ui 目录下执行下方命令进行安装:

# 安装 ant-design/icons
npm install @ant-design/icons-vue --save

操作截图如下:

安装 ant-design/icons

接口请求工具类

增加 utils/request.js 文件:

/src/utils/request.js
import axios from 'axios';

// 创建axios实例
const request = axios.create({
// API请求的默认前缀
baseURL: '/api',
// 请求超时时间
timeout: 20000,
// 请求头(必须加,否则transformRequest后数据格式不正确)
headers: {'Content-Type': 'application/json;charset=UTF-8'},
// 修改请求数据
transformRequest: [function (data, headers) {
let req = {};
req.data = data;
return JSON.stringify(req);
}],
});

export default request;

我只配置了几个必要的参数,更多参数请参考 Axios 官网,以上参数的简单介绍如下:

  • baseURL:用于标识需要请求后端的 url 地址,比如 /api/login 会请求后端 http://host:ip/login 接口,而 /apix/login 则只在前端路由中查找此地址
  • timeout:接口超时时间,如果系统中存在已知很慢的接口,需要将此值调大
  • headers:与后端协定的请求体格式
  • transformRequest:这里可以对请求体进行二次封装,可以增加一些通用的数据,例如当前登陆用户等

增加接口请求方法

为了便于维护,我将所有的接口文件都放在了 /src/api 目录下,并且目录结构尽量与 /src/views 保持一致。

首先第一个增加的接口请求方法是人物列表,增加 record/personage.js 文件:

/src/api/record/personage.js
import request from '@/utils/request';

// 获取人物列表
export function getPage(query) {
// 设置请求为PageQuery
query.service = 'PageQuery';
// 发送请求
return request({
url: '/record/personage/getPage',
method: 'post',
data: query
});
}

这个方法中向接口 /record/personage/getPage 发送 post 请求并获取响应数据,其中 PageQuery 是与后端约定的请求体数据类型,如果漏掉或写错,后端将无法正常解析请求。

页面中获取数据

页面文件主要放在 /src/components/src/views 两个目录下,前者主要是公共组件,后者是各个具体页面,目录结构一般按照功能划分。

第一个增加的页面是人物大全,增加 record/personage/index.vue 文件:

/src/views/record/personage/index.vue
<template>
<a-layout style="min-height: calc(100vh - 64px - 70px);">
<a-page-header style="padding-left: 0; background-color: transparent" title="人物大全" sub-title="滚滚长江东逝水,浪花淘尽英雄"/>
<a-layout style="background: #fff">
<a-layout-content style="padding: 24px;">
...
<!-- 人物卡片列表 -->
<a-row :gutter="[8,8]">
<a-col v-for="personage in personageList" :xs="12" :sm="8" :lg="4">
<a-card :loading="personage.loading" class="card" @click="detail(personage)" hoverable>
...
</a-card>
</a-col>
</a-row>
...
</a-layout-content>
...
</a-layout>
</a-layout>
</template>

<script>
...
import {getPage} from '@/api/record/personage';
...

export default defineComponent({
setup() {
const state = reactive({
// 遮罩层
loading: true,
// 查询参数
query: {
param: {},
pageNum: 1,
pageSize: 30,
sortField: 'CREATE_TIME',
sortOrder: 'ASC'
},
// 人物列表
personageList: [],
personageTotal: 0
});
...
// 查询列表
const loadPage = () => {
// 打开加载
state.loading = true;
...
// 请求数据
getPage(state.query).then(response => {
if (response.data.code == 200) {
// 获取真正返回结果
let data = response.data.data;
// 更新人物列表数据
state.personageList = data.list;
// 更新人物总数
state.personageTotal = data.total;
// 关闭加载
state.loading = false;
} else {
// 提示失败
requestFailed(response.data);
}
}).catch((error) => {
// 提示失败
requestFailed(error);
});
};
// 重置
const resetQuery = () => {
// 重置查询条件
...
// 查询列表
loadPage();
};
...
// 加载页面
onMounted(() => {
...
resetQuery();
});

return {
...toRefs(state),
...
};
}
});
</script>

<style scoped>
...
</style>

页面的整体布局是标题、副标题、内容、分页,其中前两个较简单,内容与分页将推迟到下一章中再进行介绍,此处主要对页面的数据交互进行介绍:

  1. 使用生命周期中的 onMounted 方法作为入口,即页面加载完成后调用查询数据的方法 resetQuery -> loadPage
  2. 在 loadPage 方法中调用 getPage 方法(上方已经 import 引入),得到数据集 personageList 并放入 reactive 变量中
  3. 使用 v-for 遍历 personageList 拼装元素,展示页面内容

增加页面路由

完成页面后,需为页面增加路由,修改 router/index.js 文件,增加以下内容:

/src/router/index.js
const routes = [
...
{
path: '/personage',
component: Layout,
children: [
{
path: 'list',
meta: {
title: '人物大全',
icon: 'TeamOutlined',
key: 'personage:list'
},
component: () => import('@/views/record/personage/index.vue')
}
]
},
...
];

我要把刚才写的人物大全页面作为网站首页,所以我把首页 views/index.vue 文件修改为如下内容:

/src/views/index.vue
<template>
<personage-list msg="欢迎您的访问"/>
</template>

<script>
import {defineComponent} from 'vue';
import PersonageList from './record/personage/index';

export default defineComponent({
components: {
PersonageList
}
});
</script>

<style scoped></style>

配置后端地址

完成以上内容后,前端工作已经结束,但是 axios 请求的后端地址还没有,这里也是比较难懂的一块内容,我只介绍我熟悉的方式。

开发环境

在开发环境中配置后端地址,需要在 vue.config.js 文件中增加以下内容:

/vue.config.js
...
module.exports = defineConfig({
...
// 开发环境的设置
devServer: {
// 端口
port: 9518,
// 设置代理
proxy: {
// 转发前缀为/api的请求
"/api": {
// 转发目的地址
target: "http://127.0.0.1:9517/",
// 设置同源,解决跨域问题
changeOrigin: true,
// 路径重写
pathRewrite: {
// 去掉前缀
"^/api": ""
}
}
}
}
...
});

这里的配置并非只针对后端地址,其实是对开发服务的配置,每个配置项都加了注释,所以不再赘述。

生产环境

所谓生产环境,是相对于开发环境而言,更准确的说是我在 Nginx 下做的配置,以我的网站为例,可以通过以下配置完成接口请求的转发:

/nginx.conf
...
http {
...
server {
listen 80;
server_name www.sanguo.fun;
location / {
root /root/www.sanguo.fun/www-root;
index index.html;
try_files $uri $uri/ /index.html;
}
location /api/ {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET,POST,OPTIONS,PUT,DELETE';
add_header Access-Control-Allow-Headers 'Token,DNT,X-Mx-ReqToken,keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
proxy_pass http://127.0.0.1:9517/;
}
}
}

更新后的页面

现在通过 npm run serve 命令启动前端项目,现在的页面如下图所示:

展示后端数据的人物大全页面


本篇文章到这里就结束了,欢迎关注后续更新。