規(guī)范

[toc]

1 工作流規(guī)范

1.1 git規(guī)范

1.1.1 分支管理規(guī)范

git版本管理中主要有以下幾種類型的分支:master、develop、feature、release、hotfix。

  1. 主分支master
    代碼庫應(yīng)該有且僅有一個(gè)。所有提供給用戶使用的正式版本,都在這個(gè)主分支上發(fā)布;
  2. 開發(fā)分支develop
    我們把開發(fā)用的分支,叫做develop分支。開發(fā)分支(develop)應(yīng)該總能夠獲得最新開發(fā)進(jìn)展的代碼。
  3. 臨時(shí)分支
    除了常設(shè)分支以外,還有一些臨時(shí)性分支,用于應(yīng)對一些特定目的的版本開發(fā)。臨時(shí)性分支主要有三種:
  • 功能feature分支
    feature分支是為了開發(fā)某種特定功能,從develop分支上面分出來的。開發(fā)完成后,要并入develop。功能分支的名字,可以采用xx-feature-[功能名稱/版本信息]的形式命名。
  • 預(yù)發(fā)布release分支
    release分支是指發(fā)布正式版本之前(即合并到master分支之前),我們可能需要有一個(gè)預(yù)發(fā)布的版本進(jìn)行測試而從develop創(chuàng)建的分支。
  • 修補(bǔ)bug hotfix分支
    正式發(fā)布以后,難免會(huì)出現(xiàn)bug。這時(shí)就需要?jiǎng)?chuàng)建一個(gè)分支,進(jìn)行bug修補(bǔ)。
    修補(bǔ)bug分支是從Master分支上面分出來的。修補(bǔ)結(jié)束以后,再合并進(jìn)master和develop分支。它的命名,可以采用hotfix-x的形式。
1.1.2 分支操作規(guī)范:

禁止master分支直接用來作為開發(fā)分支,針對開發(fā)新功能,從master分支拉出來一個(gè)作為本次上線開發(fā)分支。
其中一個(gè)fe對多個(gè)rd開發(fā)一個(gè)上線版本的多個(gè)功能點(diǎn),建議先從master分支拉出一個(gè)公共的版本開發(fā)分支用來上線,然后根據(jù)不同rd開發(fā)的功能區(qū)別建立分支,從master拉出分支,例如:xx-feature-dev1.1、xx-feature-dev1.1。開發(fā)完成后,合并到xx-feature-dev2.0分支,部署上線。

1.1.3 分支命名規(guī)范:

結(jié)合分支類型及我們的gitlab ci + rancher 自動(dòng)化部署方案,因此分支命名皆以開發(fā)人員姓名縮寫開頭+分支類型,如wy1-hotfix-[bug編號(hào)]、wy2-feature-[功能名稱/版本信息]。(不同數(shù)字用來區(qū)分開發(fā)人員的多套環(huán)境)

1.1.4 提交規(guī)范

commit message 的作用,可以提供更多的歷史信息,方便快速瀏覽。
其中commit message包含三個(gè)部分:header , body , footer。通常body和footer都可以省略。
header部分包含三個(gè)字段:type(必須)、scope(可選)、subject(必須)。

  • type(必須)
    • 用于說明 commit 的類別,只允許使用下面10個(gè)標(biāo)識(shí)。
      • feat:新功能(feature)
      • fix:修補(bǔ)bug
      • docs:文檔(documentation)
      • style: 格式(不影響代碼運(yùn)行的變動(dòng))
      • refactor:重構(gòu)(即不是新增功能,也不是修改bug的代碼變動(dòng))
      • perf:性能優(yōu)化
      • test:增加測試
      • chore:構(gòu)建過程或輔助工具的變動(dòng)
      • revert:回退
      • build:打包
  • scope(可選)
    • 用于說明 commit 影響的范圍,比如Button組件、store、首頁、路由等等,視項(xiàng)目不同而不同。
  • subject(必須)
    • commit 目的的簡短描述,不超過50個(gè)字符。
      • 以動(dòng)詞開頭,使用第一人稱現(xiàn)在時(shí),比如change,而不是changed或changes
      • 第一個(gè)字母小寫
      • 結(jié)尾不加句號(hào)(.)
        示例
