我是如何讓公司後臺管理系統面目一新的(下)-封裝組件

寫在前面

上篇在這裏前端

立刻到了金三銀四的時間,不少公司開啓了今年第一輪招聘的熱潮,雖然說今年是互聯網的寒冬,可是隻要對技術始終抱有熱情以及有過硬的實力,即便是寒冬也不會阻撓你前進的步伐。在面試的時候,每每在二面,三面的時面試官會結合你的簡歷問一些關於你簡歷上項目的問題,而如下這個問題在不少時候都會被問到vue

在這個項目中你有遇到什麼技術難點,你是怎麼解決的?node

其實這個問題旨在瞭解你在遇到問題的時候的解決方法,畢竟如今前端技術領域廣,各類框架和組件庫層出不窮,而業務需求上有時紛繁複雜,觀察一個程序員在面對未知問題時是如何處理的,這個過程相對於只出一些面試題來考面試者更能瞭解面試者實際解決問題的能力git

而不少人會說個人項目不大,並無什麼難點,或者說並不算難點,只能說是一些坑,只要google一下就能解決,實在不行請教我同事,這些問題並無困擾我好久。其實我也遇到過相同的狀況,和麪試官說如何經過搜索引擎解決這些坑的吧不太好,讓面試官認爲你只是一個API Caller,可是又沒有什麼值得一談的項目難點程序員

個人建議是,若是沒有什麼能夠深聊的技術難點,不妨在平常開發過程當中,試着封裝幾個經常使用的組件,同時嘗試分析項目的性能瓶頸,尋找一些優化的方案,一樣也能讓面試官對你有一個總體的瞭解github

上篇分享了我在項目中是如何根據功能劃分模塊以及性能優化的技巧,這章我會記錄設計和封裝組件的過程面試

技術棧是Vue + Element的單頁面應用後端

封裝組件

有人會說,github上那麼多好的開源組件,好的開源庫放着不用,爲啥本身還要折騰呢?api

其實我認爲本身動手封裝一個組件仍是頗有意義的,由於若是是從零開始編寫的組件,你可以更好的掌握本身組件的全部功能,而且還能根據公司的業務需求定製一些特殊的功能,除此以外,理解一個組件內部的實現機制也有助於提高我的的編碼能力,而不是別人問起來你只知道我用過某個組件,很好用,可是不知道是怎麼作到的。因此我仍是比較推薦去嘗試編寫幾個經常使用的組件數組

由於是後臺管理系統,核心的組件確定是表單組件和表格組件,公共組件是基於element組件的二次封裝,組件的設計遵循如下的思路

  • 高內聚低耦合,儘量少的暴露組件的api,將功能儘可能封裝在組件內部
  • 組件內部根據業務需求設置了一些組件默認的配置項,另外再經過不一樣頁面傳入不一樣配置項提升組件的通用性

設計組件的目的就是讓組件進一步解耦,將配置項和模板標籤分離,一方面是減小在業務邏輯組件中的代碼量,另外一方面就是單獨抽離的配置項使得可以經過後臺動態傳遞給前端,或者本身建一個配置項的js/ts文件(若是有規範的開發者文檔還可使用nodejs編寫一個讀取開發者文檔一鍵寫入配置項的腳本,進一步提高開發效率)

表格組件

表格組件設計大體分爲如下幾個部分

  • 儘可能貼近element組件庫的api
  • 傳入一個表頭的配置項數組,經過這個配置項動態生成el-table-columns標籤
  • 交互複雜的表頭列的解決方式

儘可能貼近element組件庫的api

組件中使用了$attrs,$listeners實現屬性和監聽事件的跨級傳遞,使得在頁面中給自定義組件中的傳入的屬性可以經過自定義組件內部的轉發直接成爲el-table標籤的屬性,達到跨級的屬性傳遞,而$listeners和$attrs相似,可以監聽el-table組件中觸發的事件,將事件轉發 到頁面中的自定義組件上

自定義組件:

這樣作的目的就是能讓你的自定義組件和el-table組件有相同的用法,傳入的屬性,監聽的事件也是相同的

在頁面中使用自定義組件,能夠看到z-table和el-table的用法幾乎是相同的,只須要額外傳入一個columns的屬性:

表頭的配置項設計

繼續給這個表格組件添加表頭標籤,這裏我把一些沒必要要的判斷都去除了,只留下了核心的邏輯,實際在組件內部只須要循環這個配置項動態生成el-table-column標籤就能夠了

自定義組件:

配置項文件:

這裏的核心是在於這個v-bind,當v-bind後面等號裏放入的是一個對象時,它會遍歷這個對象的全部屬性,將屬性和值一一作綁定

