[toc]
1 工作流規(guī)范
1.1 git規(guī)范
1.1.1 分支管理規(guī)范
git版本管理中主要有以下幾種類型的分支:master、develop、feature、release、hotfix。
- 主分支
master
代碼庫應(yīng)該有且僅有一個(gè)。所有提供給用戶使用的正式版本,都在這個(gè)主分支上發(fā)布; - 開發(fā)分支
develop
我們把開發(fā)用的分支,叫做develop分支。開發(fā)分支(develop)應(yīng)該總能夠獲得最新開發(fā)進(jìn)展的代碼。 - 臨時(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ā)布
- 如第一步打包失敗,查看打包的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 - 如第二步預(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ì)從線上撤回。 -
如第四步發(fā)布失敗,查看發(fā)布的log,確認(rèn)原因后,在原來的基礎(chǔ)上,重新發(fā)布。
如發(fā)布成功,即將上線分支合并到master。無需手動(dòng)合并。
其中發(fā)布規(guī)則如下圖所示:
image.png
uat上線流程如下:
- 提工單,在Jenkins綁定Job,綁定過后,打包頁面的build_type的列表里多一個(gè)uat的環(huán)境。
- 在上線系統(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。
- 新建一個(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>></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)
- 增加依賴項(xiàng) eslint-config-prettier@8.3.0、eslint-plugin-prettier@4.0.0 和 eslint-webpack-plugin@^2.6.0
- 根目錄下增加文件 .eslintignore、.eslintrc.js、.prettierignore、.prettierrc.js、.gitattributes
- 刪除 package.json 里的 eslintConfig 和 prettier
- lint-stage 增加代碼風(fēng)格檢查
- 增加項(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
- 定義類型 State
- 定義類型 Model
- 定義 model
- 從 store 里導(dǎo)出 useSelector 和 useDispatch**
- 獲取類型良好的開發(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é)作流程如下:

- 需求分析。參與者一般有前后端、測試、以及產(chǎn)品. 由產(chǎn)品主持,對需求進(jìn)行宣貫,接受開發(fā)和測試的反饋,確保大家對需求有一致的認(rèn)知。
- 前后端開發(fā)討論。討論應(yīng)用的一些開發(fā)設(shè)計(jì),溝通技術(shù)點(diǎn)、難點(diǎn)、以及分工問題。
- 設(shè)計(jì)接口文檔。可以由前后端一起設(shè)計(jì);或者由后端設(shè)計(jì)、前端確認(rèn)是否符合要求。
- 并行開發(fā)。前后端并行開發(fā),在這個(gè)階段,前端可以先實(shí)現(xiàn)靜態(tài)頁面; 或者根據(jù)接口文檔對接口進(jìn)行Mock, 來模擬對接后端接口。
- 在聯(lián)調(diào)之前,要求后端做好接口測試。
- 真實(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)的信息。通常需要包含這些信息:
- 版本號(hào)
- 文檔描述
- 服務(wù)的入口. 例如基本路徑
- 測試服務(wù)器. 可選
- 簡單使用示例
- 安全和認(rèn)證
- 具體接口定義
7.1 方法名稱或者URL
7.2 方法描述
7.3 請求參數(shù)及其描述,必須說明類型(數(shù)據(jù)類型、是否可選等)
7.4 響應(yīng)參數(shù)及其描述, 必須說明類型(數(shù)據(jù)類型、是否可選等)
7.5 可能的異常情況、錯(cuò)誤代碼、以及描述
7.6 請求示例,可選