git commit -m "feat: 新增用戶詳情頁接口"
git commit -m "fix: 修復(fù)用戶注冊時(shí)電話號(hào)碼校驗(yàn)邏輯問題"
git commit -m "docs: 新增項(xiàng)目Readme 文檔"

提交的代碼必須通過 eslint 的校驗(yàn)

1.2 上線流程

①打包 → ②預(yù)發(fā)布 → ③上線 → ④發(fā)布

  1. 如第一步打包失敗,查看打包的log,確認(rèn)原因后重新打包。
    常見原因1:上次上線后未發(fā)布,本次分支打包失敗;
    解決辦法:上次上線預(yù)發(fā)布后的版本進(jìn)行發(fā)布操作,之后將本次分支合并一下master,再次打包、預(yù)發(fā)布。
    常見原因 2:master分支上線,未勾選is_tag;
    選擇master分支→ build_type選擇「online」→ 勾選is_tag,再次打包:
    其中打包的校驗(yàn)邏輯如下圖所示:
    image.png
  2. 如第二步預(yù)發(fā)布失敗,查看預(yù)發(fā)布的log,確認(rèn)原因后重新打包,重新預(yù)發(fā)布。
    常見原因:落后master,未合并master不允許預(yù)發(fā)布上線。
    解決辦法:合并master,重新打包→ 預(yù)發(fā)布。
    其中預(yù)發(fā)布的校驗(yàn)規(guī)則如下圖所示:
    image.png

    如預(yù)發(fā)布成功,發(fā)現(xiàn)線上代碼有誤,可選擇取消預(yù)發(fā)布,包會(huì)從線上撤回。
  3. 如第四步發(fā)布失敗,查看發(fā)布的log,確認(rèn)原因后,在原來的基礎(chǔ)上,重新發(fā)布。
    如發(fā)布成功,即將上線分支合并到master。無需手動(dòng)合并。
    其中發(fā)布規(guī)則如下圖所示:


    image.png

uat上線流程如下:

  1. 提工單,在Jenkins綁定Job,綁定過后,打包頁面的build_type的列表里多一個(gè)uat的環(huán)境。
  2. 在上線系統(tǒng)申請要?jiǎng)?chuàng)建的模塊的環(huán)境,上線系統(tǒng)的命名規(guī)范是:產(chǎn)品線服務(wù)名環(huán)境名,以小哥管理平臺(tái)舉例,產(chǎn)品線為sds,服務(wù)名為fsds,環(huán)境為uat-master,則build_type為:sds_fsds_uat-master。
  3. 新建一個(gè)sds_fsds_uat-master,則可準(zhǔn)備打包了。

對不同分支的理解:
其中 master 分支一般和我們線上的版本同步。uat-master分支為我們的內(nèi)測分支,內(nèi)部同事可以在uat-master環(huán)境測試、體驗(yàn)我們的最新版本,原則上項(xiàng)目在上線前需將代碼同步至uat-master分支,讓 pm 及相關(guān)的同事測試,測試通過后再部署線上。

2 編碼規(guī)范

2.1 Javascript

2.1.1 JS 變量命名

命名方法:小駝峰式命名
命名規(guī)范:前綴應(yīng)當(dāng)是名詞。(函數(shù)的名字前綴為動(dòng)詞,以此區(qū)分變量和函數(shù))
命名建議:盡量在變量名字中體現(xiàn)所屬類型,如:length、count等表示數(shù)字類型;包含name、title表示為字符串類型。

// 推薦
const maxCount = 10;
const tableTitle = 'LoginTable';

// 不推薦
const setCount = 10;
const getTitle = 'LoginTable';
2.1.2 JS 函數(shù)命名

命名方法:小駝峰式命名法
命名規(guī)范:前綴應(yīng)當(dāng)為動(dòng)詞
命名建議:可使用常見動(dòng)詞約定