什麼意思呢?這裏結合配置項文件來講明,若是傳入上述的配置項,組件的內部實際是這樣子的

拋開key不談,在配置項的每一個元素中暴露一個attrs屬性,裏面保存了全部el-table-column標籤能夠接受的屬性。例子中label,prop,width這3個屬性是在配置項每一個元素的attrs屬性中的,經過v-bind="column.attrs"讓這3個屬性和它們的值分別在el-table-column標籤中作了綁定,從而達到了模板和配置項解耦的目的

交互複雜的表頭列的解決方式

對於一些須要特別處理的表頭列的數據,我在組件內部利用插槽和做用域插槽,經過插槽定義表頭列的插入位置,再經過做用域插槽將信息返回給父組件,在父組件中定義如何顯示,使得表格組件很是的靈活可以應對大部分業務需求

能夠看到具名插槽的名字也是經過配置項傳入的,而且做用域插槽將整個表單內部的數據經過scope傳給父組件,在複雜的業務場景,沒法經過配置項解決問題的時候,經過插槽和做用域插槽讓父組件去決定如何去處理數據

配置項中添加插槽屬性:

頁面組件:

在頁面組件中,能夠和element提供的做用域插槽的使用方式類似,經過scope能夠訪問到組件內部的全部數據而且交給頁面組件去作複雜的邏輯處理

其餘功能

針對公司的需求,我對組件作了進一步的改造

  • 使用render函數使得表頭顯示可以更加靈活
  • 配置項暴露一個函數可以讓當前列的數據執行這個函數達到預處理的效果
  • 配置項中設置一個二維數組,可以讓數據字段組合,達到數據顯示在不一樣的行數的效果
  • 添加了操做圖標
  • 添加了數據(code碼)轉對應中文語義的功能

源代碼

表格組件

表單組件

表單組件相對於表格組件在實現方面要困難一點,由於表單的控件很是多,每一個配置項又須要很是靈活,這裏我借鑑了以前在知乎看到的一篇博客,文章中雖然沒有把代碼列出來,可是羅列了總體的實現方案,隨後我根據文章中的思路設計了這個表單組件

設計大體分爲如下幾個部分

  • 表單配置項設計
  • 表單驗證
  • 表單請求
  • 表單控件之間的聯動
  • 調用後端接口生成表單控件的選項

表單配置項設計

根據上面的表格組件的封裝思路,仍是利用$attrs作根元素屬性的傳遞,用v-bind在配置項中設置組件內部的屬性

表單組件:

配置項文件:

和表格組件不一樣的是,由於表單組件分爲el-form-item標籤和表單控件2部分,這2個部分都須要在配置項中對應配置屬性,在配置項中使用itemAttrs控制el-form-item標籤的屬性,使用attrs控制表單控件的屬性

這裏還用到了component標籤,經過配置項的tag標籤動態生成el-input的表單控件,可是能夠看到這裏我並無直接將tag的值設爲el-input,那input是如何變成el-input的呢?

這裏我又定義了每一個組件通用的配置項,使得不須要每次都在組件的attrs中聲明一些重複的屬性,好比placeholder,clearable等

通用配置項文件:

最重要的是我創建了組件配置項和通用配置項之間的關聯,經過組件配置項中的tag屬性找到通用配置項對應的對象,結合上面的例子若是tag的值是input,那就會從通用配置項中找到input屬性對應的對象,而且將真實的tag值指向通用配置項的component,這裏就是el-input

而這種關聯又是怎麼創建起來的呢,其實仍是用了Object.assgin作了對象之間的合併

核心邏輯以下(參數formItem指的是組件配置項formItems中的每一個元素):

這裏定義了一個computeFormItem的函數,經過傳入配置項數組的每一個元素,根據元素的tag值找到通用配置項(basic對象)中相應的值,隨後用了Object.assgin作了合併,關於這個computeFormItem函數我稍後在後面的表單控件之間的聯動中會詳細去講

通用和組件配置項都有了,接下來要實現的是表單組件須要上傳給後端的數據對象

這裏個人思路是經過配置項中聲明的字段名(key)動態生成數據對象,這樣能夠減小傳入的配置項的數量,在組件內部聲明Model變量保存數據對象

可是這裏有2點須要注意

  • 由於組件內部聲明的Model是一個空對象,Vue的響應式系統是監聽不到對象建立了新的屬性,須要使用$set來設置,使得可以強制更新視圖
  • 這裏須要經過formItems對Model數據對象賦值,若是放在mounted鉤子中執行的話拿到的是一個空數組,因此我這裏使用watch來監聽formItems,而且使用immediate當即執行(用computed聲明一個新數組理論上也能夠)

