Skip to content

Commit

Permalink
Merge pull request #3 from grtsinry43/main
Browse files Browse the repository at this point in the history
feat: 书写前端规范,解决已知问题
grtsinry43 authored Jul 30, 2024
2 parents 21e19e3 + 6d3d204 commit cc9c996
Showing 4 changed files with 417 additions and 27 deletions.
8 changes: 6 additions & 2 deletions .vitepress/config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {defineConfig} from 'vitepress'
import {defineConfig} from 'vitepress';

// https://vitepress.dev/reference/site-config
export default defineConfig({
@@ -7,9 +7,13 @@ export default defineConfig({
titleTemplate: ':title - 升华工作室文档站',
description: "中南大学升华工作室的文档网站,包含代码规范,技术教学文档,项目文档等",
lastUpdated: true,
publicDir: 'public',
sitemap: {
hostname: 'https://docs.54sher.com'
},
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
logo: 'logo.png',
logo: '/logo.png',
nav: [
{text: '主页', link: '/', activeMatch: '^/$'},
{text: '代码规范', link: '/styleguide/', activeMatch: '^/styleguide/'},
Binary file added public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 6 additions & 1 deletion styleguide/index.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
# 代码规范

::: tip
这部分内容同步自 [Grtsinry43's Docs](https://docs.grtsinry43.com/)最后一次更新于2024-07-24。
这部分内容同步自 [Grtsinry43's Docs](https://docs.grtsinry43.com/)最后一次更新于 2024-07-24。
:::
::: info
这里是我个人的代码规范,参考了大型开源项目以及一些知名企业的开发规范,希望大家能够有所收获,也能不断完善这个规范。
:::

## 为什么要有代码规范?

首先当前的技术趋势都是前后端分离,我们要保证相互的协作开发,需要有详细的代码规范,这样才能保证代码的可读性,可维护性,可扩展性,可测试性等等。
其次,由于代码需要不断维护,不断调整迭代,必要时进行重构,所以我们需要有一套规范来保证代码的质量,减少代码的维护成本。
最后,学习代码规范也便于以后就业,学会了普遍的代码规范,对以后的工作 **(准确是和同事的交流和协作)** 也是有帮助的。

## 这里包含了什么?

首先是前后端(前端采用 `Vue.js`,后端采用 `SpringBoot``FastAPI`)的代码以及规范,
然后是数据库的设计规范,运维和产品的相关内容,最后是一些常用的工具的使用规范。
429 changes: 405 additions & 24 deletions styleguide/part2.md
Original file line number Diff line number Diff line change
@@ -8,9 +8,11 @@

在项目中引入 `axios` 后,我们需要对其进行封装,以便于更好地处理请求和响应,比如添加请求拦截器,响应拦截器,统一处理错误等等。

首先,这是我在项目中经常使用的 `axios` 封装,大家可以参考一下(这里用了`vant`的弹窗组件,可以根据自己的项目需求进行修改,比如`El-Message`什么的都可以哇):
首先,这是我在项目中经常使用的 `axios` 封装,大家可以参考一下(这里用了 `vant`
的弹窗组件,可以根据自己的项目需求进行修改,比如 `El-Message` 什么的都可以哇):

::: details 点我查看代码

```js
import axios from "axios";
import {showDialog, showNotify} from "vant";
@@ -26,7 +28,7 @@ const ins = axios.create({
});
ins.interceptors.response.use(
function (resp) {
// 如果响应头中有token,则存储到localStorage中,以便下次请求时携带
// 如果响应头中有 token,则存储到 localStorage 中,以便下次请求时携带
console.log(resp.headers)
if (resp.headers.Authorization) {
console.log("存储token")
@@ -60,10 +62,10 @@ ins.interceptors.response.use(

ins.interceptors.request.use(
function (config) {
// 在localStorage中获取token
// 在 localStorage 中获取 token
const token = getToken();
if (token) {
// 如果存在token,则在请求头中携带token
// 如果存在 token,则在请求头中携带 token
config.headers.Authorization = `Bearer ${token}`;
}
return config;
@@ -78,11 +80,13 @@ ins.interceptors.request.use(

export default ins;
```

:::

我们开始逐步讲解:

1. 首先我们引入了 `axios`,然后创建了一个实例 `ins`,并设置了一些默认值,比如 `baseURL``timeout``headers` 等等。

```js {2}
const ins = axios.create({
baseURL: "/api/v2", // 设置基础URL
@@ -92,33 +96,37 @@ const ins = axios.create({
},
});
```

其中,`baseURL` 一定要确定好,这样在请求时就不用每次都写全路径了,这里补充一下,如果你正在本地开发,一定会设置代理服务器:

```js {11-19}
export default defineConfig({
plugins: [
vue(),
VueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
}
plugins: [
vue(),
VueDevTools(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
host: '0.0.0.0',
}
server: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
}
},
host: '0.0.0.0',
}
})
```
2.接下来就是拦截器的设置,这里我们设置了两个拦截器,一个是请求拦截器,一个是响应拦截器。
响应拦截器主要用来处理响应数据,比如判断响应头中是否有 `token`,如果有则存储到 `localStorage` 中,以便下次请求时携带;判断响应数据中的 `code` 字段,如果不为 0 则弹出提示框,当没有报错就直接返回数据。
响应拦截器主要用来处理响应数据,比如判断响应头中是否有 `token`,如果有则存储到 `localStorage`
中,以便下次请求时携带;判断响应数据中的 `code` 字段,如果不为 0 则弹出提示框,当没有报错就直接返回数据。
```js {23}
ins.interceptors.response.use(
function (resp) {
@@ -155,10 +163,11 @@ ins.interceptors.response.use(
```
::: tip
注意下这里的写法哦,我们获取`resp.data.data`,这样直接就是我们需要的数据了,不用每次都去解构,这样也方便我们后续的处理。
注意下这里的写法哦,我们获取 `resp.data.data`,这样直接就是我们需要的数据了,不用每次都去解构,这样也方便我们后续的处理。
:::
请求拦截器主要用来处理请求数据,比如在请求头中添加 `token`,这样后端就可以根据 `token` 来判断用户的身份,然后返回相应的数据。
```js {7}
ins.interceptors.request.use(
function (config) {
@@ -185,6 +194,8 @@ ins.interceptors.request.use(
首先,我们明确一下项目的目录结构,这里我推荐一种目录结构,大家可以参考一下:
::: details 点我查看目录结构
```
├── public
│ ├── favicon.ico
@@ -202,7 +213,7 @@ ins.interceptors.request.use(
│ ├── directives // 自定义指令
│ │ ├── index.js
│ │ └── ...
│ ├── mocks // 模拟数据,如果使用Vite mock服务额可能会在根目录下
│ ├── mock // 模拟数据,如果使用Vite mock服务额可能会在根目录下
│ │ ├── index.js
│ │ └── ...
│ ├── router // 路由相关
@@ -229,3 +240,373 @@ ins.interceptors.request.use(
└── ...
```
:::
### /api
这部分主要是存放接口相关的文件,比如 `user.js``article.js`
等等,这里一般会根据模块来划分,比如用户相关的接口就放在 `user.js` 中,文章相关的接口就放在 `article.js` 中。
在分别写某个接口之前,首先建议要用 `axios` 封装好,这样在写接口时就可以直接调用封装好的 `axios` 实例了。
(这里可以参考上面的 `axios` 封装)
对于每个接口尽量要写好注释,说明这个接口的作用,参数,返回值等等,这样方便后续的维护和修改。
比如像以下这样:要让人一眼看出来这个接口是干什么的,传入什么参数,返回什么值。
::: tip
如果你使用的 `WebStorm` 或者 `VSCode`,可以直接在函数上方 `/**`,然后回车,就会自动生成注释模板,然后你只需要填写参数,返回值等等就可以了。
:::
```js
/**
* 获取成员签到信息(用于队长或者指导老师)
* @param {String} id 成员 id
* @returns {Promise <AxiosResponse<any> >} 成员签到信息
*/
export function getMemberSignInfo(id) {
return ins.get("/sign/detail", {
params: {
memberid: id,
}
});
}
```
### /assets
这个文件夹主要是存放静态资源,比如图片,字体等等,这里一般会根据类型来划分,比如图片就放在 `images`
文件夹中,字体就放在 `fonts` 文件夹中。
注意,由于使用`Webpack`打包,我们在引入静态资源时,一定要使用 `@` 来引入,这样可以避免路径错误。
```vue
<img src="@/assets/images/logo.png" alt="logo"/>
```
当然也可以在 script setup 中使用 `import` 来引入(推荐这个吧,这个管理起来比较舒服):
```js
import logo from '@/assets/images/logo.png';
```
```vue
<img :src="logo" alt="logo"/>
```
### /components
这个目录主要是存放公共组件,公共的组件代码一定要封装好,充分解耦合
比如侧边栏,头部导航栏,底部导航栏等等,这些组件一定要封装好,方便多次使用。
这里最好要考虑好组件的复用性,可维护性,可扩展性等等,这样可以减少代码的冗余,提高开发效率。
比如说通过 `props` 来传递数据,通过 `emit` 来触发事件,通过 `slots` 来插槽等等。
### /directives
这个目录主要是存放自定义指令,比如 `v-permission``v-ellipsis`
等等,这些指令一般会根据功能来划分,比如权限相关的指令就放在 `permission.js` 中,文本截断相关的指令就放在 `ellipsis.js` 中。
可能大家用的不多吧...除了我举的这两个例子,还可以 `v-focus``v-loading` 等等,这些指令可以方便我们在模板中使用,减少代码的冗余,提高开发效率。
### /mock
这个目录主要是存放模拟数据,这个目录一般会根据模块来划分,比如用户相关的模拟数据就放在 `user.js`
中,文章相关的模拟数据就放在 `article.js` 中。
方便前端攻城狮——独!立!开!发!不用再苦求后端小伙伴啦(逃
具体的使用方法可以参考 `mockjs` 的官方文档,这里给一下具体的链接:[Mock.js](http://mockjs.com/),当然
代码的编写也是要有规范的,并且要和接口文档保持一致,这样才能更好地测试和开发。
这里举个栗子:
```js
import Mock from "mockjs";
import qs from "querystring";

Mock.mock(/^\/api\/message\/?(\?.+)?$/, "get", function (options) {
const query = qs.parse(options.url);

return Mock.mock({
code: 0,
msg: "",
data: {
total: 52,
[`rows|${query.limit || 10}`]: [
{
id: "@guid",
nickname: "@cname",
content: "@cparagraph(1, 10)",
createDate: Date.now(),
"avatar|1": [
"https://balabala/avatar6.jpg",
"https://balabala/avatar4.jpg",
"https://balabala/avatar8.jpg",
"https://balabala/avatar2.jpg",
],
},
],
},
});
});
```
还有,最后建议创建一个 `index.js` 文件,然后在这个文件中引入所有的模拟数据,这样方便管理,方便维护。
`main.js` 中引入这个文件,这样就可以在开发时直接使用模拟数据了。
并且开发完成直接注释这行代码就可以了:)
### /router
这个目录主要是存放路由相关的文件,比如 `index.js``guard.js` 等等
要善于使用路由懒加载,还有路由守卫,这样可以提高页面的加载速度,保护页面的安全性。
另外,根据路由的`meta`字段,可以实现权限控制,比如某个页面登录之后才能访问,这样可以提高系统的安全性。
具体这样写就可以啦:
```js {21}
import {createRouter, createWebHistory} from 'vue-router'
import Login from "@/views/Login.vue";

const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
redirect: '/login',
},
{
path: '/login',
name: '登录',
component: Login,
meta: {title: '登录'}
},
{
path: '/myHome',
name: '我的',
component: () => import('../views/MyHome.vue'),
meta: {title: '我的', auth: true}
},
{
path: '/index',
name: '首页',
component: () => import('../views/HomeView.vue'),
meta: {title: '打卡', auth: true}
},
//...更多的路由
]
});

export default router;
```
当然阴间的微信`js-sdk`也可以切换路由的时候进行初始化,这样可以避免一些问题。
### /store
这个目录主要是存放状态管理相关的文件,一般Vue3都会使用`Pinia`,这里就不多说了,如果使用`Vuex`
这里一般会根据模块来划分,比如用户相关的状态就放在 `user.js` 中,文章相关的状态就放在 `article.js` 中。
没什么好说的,就是状态管理,方便数据的共享,方便数据的修改,方便数据的监听等等。
写的方法按照官方的例子就好,额用一个之前项目的例子吧:
```js
/**
* @name UserStore
* @description 用户信息
* 这里打开网页时就会通过携带wx相关信息向后端请求,获取信息并存储
*/
import {defineStore} from 'pinia'

export const useUserStore = defineStore('user', {
state: () => {
return {
name: '',
phone: '',
title: '',
belong: '',
avatar: '',
}
},
actions: {
/**
* @name setUser
* @param data 传入的data应该是一个对象,包含name, phone, title
*/
setUser(data) {
this.name = data.name;
this.phone = data.phone;
this.title = data.title;
},
/**
* @name setAvatar
* @param avatar 传入的avatar应该是一个字符串,表示头像的url
*/
setAvatar(avatar) {
this.avatar = avatar;
}
},
});

```
在其他的地方使用的时候最好是先setup中定义一个对象,然后在模板中使用。
```js
import {useUserStore} from "@/store/user";

const user = useUserStore();
```
### /styles
样式文件,最好用`less`或者`sass`,这样可以方便我们使用变量,函数等等。
建议包含这些文件:
- `golbal.less`:全局初始化
```less
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

a {
text-decoration: none;
color: inherit;
}

ul, ol {
list-style: none;
}

```
- `variables.less`:变量
```less
:root {
--primary: #1890ff; // 全局主色
--bg: #ffffff; // 全局背景
--font: #333333; // 全局字体颜色
--warning: #faad14; // 警告
--success: #52c41a; // 成功
--error: #f5222d; // 错误
--info: #1890ff; // 信息
--disabled: #bfbfbf; // 失效
--link: #1890ff; // 链接
--hover: #001764; // hover
}

@primary: var(--primary);
@bg: var(--bg);
@font: var(--font);
@warning: var(--warning);
@success: var(--success);
@error: var(--error);
@info: var(--info);
@disabled: var(--disabled);
@link: var(--link);
@hover: var(--hover);

@media (prefers-color-scheme: dark) {
:root {
--primary: #718dff; // 全局主色
--bg: #1d1e21; // 全局背景
--font: #ffffff; // 全局字体颜色
--warning: #faad14; // 警告
--success: #a8ff7d; // 成功
--error: #f5222d; // 错误
--info: #80c1ff; // 信息
--disabled: #4e4e4e; // 失效
--link: #a0b5ff; // 链接
--hover: #d5e8ff; // hover
}
}
```
接下来的 `less` 文件就可以引入这个文件,然后使用这些变量了。
- `mixin.less`:混合(公共样式)
```less
// 这里就随便举个例子吧,就是公共样式
@self-conter: {
display: flex;
justify-content: center;
align-items: center;
}
```
其他的文件按模块来划分,比如 `login.less``home.less` 等等,
另外less相互引入的时候,最好是使用`@import`,这样可以避免路径错误。
```less
@import "@/styles/mixin.less";

.manage-team-container {
.main-container;
overflow-y: auto;
}
```
### /utils
工具类,不多说了,就是一些工具函数,比如时间格式化,深拷贝,浏览器判断等等,这些函数一定要封装好,方便多次使用。
### /views
页面文件,这里一般会根据模块来划分,不是很复杂的页面就直接放在这个目录下,如果复杂或者存在子页面,可以再细分,创建目录。
## 2.3 - JavaScript 规范
:::warning
这个真的是重中之重,一定要遵守,不然后面维护起来会很痛苦的。
对于一个团队的代码规范,以及个人的代码风格,都是举足轻重的。
:::
:::tip
强烈建议大家书写代码时启用 `eslint``prettier` 等工具(尤其是 `ESLint`
:::
### 命名规范
在 JavaScript 中,变量名,函数名,类名等等都是有规范的
务必要遵守驼峰命名法(小驼峰),比如 `userName``getUserInfo`等等
这样可以提高代码的可读性,减少歧义,方便维护。
### 缩进
我们希望在纯 JavaScript 文件中使用四个空格缩进(更清晰),而对于 Vue 和 React ,我们希望使用两个空格缩进(更紧凑)。
### 分号
在 JavaScript 中,分号是可选的,但是我们建议在每行语句的末尾加上分号,这样可以避免一些错误。
### 注释
注释真的非常重要,尤其是协作开发和代码的流传与维护(?
在 JavaScript 中,我们建议使用单行注释 `//`,多行注释 `/* */`,文档注释 `/** */`等等
在写注释时,一定要写清楚这段代码的作用,这样方便后续的维护和修改。
强烈建议书写文档注释!!并且署名,这样方便他人查看,如果有不清楚的地方,可以直接找到你。

就像以下这样:

```js
/**
* @name Permission
* @description 通过路由守卫实现登录验证
* @author Grtsinry43
* @date 2024-07-24
* 本段代码灵感来源于vue-element-admin,当用户已登录时,会自动获取用户信息,
* 当用户访问需要登录的页面时,会自动跳转到登录页面,鉴权后再跳转回原页面
*/
```

### 函数风格

这里以 Vue 为例,比如一些业务处理,命名为 ...Handle,
比如submitHandle,clickHandle等等,这样可以方便我们区分这个函数是用来处理什么的。

参数尽量让人一看就知道要传什么,比如 `durationSeconds`好于 `duration``isShow`好于 `show`等等。
当然即使这样,也要写好注释,方便他人查看。

## 2.4 - 常用组件库的使用规范

[//]: # (TODO: 待补充)

0 comments on commit cc9c996

Please sign in to comment.