動(dòng)詞 含義 返回值
can 判斷是否可執(zhí)行某個(gè)動(dòng)作(權(quán)限) 函數(shù)返回一個(gè)布爾值。true:可執(zhí)行;false:不可執(zhí)行
has 判斷是否含有某個(gè)值 函數(shù)返回一個(gè)布爾值。true:含有此值;false:不含有此值
is 判斷是否為某個(gè)值 函數(shù)返回一個(gè)布爾值。true:為某個(gè)值;false:不為某個(gè)值
get 獲取某個(gè)值 函數(shù)返回一個(gè)非布爾值
set 設(shè)置某個(gè)值 無返回值、返回是否設(shè)置成功或者返回鏈?zhǔn)綄ο?/td>
load 加載某些數(shù)據(jù) 無返回值或者返回是否加載完成的結(jié)果
2.1.3 JS 常量命名命名方法:名稱全部大寫

命名規(guī)范:使用大寫字母和下劃線來組合命名,下劃線用以分割單詞
示例

const MAX_COUNT = 10;
const URL = 'http://www.sf-express.com/';  

2.2 Html

2.2.1 元素及標(biāo)簽閉合

HTML元素共有以下5種:
空元素:area、base、br、col、command、embed、hr、img、input、keygen、link、meta、param、source、track、wbr
原始文本元素:script、style
RCDATA元素:textarea、title
外來元素:來自MathML命名空間和SVG命名空間的元素。
常規(guī)元素:其他HTML允許的元素都稱為常規(guī)元素。

所有具有開始標(biāo)簽和結(jié)束標(biāo)簽的元素都要寫上起止標(biāo)簽,某些允許省略開始標(biāo)簽或和束標(biāo)簽的元素亦都要寫上。

<!-- 推薦  -->
<div>
    <h1>我是h1標(biāo)題</h1>
    <p>我是一段文字,我有始有終,瀏覽器能正確解析</p>
</div>
<br>
<!-- 不推薦  -->
<div>
    <h1>我是h1標(biāo)題</h1>
    <p>我是一段文字,我有始無終,瀏覽器亦能正確解析
</div>
<br/>
2.2.2 類型屬性

不需要為 CSS、JS 指定類型屬性,HTML5 中默認(rèn)已包含

<!-- 推薦  -->
<link rel="stylesheet" href="" >
<script src=""></script>
<!-- 不推薦  -->
<link rel="stylesheet" type="text/css" href="" >
<script type="text/javascript" src="" ></script>
2.2.3 元素屬性

元素屬性值使用雙引號(hào)語法
元素屬性值可以寫上的都寫上

<!-- 推薦  -->
<input type="text">
    
<input type="radio" name="name" checked="checked" >
<!-- 不推薦  -->
<input type=text>   
<input type='text'>
    
<input type="radio" name="name" checked >
2.2.4 特殊字符引用

在 HTML 中不能使用小于號(hào) “<” 和大于號(hào) “>”特殊字符,瀏覽器會(huì)將它們作為標(biāo)簽解析,若要正確顯示,在 HTML 源代碼中使用字符實(shí)體

<!-- 推薦  -->
<a href="#">more&gt;&gt;</a>
<!-- 不推薦  -->
<a href="#">more>></a>
2.2.5 附標(biāo)準(zhǔn)模板
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>HTML5標(biāo)準(zhǔn)模版</title>
</head>
<body>
    
</body>
</html>

2.3 Css

2.3.1 命名規(guī)范

所有的命名用小寫的英文單詞
不使用簡單的方位詞直接命名,如"left","bottom"
不縮寫單詞,除非一看就明白的單詞

公共命名參考如下:

參考命名 模塊
wrapper 頁面外圍控制整體布局寬度
container 容器,用于最外層
layout 布局
header 頁頭部分
footer 頁腳部分
nav 主導(dǎo)航
sub_nav 二級(jí)導(dǎo)航
menu 菜單
sub_menu 子菜單
side_bar 側(cè)欄
sidebar_l 左邊欄
message 提示信息
tips 小技巧
vote 投票
friendlink 友情鏈接
title 標(biāo)題
summary 摘要
search_input 搜索輸入框
search 搜索
list 列表
home_page 首頁
sub_page 二級(jí)頁面子頁面
download 下載
2.3.2 推薦展開格式
// 推薦
.sftc{
   display: block;
   width: 50px;
}
// 不推薦
.sftc{ display: block;width: 50px;}
2.3.3 樣式選擇器,屬性名,屬性值關(guān)鍵字全部使用小寫字母書寫
/* 推薦 */
.sftc{
    display:block;
}
    