表單驗證

表單驗證方面儘可能貼合element組件的傳入方式,保持全部在el-form-item標籤中寫的屬性都寫在itemAttrs中,全部在表單控件中寫的屬性都寫在attrs中,因此能夠在itemAttrs中編寫表單驗證方面的邏輯

表單請求

表單請求方面,由於在重構時新建了api文件夾,存放的是一個個後端接口的api函數,作到一個頁面對應一個api文件夾中的一個接口文件

每一個接口文件中能夠導出多個接口的函數

在表單組件中只須要聲明一個api的props讓頁面組件傳入就能夠了

隨後給提交按鈕綁定click事件,進行表單驗證最後執行接口函數,傳入Model這個數據對象便可

在接口函數調用成功返回響應數據後,我這裏經過觸發after-submit的事件讓頁面組件監聽這個事件,而且把響應數據傳給頁面組件,這樣頁面組件就能拿到響應的數據而且作一些處理了

頁面組件監聽after-submit事件:

表單控件之間的聯動

這一部分我認爲也是最難實現的,在平常的業務需求中可能須要某個控件控制另一個控件顯示與否

核心的思路就是在配置項中定義一個getAttrs的函數,這個函數根據當前Model,也就是數據對象中的某個值動態的生成一個attrs對象,最後將這個attrs對象經過合併到當前配置項的attrs中,另外還定義了一個ifRender函數,能夠控制表單控件是否被渲染,最後咱們的配置項可能長這樣

接下來表單組件內部要實現如何執行這2個函數,依舊是以前的computeFormItem這個函數,它用來計算出當前表單組件的配置項

和上面的computeFormItem函數不一樣的是,我這裏傳入了第二個參數Model,使得當前的表單組件配置項可以根據Model動態的變化,在內部執行getAttrs函數傳入這個Model,返回的對象經過Object,assgin合併到當前的配置項中,而對於另外一個ifRender函數,也傳入Model,返回一個Boolean值,最後用這個Boolean值在模版中經過v-if控制是否渲染表單控件

這裏要分析一下整個表單最核心的部分:computeFormItem函數,它的做用是根據當前Model中的數據變化,動態的生成一個新的配置項,由於咱們的表單控件是根據配置項映射而成的,須要改變表單控件只能去修改配置項

根據上面那個圖能夠發現,咱們並無直接使用頁面組件傳來的formItems配置項,而是根據_formItems循環渲染的標籤,而_formItems是基於formItems而且通過computeFormItem生成的配置項,只要Model中的數據改變,這個配置項就須要從新計算生成新的值,因此我選擇把_formItems放在計算屬性中

這樣,只要依賴項(這裏是Model和formItems)變了,就會觸發函數從新計算出新的_formItems

下拉框/單選框/複選框

在表單組件中,我使用component標籤動態生成表單控件,可是對於一些有子節點的表單控件經過component實現就有些困難,這裏我將含有子節點的組件(下拉框/單選框/複選框)又進行了一層封裝,消除了子節點,讓全部屬性都在component這一層配置

自定義select組件

這樣以來只要在配置項中聲明一個options屬性,經過component標籤將組件轉爲自定義的select組件,讓options屬性就會變爲select組件的屬性,這樣在自定義的select組件內部能夠經過$attrs.options獲取到它(這裏注意value,label必須都要顯式的聲明不然會報錯,由於element組件內部會對傳入的屬性驗證)

組件配置項文件:

這裏再次利用通用配置項文件,將組件配置項中聲明的select組件的配置項映射到自定義的select組件中

調用後端接口生成表單控件的選項

在真實的業務需求中,部分下拉框,單選框的選項是經過拉取後端的接口生成的。放在表單組件中的話仍是須要修改配置項,在頁面組件中修改formItem。找到下拉框/單選框的key,將接口的數據賦值給options屬性

總結

能夠看到表單組件仍是比較複雜的,其實這個表單組件相對於表格組件來講仍是有必定的侷限性,後續可能會給它設計插槽的功能。另外真實的業務需求確定是更加複雜多變的,無論怎麼說,一些交互邏輯不是特別複雜的表單這個組件仍是能hold住的,本人能力有限,這裏也只是給一個思路,但願後續可以愈發完善

源代碼

表單組件

一鍵生成配置項

介紹一款我本身寫的工具庫,能夠和表格組件完美配合,讀取開發者文檔,一鍵生成組件的配置項,免除多字段輸入的錯誤和重複勞動,有幫助的話但願各位賞個 star ~

excel-code-generator

參考資料

加快Vue項目的開發速度

不再想寫表單了

相關文章
相關標籤/搜索