做了這麼多年前端,為什麼你還是不會寫業務程式碼?
阿新 • • 發佈:2020-12-04
我在平時工作中也會負責一些程式碼審查的工作,做的多了,就發現了一個問題:大部分程式設計師習慣把所有的邏輯都寫在vue檔案裡,所以這就導致一個問題,也就是你專案中的`.vue`檔案的程式碼會巨多,相反,你的`js/ts`檔案中的程式碼會沒有那麼多。如果是一個小型專案當然還好,如果是一個大型的專案,這可能就是維護人員的噩夢了,因為後續的維護成本是巨大的。至於為什麼,相信你看完這篇部落格就能懂我的意思了。
今天有時間靜下心可以寫一篇部落格,總結了一下日常審過的程式碼,我們就用這些程式碼當作案例,分析一下我們以後的`coding`生涯該如何去避免這些問題。
首先我們想思考一個問題:**`.vue`檔案到底是用來幹嘛用的?**
我們可以看一下`vue官網`是如何介紹這款框架的:
![image](https://blog-1300740786.cos.ap-nanjing.myqcloud.com/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20201203111933.png)
這個檢視層也就`vm`,說白了就是我們寫的頁面。
那麼頁面中應該負責幹什麼呢?無非就是用`html`和`css`程式碼搭建頁面結構,然後頁面中可以能有一些元素的事件,比如說按鈕的點選事件,表單的查詢,表格的請求資料的動作等等。
所以綜上所述我們可以總結一句話: **`.vue`檔案中包含一些頁面結構以及頁面元素動作的發起。**
那麼,動作的發起者有了,動作的執行者是誰呢?
我們看一些我們平常寫的專案結構是啥樣的,拿一個ts專案為例:
![image](https://blog-1300740786.cos.ap-nanjing.myqcloud.com/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20201203113805.png)
這個是`src`下的目錄結構,應該是分的比較詳細的,各個資料夾有不同的作用,這也符合單一職責。
我們在回過頭來看一些誰能當作動作的執行者呢?`api`只負責呼叫介面,他拿到資料後就丟擲了,資料這時候已經流向別處了,`assets`只放靜態資源,這兩個顯然不能。`component`,`public_component`,`instance`,`mixin`和`views`全是用來搭建頁面的,`mixin`雖然是`ts`檔案,但是他的定義也是`可以分發Vue元件中的可複用功能`,這些顯然也是不行的。`interface`和`utils`這些是抽象出來的東西,顯然是不能放業務程式碼的。`store`現在已經不被大家看好了,因為`vuex`中的通訊實在是太繁瑣了,目前我們的專案只用來放一些字典資料用來快取。還剩下`routers`,`middleware`,`style`這三個顯然不是幹這個用的。最後就只剩下`domain`了。
`domain`(也有叫`service`的)作為業務層,我們給他最初的定義就是寫一些業務程式碼,按鈕的點選事件,頁面的滾動事件顯然不是業務程式碼,這些可以負責呼叫業務程式碼,也就是我們上面說的動作的發起者。這時候業務層的作用就來了,就是充當動作的執行者。設想一下,我點選一個按鈕去請求一個表格資料,那麼按鈕上肯定繫結一個`click`事件,點選完成之後就應該調介面了,後續的事情就可以交給業務層了,由業務層完成後續的邏輯,比如我拿資料需要呼叫`api層`先請求一下後臺資料,拿到資料看一下有沒有請求成功,資料是不是我們想要的格式,處理好時候就可以交給頁面層渲染了。
好,我看一下實際的程式碼表現是什麼樣的。
先說一個簡單需求,我們希望一個表格內展示一些使用者資料,看一下一般的程式設計師是怎麼做的:
> 資料結構:
```
// 表格資料
let tableData = [
{
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀區金沙江路 1518 弄",
phone: "13033443344",
love: [
'吃飯',
'睡覺',
'寫bug'
]
},
{
date: "2016-05-02",
name: "王小虎",
address: "上海市普陀區金沙江路 1518 弄",
phone: "13033443344",
love: [
'吃飯',
'睡覺',
'寫bug'
]
}
...
]
// 表頭資料
let headData = [
{
label: "日期",
prop: "date",
width: "180"
},
{
label: "姓名",
prop: "name",
width: "180"
}
....
]
```
> .vue檔案
```
{{scope.row.jobInfo.job}}
{{scope.row.love.join('-')}}
{{scope.row[item.prop]}}
```
> service業務層
```
import { getTableData, getHeadData } from "@/api/index"
export class TableList {
public async searchTableData () {
let data = await getTableData();
return data;
}
public async searchHeadData () {
let data = await getHeadData();
return data;
}
}
```
> 最終效果
![image](https://blog-1300740786.cos.ap-nanjing.myqcloud.com/%E5%BE%AE%E4%BF%A1%E6%88%AA%E5%9B%BE_20201204152710.png)
我們可以看出這裡的程式碼大部分寫在了`.vue`檔案中,裡邊包含了一些判斷和資料處理,而且業務層檔案基本沒發揮它的作用,只是簡單的呼叫了介面而已,我們知道一個類最基本的就是要構造他,才能體現它的多型,這裡只是一個頁面有表格業務操作,如果我們有很多個表格呢,是不是就會有很多個業務檔案?
如果我們按照我的說法,把業務程式碼不寫在頁面而是寫在service中,看看是什麼效果:
> .vue檔案
```
```
> service業務層
```
import { getTableData, getHeadData } from "@/api/index"
export class TableList {
// 表格資料
public tableList: any;
// 表頭資料
public headList: any;
constructor (tableList =[],headList=[]) {
this.tableList = tableList;
this.headList = headList;
}
public async searchTableData () {
let data: any = await getTableData();
this.tableList = data.map(el => {
Reflect.set(el, 'job', el.jobInfo.job);
Reflect.set(el, 'love', el.love.join('-'));
return el
})
}
public async searchHeadData () {
this.headList = await getHeadData();
}
}
```
我們可以看出,業務類中定義了表格資料和表頭,從後端獲取到資料後直接掛在了業務類中,頁面那些資料處理也在放在了業務類中,在頁面中只需要把這個業務類存在vue例項中,在這個頁面中只要是需要就可以拿到這個業務中的屬性和方法。不僅如此,以後不管有多少個表格,只要是業務類似,都可以用這個業務類。是不是很方便?而且頁面中的程式碼減少了很多。個人認為這種方式是比第一種要好很多的。
不僅如此,有沒有想過我們寫的form表單也是隻接寫成業務的?把每個表單中的欄位用類構造,這樣頁面中只接繫結類中的屬性。因為類是引用型別,所以頁面中表單有變化,業務類中是能響應的,這樣表單的查詢只接在類中取值就行了,而且表單構造相應變得簡單了很多。我們看一下這個例子:
> service中的表單業務
```
export class Form {
public job: string;
public love: string[];
public address: string;
constructor ( job='', love=[], address='' ) {
this.job = job;
this.love = love;
this.address = address
}
}
```
> .vue頁面
```
...
```
新增表單需要初始化資料,就是類構造的過程,點選編輯按鈕需要載入表格中的行資料,賦值到表單中,這時候需要拿到行資料再次構造一下業務類,是不是比賦值要方便很多,省去很多個等號?如果是個查詢的表單,那麼查詢的業務,重置的業務都可以在類中取完成。
我們再深入研究一下,這個頁面中用到了側滑元件,想想我們在一個專案中是不是有很多個側滑,彈窗等等,那麼每次用都要寫一堆的開啟關閉這些事件嗎?其實這些簡單的邏輯不是我們重點關注的,如果我把這些流程寫成一個業務呢?看看下邊的程式碼:
> .vue檔案
```
...
開啟
關閉
```
> service側滑業務
```
export class Drawer {
public visible: boolean;
constructor ( visible = false ) {
this.visible = visible;
}
open () {
this.visible = true;
}
close () {
this.visible = false;
}
}
```
這樣每個側滑元件我們都可以用這個業務了;甚至像彈窗這種類似的元件也能用這個業務。
其實看到這裡你應該就明白了,我們應該如何去寫業務程式碼了。
我們作為程式設計師,從剛入行開始寫的就是業務程式碼,做的多了,應該學會自己把自己寫的程式碼變得更加漂亮了。老滿足於當下,不如搞點事情,寫一些優雅的程式碼。
業務程式碼其實是最好寫的程式碼,只有業務程式碼寫的多了,我們才能明白如何將業務下沉為公共服務,公共服務再下沉為基礎服務,等到這時候,就不是寫業務程式碼這麼簡單了,他更考驗我們的抽象能力。
本部落格耗時三天,就是希望大家不要老寫一些麵條程式碼,麵條程式碼是容易理解,但是那對我們的能力和技術一點不會有提升,只有善於封裝,善於優化才能寫出更加漂亮的程式碼。
## 關注我的個人部落格: [地址](https://www.liuguisheng.vip)
## 我的開源專案: [地址](https://www.liuguisheng.vip/react-admin-plus/)
## 一天一句毒雞湯小程式
![image](https://img-blog.csdnimg.cn/20201124141753595.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2NvZGVMaXVndWlzaGVuZw==,size_16,color_FFFFF