/* 不推薦 */
.SFTC{
    DISPLAY:BLOCK;
}

2.3.4 分號(hào)

每個(gè)屬性聲明末尾都要加分號(hào);
為單個(gè)css選擇器或新申明開啟新行

// 推薦
.sftc, 
.sftc_logo, 
.sftc_hd {
    color: #ff0;
}
.nav{
    color: #fff;
}
// 不推薦
.sftc,sftc_logo,.sftc_hd {
    color: #ff0;
}.nav{
    color: #fff;
}
2.3.5 顏色值 rgb() rgba() hsl() hsla() rect() 中不需有空格,且取值不要帶有不必要的 0
// 推薦
.sftc {
   color: rgba(255,255,255,.5);
}
// 不推薦
.sftc {
   color: rgba( 255, 255, 255, 0.5 );
}

2.3.6 屬性值十六進(jìn)制數(shù)值能用簡寫的盡量用簡寫
// 推薦
.sftc {
    color: #fff;
}
// 不推薦
.sftc {
    color: #ffffff;
}
2.3.7 不要為 0 指明單位
// 推薦
.sftc {
   margin: 0 10px;
}

// 不推薦
.sftc {
   margin: 0px 10px;
}

2.4 代碼格式

2.4.1 eslint

使用如下幾個(gè)規(guī)則集合,校驗(yàn) typescript 和 react。

  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'prettier',
    // 'plugin:prettier/recommended',
  ],

2.4.2 prettier

需要安裝 eslint-config-prettier 和 eslint-plugin-prettier
代碼格式化工具,統(tǒng)一代碼風(fēng)格

module.exports = {
  singleQuote: true,
  semi: true,
  tabWidth: 2,
  proseWrap: 'preserve',
  endOfLine: 'lf',
  printWidth: 100,
};

項(xiàng)目文件改動(dòng)

  1. 增加依賴項(xiàng) eslint-config-prettier@8.3.0、eslint-plugin-prettier@4.0.0 和 eslint-webpack-plugin@^2.6.0
  2. 根目錄下增加文件 .eslintignore、.eslintrc.js、.prettierignore、.prettierrc.js、.gitattributes
  3. 刪除 package.json 里的 eslintConfig 和 prettier
  4. lint-stage 增加代碼風(fēng)格檢查
  5. 增加項(xiàng)目的vs code settings 里 eslint 自動(dòng)修復(fù)并關(guān)閉保存時(shí)格式化(與prettier 沖突)
    具體的包的詳細(xì)內(nèi)容請查看EsLint 詳細(xì)。無特殊情況請不要關(guān)閉或修改項(xiàng)目中的rules。

2.5 注釋規(guī)范

2.5.1 單行及多行注釋

單行注釋
句首加空格
句尾不加標(biāo)點(diǎn)符號(hào)

  // 我是單行注釋
  const sum = 0;

多行注釋
多行注釋使用 /** ... */,而不是多行的 //

// bad
// make() returns a new element
// based on the passed in tag name
function make(tag) {
  // ...

  return element;
}

// good
/**
 * make() returns a new element
 * based on the passed-in tag name
 */
function make(tag) {
  // ...

  return element;
}
2.5.2 使用特殊注釋標(biāo)記

發(fā)現(xiàn)某個(gè)可能的 bug,但因?yàn)橐恍┰蜻€沒法修復(fù);或者某個(gè)地方還有一些待完成的功能,這時(shí)我們需要使用相應(yīng)的特殊標(biāo)記注釋來告知未來的自己或合作者。常用的特殊標(biāo)記有兩種:
FIXME: 說明問題是什么
TODO: 說明還要做什么或者問題的解決方案


class Calculator extends Abacus {
  constructor() {
    super();
 
    // FIXME: shouldn’t use a global here
    total = 0;
 
    // TODO: total should be configurable by an options param
    this.total = 0;
  }
}


2.5.3 函數(shù)、類、文件、事件等使用 jsdoc 規(guī)范

