之前寫了個小組件, 首先感謝大佬們提的意見, 今天我要總結一下關于開發過程中, 什么情況下我們要去封裝自己的組件, 當然這個我自己一步步感覺出來的, 大家可能也有自己的經驗, 如果大家有更好的方法, 也希望大家可以不吝賜教留言給我和不小心進來的同學
好了不多bb, 這次我是來解析封裝多行編輯組件的
多行編輯組件, 一般在管理系統的大表單中出現的幾率比較大, 而且業務越復雜的表單越有幾率出現他的身影, 部分人可能還沒聽過這個東西, 我先介紹一下吧, 這個東西也叫"動態增減表單項", 就是這個東西
再element-ui中是這樣的
網上對這個東西的介紹只能算一般多吧, jquery封裝的組件可能多一點, 框架的UI雖然也有封裝, 但是功能都偏少
好了現在又到了我們會1+1, 就要算微積分了的時候了, 當然我們也不能憑空去算, 至少看一下前人的經驗, 我看過稍微完整一點的就是Ant Design Pro管理系統模板的, 當然這個是react的, 但是無所謂是用的什么框架, 我們先看一下他的
功能挺多的了, 而且他是在表格中實現的, 看起來比較整齊, 當然用Layout布局也可以, 都沒什么問題, 我這次就站在巨人肩膀上用element-ui的表格布局實現以下他這個吧, 畢竟我們要做vue的多行編輯功能, 先總結他的已有功能吧, 然后我再添加點
總結:
a. 有個表頭, 或者叫列名, 當然我們在接下來的輸入框中我們還會繼續給他提醒
b. 要有一個操作列, 5種功能
i. 添加: 當一個新的一行出現的時候展示, 填完信息后點擊添加變為不可編輯狀態
ii. 刪除: 刪除當前行
iii. 編輯: 當已經點過添加, 變為不可編輯裝填展示, 點擊后變為可編輯狀態
vi. 保存: 編輯后進行保存數據
v. 取消: 取消當前編輯的內容, 類似于一個還原, 然后并變為不可編輯狀態
c. 要有一個添加一行的功能
d. 最主要的就是中心編輯展示部分, 一種是展示狀態, 不可編輯, 純文本, 一種是輸入框狀態, 可編輯
好, 有了整理我們就很清楚了, 具體什么用什么功能的組件, 但是這些并不能滿足我們的需求, 我們還要再添加一點功能
新增:
a. 表單驗證功能, 其實就是element-ui的那個多行編輯的驗證功能, 讓他稍微變得靈活一點
b. 增加日期框, 數字輸入框, select框, 查詢回顯框(就用我之前寫的那個), 不過這樣會讓這兩個組件綁定言重, 但是這個對于我的業務來說是很有必要的, 雖然嚴重但是對我構建項目來說卻更加便利
這里也引出一個點, ui庫已經給你封裝好了你就復制粘貼嵌套一下就好了, 為什么還要多此一舉?
我大體來回答一下, 我們的開發與封裝就是要基于業務和開發便利以及便于維護為目的, 而ui框架的開發更多的是為了去適應更多的人使用, 更加便利易懂
打個比喻: ui庫不是做出一個個"人", 而是要做出一個個骨架, 一種種外貌, 讓我們自己去捏人捏臉, 讓我們自己拼接
而融入到業務中, 我們在這樣是不能夠達到最大方便的, 我們在業務中就是要吧這些零散的骨架適當組裝, 組裝出可能用到的各種腿, 各種胳膊, 身子, 美麗且滿滿頭發的腦袋瓜, 我們再去拿這些拼人就好了, 原來我們要ui的零散的好多拼成一個頁面, 現在我們只要拿幾個稍大的功能組件一組就夠了, 可能很多人在自己的開發中已經應用了這種方法, 沒問題, 我覺得這么做有點棒棒的
開始操作起來, 不過我相信你已經明白該怎么做了, 下面還是按照上一篇文檔的節奏來寫, 我們現在已經總結完功能了, 接下來我們就是要設計基本的結構
1. 基本結構
<div>
<table>
<!-- 表頭 -->
<thead>
<td></td> *n
</thead>
<!-- 內容 -->
<tr>
<td> *n
<input>
</td>
<!-- 控制列 -->
<td>
<button>確認</button>
<button>取消</button>
<button>刪除</button>
<button>編輯</button>
</td>
</tr>
</table>
<button>新增一行</button>
</div>
*n的地方代表了接下來我們要用循環創建
把結構一屢, 沒多少東西, 接下來我們就要確定哪些東西是要外部控制的
2. 外部傳輸的方法
先插入一點原理, 這個多行編輯是怎么實現的
再vue中, 我們通過v-for循環創建一組對應的標簽, 所以如果我們對循環的那個變量不斷的push新的值自然就會被v-for渲染到頁面, 好了繼續整理
a. 首先傳入一個新增一行的方法, 上面介紹了, 我們只要給v-for遍歷的那個變量push就好了
b. 要傳入控制當前行狀態的方法, 這個添加就是要當我們完成單行編輯的時候, 先去驗證是否必填的已經填完了, 然后讓此行變成確定狀態, 不可再編輯, 也可反之變為可編輯狀態
c. 傳入一個刪除的方法, 刪除就是從那個遍歷的參數中把當前行的內容刪除就可以了, 我們可以通過給每一行多定義一個隱藏參數為時間戳, 讓每一行保持獨立
d. 傳入取消的方法, 我們當再修改途中, 想還原之前填寫的狀態用, 所以我們還要暫存一下當前點擊修改的那行初始值
簡單寫一下這個
methods:{
pushlist() {
//添加一行
},
editstatus(index){
//控制單行的開關狀態
},
delrow(index) {
//刪除本行
},
cancelrest(index, sw, row) {
//取消時恢復本行
},
}
整理了方法, 我們就要看看這些方法中, 以及應用中要用到哪些從外部傳入的參數呢
3. 外部傳入參數
a. 要傳入一個表頭的數組
b. 要傳入一個單行內要有幾列, 也就是一行有幾個輸入框的數組, 這個比較麻煩我們要慢慢整理
c. 要傳入整個多行編輯數據, 初始就是個空數組
4. 接下來把結構補全
<div id="inputList">
<!-- 因為要做rule驗證, 所以要有form -->
<el-form :model="listModel">
<!-- 表格, tableData為多行編輯的數據, 我們要用他的長度渲染表格有幾行所以要綁定data -->
<el-table :data="listModel.tableData" style="width: 100%" size="mini">
<!-- 在element-ui中的table是自動綁定列名稱的,所以就合成一個數組rowTable中 -->
<el-table-column v-for="(item,index) in rowTable" :key="index" :label="item.label" :width="item.width">
<!-- 要獲取單行數據進行處理, 所以要綁定scope -->
<template slot-scope="scope">
<!-- 當只展示時, 用span進行展示 -->
<span v-show="scope.row.status">{{ scope.row[item.prop] }}</span>
<!-- 編輯時, 用form + input等方式編輯 -->
<el-form-item v-show="!scope.row.status" :prop="'tableData.'+scope.$index+'.'+item.prop" :rules="item.rule"
:ref="'tableData.'+scope.$index+'.'+item.prop">
<el-input size="mini" v-model="listModel.tableData[scope.$index][item.prop]"
v-if="item.type == 'text' || !item.hasOwnProperty('type')" :disabled="item.disabled"></el-input>
</el-form-item>
</template>
</el-table-column>
<!-- 單獨一列, 操作列 -->
<el-table-column label="操作">
<template slot-scope="scope">
<el-button size="mini" @click="handleEdit(scope.$index, scope.row.status, scope.row)">
{{scope.row.status?'編輯':'確定'}}</el-button>
<el-button size="mini" type="danger" @click="handleDelete(scope.$index)">刪除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 新增一行操作 -->
<el-button size="mini" @click="addRowList" class="addBtn">新增一行</el-button>
</el-form>
</div>
5. 把需要循環創建的參數提取出來設計參數
a. rowTable, 看看循環他我們需要從中拿到那些數據來用, 把這些數據一總結放到個對象里, 這個就創建完了
{
//顯示的名稱
label: "郵箱",
//input寬度
width: "180",
//綁定prop
prop: "email",
//驗證規則
rule: [{ required: true, message: "年齡不能為空" }],
//input類型 "number", "date", "text", "search", "select", 暫時想了這么多, search就是上一篇的類型
type: "number",
//是否允許編輯, 有的內容是只由別的帶出來, 只能看或者修改別的框改變這個, 所以此框禁用
disabled: false
},
b. tableData這個是自動綁定的, 我們要思考除了表格內容我們還要什么參數
// form綁定的數據
listModel: {
//表格綁定的數據
tableData: [
{
//表格一行的數據
email: "email1@qq.com",
email1: "",
email2: "email2@qq.com",
email3: "email3@qq.com",
email4: "email4@qq.com",
email5: 123,
//開關, 決定是否是展示狀態還是編輯狀態, disabled禁用屬于編輯狀態
status: false,
//確定每一行唯一的key
key: new Date().getTime()
}
]
}
6. 由于這個功能相對復雜, 我們還需要內部定制一個參數用于臨時使用
a. 當我們點編輯的時候要暫存這個數據, 以備用戶點擊取消的時候恢復使用, 因為用戶可能一次點了好幾個編輯, 我們都要存儲, 又因為我們有一個key值可以當我們的索引, 我們只需要把用戶點擊編輯的數據push一個數組就夠了
cancelListData:[
{
//表格一行的數據
email: "email1@qq.com",
email1: "",
email2: "email2@qq.com",
email3: "email3@qq.com",
email4: "email4@qq.com",
email5: 123,
status: false,
//確定每一行唯一的key
key: new Date().getTime()
}
]
7. 好了基本需要的東西我們都準備完了, 接下來還要實現組件里的方法
methods:{
addRowListJudge(){
// 判斷是否有未操作完的行, 然后才允許新增一行, 也是為了提交表單時判斷更為簡便
},
handleEdit(){
// 調用傳入的修改狀態的方法
},
handleCancel(){
// 調用傳入的取消方法
},
handleDelete(){
// 調用傳入的刪除行的方法
},
}
8. 最后一步就是實現各個方法就可以了, 這里就不細寫了, 具體還是直接看代碼吧, 代碼放在:https://github.com/wqliusong/happy/tree/master/rowList, 有可以直接運行的單頁面下載就可以看, 也希望各位路過的朋友能給提點意見, 先謝過
總結: 最后來說一下自己遇到的一些家長里短的問題
a. 第一個就是淺拷貝深拷貝的問題, 有很多人說淺拷貝深拷貝有啥用, 平時也基本遇不到, 這里就給了一個例子, 代碼中有注釋, 具體會遇到什么問題, 我在這里說一下, 當我在從不可編輯變為可編輯的時候我要先備份一下當前行, 便于點取消的時候能夠恢復, 如果我用了淺拷貝, 這個數組里的內容指向的還是同一個地址, 當我改變當前行的時候, 其實我備份的那個也已經變了, 所以就不能恢復了, 即一個動, 全都動, 所以這里要畫個重點
b. 第二個就是vue視圖更新的問題, 數組內容更新, vue視圖是不會自動更新的, 具體可以查看官網的https://cn.vuejs.org/v2/guide/reactivity.html, 所以用splice去處理數組, 當然還有好多辦法, splice比較簡單
c. 關于業務封裝組價的問題, 因為每個人的業務是不同的, 做出符合各種功能的組件是很難的, 所以各個ui庫會盡量的把功能拆分的細小一點, 也會更加靈活, 而我們在實際業務開發中, 我們想要的是更加節省時間, 所以在原有細小的基礎上做一些相對功能豐富一點, 而且更易于配置的組件, 像這個組件, 我們除了在開發中調用它, 我們甚至只要幾個空間, 在數據庫中配置這個大json就可以了, 而不用每次都要在前端配置
當然不同的公司也會有不同的考慮, 還是希望大家都能有所進步, 也可以把你們的想法告訴我, 帶我這個渣渣一起進步, 再次感謝