/** 開始,注此處兩個(gè)星
@description 簡要描述
@param {類型} 參數(shù) 單獨(dú)類型的參數(shù)
@param {[類型|類型|類型]} 參數(shù) 多種類型的參數(shù)
@param {類型} [可選參數(shù)] 參數(shù) 可選參數(shù)用[]包起來
@return {類型} 說明
@author 作者 創(chuàng)建時(shí)間 修改時(shí)間(短日期)改別人代碼要留名
@example 舉例(如果需要)
*/

/**
* @description 減法運(yùn)算
* @param {Num} num1 減數(shù)
* @param {Num} num2 被減數(shù)
* @return {Num} result 結(jié)果
*/
function minus(num1,num2){
  return num1 – num2;
}

2.6 React

2.6.1 命名屬性規(guī)范(組件/屬性)

擴(kuò)展名: 用 .tsx 作為組件擴(kuò)展名。
文件名: 用大駝峰作為文件名,如:ReservationCard.tsx。
參數(shù)命名: React 組件用大駝峰,組件的實(shí)例用小駝峰。

// bad
import reservationCard from './ReservationCard';

// good
import ReservationCard from './ReservationCard';

// bad
const ReservationItem = <ReservationCard />;

// good
const reservationItem = <ReservationCard />;

組件命名: 文件名作為組件名。例如:ReservationCard.tsx 應(yīng)該用 ReservationCard 作為參數(shù)名。 然而,對于一個(gè)文件夾里的跟組件,應(yīng)該用 index.tsx 作為文件名,同時(shí)用文件夾名作為組件名

// bad
import Footer from './Footer/Footer';

// bad
import Footer from './Footer/index';

// good
import Footer from './Footer';

Props 命名: 避免用 DOM 組件的屬性名表達(dá)不同的意義

// bad
<MyComponent style="fancy" />

// bad
<MyComponent className="fancy" />

// good
<MyComponent variant="fancy" />
2.6.2 hook規(guī)則

Hooks 只能應(yīng)用于函數(shù)式組件中
只在 React 函數(shù)最頂層使用 Hooks
不要在循環(huán),條件或嵌套函數(shù)中調(diào)用 Hook, 確保總是在你的 React 函數(shù)的最頂層調(diào)用他們

// bad
function a () {
  const [count, setCount] = useState(0)
  useEffect(function persistForm() {
    localStorage.setItem('formData', accountName)
  })
  const x = function () {}
  const [timer, setTimer] = useState(0)

  // main logic
}

// bad
function a () {
  const [count, setCount] = useState(0)
  useEffect(function persistForm() {
    localStorage.setItem('formData', accountName)
  })
  const [timer, setTimer] = useState(0)
  const x = function () {}
  // main logic
}
2.6.3 狀態(tài)管理規(guī)范

現(xiàn)有 sds 項(xiàng)目中有三種狀態(tài)管理工具,分別是:reudx-saga、redux-toolkit、dva,dva暫時(shí)只在 newModule 模塊中使用。每一個(gè)頁面都有其頁面的 ”store“,頁面的狀態(tài)單獨(dú)管理,不與其他頁面耦合。
newModule 以外的模塊中有reudx-saga、redux-toolkit,新頁面使用redux-toolkit,采用動(dòng)態(tài)注入方式,在每個(gè)頁面的index.tsx中使用
slice

import { createSlice, PayloadAction } from '@reduxjs/toolkit';
import { createServiceAsyncThunkCreator } from 'utils/asyncRedux';

const createSimpleAsyncThunk = createServiceAsyncThunkCreator(NAMESPACE, services);
export const getDataList = createSimpleAsyncThunk('getDataList');

export const initialState: IStore = {
  isEditing: false,
  selectCourierInfo: {},
  filterDataObjParent: [],
  filterDataObj: {},
};

const slice = createSlice({
  name: NAMESPACE,
  initialState,
  reducers: {
    updateTableData(state, action: PayloadAction<any>) {
      state.tableData = action.payload;
    },
    updatePagination(state, action: PayloadAction<any>) {
      state.pagination = action.payload;
    }
  },
  extraReducers: {
    [getDataList.pending.type]: (state) => {
      state.tableLoading = true;
    },
    [postEditEntity.fulfilled.type]: (state) => {
      ....
    },
    [getDataList.rejected.type]: (state) => {
      state.tableLoading = false;
    },
  },
});

export const { actions, reducer } = slice;

injectReducer index 中使用一次即可。

const withReducer = injectReducer({ key: NAMESPACE, reducer });
withReducer(Component);

ConnectedProps react-redux 提供一個(gè)類型,能自動(dòng)推導(dǎo)出,connected props 類型, 無需手寫類型。

import { connect, ConnectedProps } from 'react-redux';

// 使用 ConnectedProps 自動(dòng)推導(dǎo) connected props 類型
type PropsFromRedux = ConnectedProps<typeof connector>;

const Component: React.FC<PropsFromRedux> = (props) => {
  return ...
}

// connector 使用使用多少、引入多少
const connector = connect(
  createStructuredSelector({
    reminderMoal: selectors.reminderMoal,
  }),
   {
    initTable: actions.initTable,
    updateFilterData: actions.updateFilterData,
    updateBatchImportModal: actions.updateBatchImportModal
  }
);
  
export default connector(Component);

newModule 這個(gè)模塊使用 dva

  1. 定義類型 State
  2. 定義類型 Model
  3. 定義 model
  4. 從 store 里導(dǎo)出 useSelector 和 useDispatch**
  5. 獲取類型良好的開發(fā)體驗(yàn)
// 詳細(xì)參見項(xiàng)目中的README
interface State {
  name: string;
}
/**
 * 定義Model
 * Reducer<當(dāng)前State, reducer名字和對應(yīng)的參數(shù)類型>
 * Effect<可選參數(shù)類型>
 * EffectWithType 使用數(shù)組形式定義effects
 */
interface Model {
  namespace: 'demo';
  state: State;
  reducers: Reducers<
    State,
    {
      // 參數(shù)類型 model中recuder中的payload類型,以及dispatch中payload校驗(yàn)使用
      modString: string;
    }
  >;
  effects: {
    // 參數(shù)類型 model中effect中的payload類型,以及dispatch中payload校驗(yàn)使用
    modPeople: Effect<{ name: string }>;
  };
}

const model: Model = {
  ...
  // 智能提示 Reducer 里的 payload
  // 提示和校驗(yàn) call 里的請求參數(shù)
  // 提示和校驗(yàn) put 的參數(shù)
  namespace: 'demo',
  state: initialState,
  effects: {
    *getTableDate({ payload }, { put, call }) {
      const result = yield call(getTableList, payload);
        console.log(result);
    },
  reducers: {
    update(state, { payload }) {
      return {
        ...state,
        obj1: payload,
      };
  },
}
// 從 store 里導(dǎo)出 useSelector 和 useDispatch
import { useSelector, useDispatch } from 'src/store';
// 校驗(yàn) dispatch 的 type 和 payload 的類型 是否準(zhǔn)確
const dispatch = useDispatch();
dispatch({
  type: 'demo/modPeople',
  payload: {
    name: ''
  }
})

export default model;
// 從 store 里導(dǎo)出 useSelector 和 useDispatch
import { useSelector, useDispatch } from 'src/store';
const Transportation: React.FC = () => {
  // 自動(dòng)推導(dǎo)toolConfigState 類型
  const toolConfigState = useSelector((s) => s.toolConfigStandard);
  
  const dispatch = useDispatch();
  
  dispatch({
    // 校驗(yàn)dispatch type是否正確
    type: 'toolConfigStandard/updateStateData',
    // 校驗(yàn)payload參數(shù)類型是否正確
    payload: {
        type: 'addAndEditModal',
        value: { type: 'edit', show: true, data: row },
    },
  });
}
2.6.4 其他注意事項(xiàng)
2.6.4.1 UI兼容性

我們還有較多網(wǎng)點(diǎn)使用的49版本的chrome,因此對于大版本迭代,提測后,都需要自查 chrome 49 版本的兼容性。

2.6.4.2 空值兼容

對于后端返回的需要前端有使用特定數(shù)據(jù)類型方法的值都需要做類型校驗(yàn),如對數(shù)組類型的map方法等。對于嵌套對象的key值讀取操作也需要做非空判斷。

2.6.4.3 防連擊處理

經(jīng)常因?yàn)榫W(wǎng)絡(luò)等問題,用戶多次點(diǎn)擊,導(dǎo)致產(chǎn)生不必要的數(shù)據(jù),影響后續(xù)操作。
防連擊具體場景:
①數(shù)據(jù)提交(用戶填寫數(shù)據(jù)后,驗(yàn)證完畢后,將數(shù)據(jù)提交給后端)
②登錄驗(yàn)證(用戶填寫完信息,驗(yàn)證完用戶身份后,登錄操作)
③單頁面的多個(gè)數(shù)據(jù)提交按鈕(某個(gè)頁面上有多個(gè)表單提交的需求,這時(shí)候設(shè)置點(diǎn)擊的開關(guān)需要區(qū)分)
防連擊的幾種處理方式:
①固定時(shí)間,比如固定2秒的時(shí)間,兩秒之后方可進(jìn)行下一次點(diǎn)擊【固定時(shí)間不是很靈活、看需求】
②等待返回結(jié)果之后方可進(jìn)行第二次點(diǎn)擊【若是沒有返回結(jié)果的話,用戶就無法進(jìn)行點(diǎn)擊了】
③等待返回結(jié)果,設(shè)置開關(guān)可進(jìn)行第二次點(diǎn)擊,與此同時(shí)設(shè)置定時(shí)器,超過5秒或一個(gè)固定時(shí)間將開關(guān)放開【防止沒有返回結(jié)果的情況】

3 協(xié)作規(guī)范

3.1 協(xié)作流程規(guī)范

前后端團(tuán)隊(duì)經(jīng)過長期的合作,一般可以總結(jié)出一條對于雙方開發(fā)效率最優(yōu)的協(xié)作流程. 將這個(gè)落實(shí)為規(guī)范,后面的團(tuán)隊(duì)成員都遵循這個(gè)步調(diào)進(jìn)行協(xié)作。
一個(gè)典型的前后端協(xié)作流程如下:


image.png
  1. 需求分析。參與者一般有前后端、測試、以及產(chǎn)品. 由產(chǎn)品主持,對需求進(jìn)行宣貫,接受開發(fā)和測試的反饋,確保大家對需求有一致的認(rèn)知。
  2. 前后端開發(fā)討論。討論應(yīng)用的一些開發(fā)設(shè)計(jì),溝通技術(shù)點(diǎn)、難點(diǎn)、以及分工問題。
  3. 設(shè)計(jì)接口文檔。可以由前后端一起設(shè)計(jì);或者由后端設(shè)計(jì)、前端確認(rèn)是否符合要求。
  4. 并行開發(fā)。前后端并行開發(fā),在這個(gè)階段,前端可以先實(shí)現(xiàn)靜態(tài)頁面; 或者根據(jù)接口文檔對接口進(jìn)行Mock, 來模擬對接后端接口。
  5. 在聯(lián)調(diào)之前,要求后端做好接口測試。
  6. 真實(shí)環(huán)境聯(lián)調(diào)。前端將接口請求代理到后端服務(wù),進(jìn)行真實(shí)環(huán)境聯(lián)調(diào)。

3.2 接口規(guī)范

明確數(shù)據(jù)類型、明確空值的意義、響應(yīng)避免冗余的嵌套

3.3 接口文檔規(guī)范

后端通過接口文檔向前端暴露接口相關(guān)的信息。通常需要包含這些信息:

  1. 版本號(hào)
  2. 文檔描述
  3. 服務(wù)的入口. 例如基本路徑
  4. 測試服務(wù)器. 可選
  5. 簡單使用示例
  6. 安全和認(rèn)證
  7. 具體接口定義
    7.1 方法名稱或者URL
    7.2 方法描述
    7.3 請求參數(shù)及其描述,必須說明類型(數(shù)據(jù)類型、是否可選等)
    7.4 響應(yīng)參數(shù)及其描述, 必須說明類型(數(shù)據(jù)類型、是否可選等)
    7.5 可能的異常情況、錯(cuò)誤代碼、以及描述
    7.6 請求示例,可選
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容