通過對iview的table表格的封裝,實現如何自定義表格的內容。實現一個可編輯的表格。

為了節省時間,首先已經做了一些准備
首先是已經創建了table頁

然后寫了一個api,用來獲取表格數據。

然后在mock里面也進行了處理。返回了數據的響應

tools里面封裝了一個方法doCustomTImes

times是循環的次數,callback是回調函數。

執行循環5次,根據template生成5條數據記錄。

最后在table頁調用訪問api的方法

可編輯表格組件
創建edit-table組件。

index.js內,引入並導出組件

組裝封裝,只用到iview里面的table組件。外面不用包裹頂層的div直接用Table就可以了。

有兩個需要傳的重要的屬性,一個是定義列的數組,一個是數據的數組。在table.vue里面我們已經定義好了。

key就是綁定的字段值,title就是列的標題。editable是我們自定義的屬性,並不是iview的屬性。

引入組件並注冊

組件內定義屬性 columns是一個空的數組,數組設置默認值,要寫一個回調函數,返回一個空數組。


把屬性傳入Table組件。

給表格添加可編輯的按鈕
要給這個表格添加一個可編輯的按鈕。是不是要在columns里面給這個列添加一個render回調函數呢?如果你在這里要自己寫的話,是要加一個render,然后傳入一個回調函數。

我們既然要封裝一個可編輯表格,那么這個工作肯定是要內部做了。
所以在哪去處理,這里列數組的東西呢?
首先在計算屬性里面 我們拿到了列

在這里我們就要會columns做處理了。在這里定義一個indiseColumns,因為我們不能直接修改父組件傳遞過來的數據的。如果要修改就必須拋出一個事件,在父組件內接收事件,在事件的綁定回調函數里面去做數據的修改。

這里我們用map做映射

如果傳入的列有render函數,說明在外面自定義了render

只要是沒有自帶render,並且editable為true的情況下。

這里是一個解構賦值的形式

第一個參數是組件名,第二個參數是可配置的屬性,第二個參數是可選的。

如果沒有需要可設置的值,就把它刪掉。

第三個參數是當前這個節點的子節點,如果里面就寫一個字符串。它渲染出來的就是包含這個字符串的div

如果你是一個組件,第三個參數就是一個數組,比如我們渲染之前封裝的CountTo組件,然后后面定義相關的屬性。
第三個參數一定是一個數組或者是字符串。這是render函數的寫法。

jsx
為了簡介簡便,我們用jsx的寫法。直接返回一個括號,在括號里面要渲染我們的標簽。

這里必須有一個最外層的div包裹。任何東西都包在這個div里面。

點擊這里就編程一個輸入框。點擊保存輸入框小時,文字顯示了。這里應該是一個v-if和v-else的邏輯
但是在jsx里面我們沒法用v-if這些指令。所以我們要通過js去判斷這個邏輯。我們的邏輯和變量都要用花括號來包裹。

先點擊第一行編輯 第一個22就編程輸入框,再點擊20的數字,20這里編程輸入框。同時只能編輯一個單元格。那么我可以給每個單元格一個標志。當我點擊某個單元格的編輯按鈕的時候,讓那個全局的值,變成黨員個格的值,通過這個全局的標志來判斷當前哪個單元格應該顯示輸入框。

定義全局的變量。這個edittingId,表格里面每一行都有一個行號。每一列都有一個key值。我們通過行號和key值就能確定單元格。我們的這個edittingId就是行號和key拼接起來,就能代表一個單元格。

先把這三個值打印出來,看一下

表格里最后用的是insideColumns


需要定義這個變量



打印出來的值。

第三個值

這樣就獲取到這一列的單元格

接下來要加一個按鈕,iview的組件呢在jsx里面 要用i-的形式。

增加編輯按鈕。

接下來要判斷點擊的是哪個單元格的按鈕。iview里面的button有自帶的click事件,所以這里要用on-的前綴 后面拼上click

直接沒有傳參數的調用,記得要用大括號,括起來。


傳參數要用.bind去執行,要在this上去執行,第一個參數是this

對象結構賦值的形式去寫。傳入row、index、column


方法這里就要以同樣的方式去接收



拼接edittingId

當點擊的時候,要把默認的數據填進去



加個樣式


內容和輸入框是二選一的形式
如果當前的拼接的edttingId是當前的,那么顯然input標簽。



把input標簽的代碼移到這里

點擊才會顯示輸入框

給input綁定事件。input我們平時用的時候是用v-model去綁定。v-model就相當於綁定value值同時綁定一個input事件,通過input事件修改這個value值。在這里我們要接收這個input事件

定義一個全局的變量去接收它

這樣每次修改內容的時候,就把它綁定到到這個edttingContent變量里面。

把這提取出來一個常量。


點擊編輯后,這里編程保存。

判斷,當前點擊是編輯狀態

否則就讓處於編輯狀態。

我們要修改傳入的tableData。所以這里改成用 v-model去綁定tableData

那么組件內屬性就要用value了。這是固定的寫法

這里需要把value值深拷貝一份去修改深拷貝后的數組,然后把這個數組通過emit傳到父組件內。

深拷貝
深拷貝我們安裝一個插件 。自己安裝。

先引進來


修改后點保存,只是console輸出了。

修改后把this.edittingId變成一個空的字符串

這樣這個內容就編輯好了

再添加一個事件,我們一般是需要獲取你編輯的是哪一行哪一列。on-edit把編輯的信息都導出去。

再增加一個NewValue告訴 父組件,更新后的值是什么

保存后,把這個edittingContent也變成空

父組件內接收這個事件
接收這四個值,並打印出來。

編輯--保存后--

編輯后的值

后端如果獲取了新的數據,如果表頭也發生了變化。所以我們要監聽columns的更新

用watch監聽。首先把這套邏輯提取出來封裝成一個方法。

監聽columns,如果更新了我們再執行一下

這樣我們編輯單個單元格就完成了


封裝第二個表格
可以同時編輯多個單元格

引入這個組件

傳的數據還是這兩個


剛才是編輯一個單元格,可以通過唯一的id去實現的。沒個單元格都可以變為同時編輯的狀態,所有的都顯示輸入框,那么就不能通過這個唯一id來實現了。所以這個時候,應該是兩份數據,把傳進來的表格數據copy一份,然后在這個上面,給這個數據對象做數據,每一行都來維護一個編輯狀態。
比如第一行,它是一個對象,里面有三個字段。我把編程編輯狀態的這一列key傳進去放在一個數組里。通過判斷當前的key,這一行的key在不在這個數組里 ,來判斷它是不是顯示狀態。

實際操作開始
我們還是在之類進行改造。首先還是判斷這個columns,判斷當前有沒有可編輯的。

數據字段上給他一個新的字段keyArray

每一行的數據對象上添加edittingKeyArr

如果行數據對象上有這個keyArr這個字段,

並且當前這個column.key在這個數組里,那就說明你這一行這一列是編輯狀態下,那么我們就顯示這個輸入框。

下面同樣的判斷條件


這里先深拷貝一份

我們要判斷當前行數據是 有沒有的, 如果有就取里面的edittingKeyArr如果沒有就是空的數組[]

數據變了的時候,要把value重新拷貝一下。所以監聽value值的變化,值變的時候也執行下this.handleColumns()方法

取當前行上的edittingKeyArra.如果有這個值說明是點擊過當前行按鈕的 。因為我們點一下會把這個key傳進去。

還是先來寫沒有這個edittingKeyArra的情況吧。
判斷rowObj這個對象上有edittingKeyArr屬性並且,edittingKeyArr.lenhth表示里面是有東西的,這里也就是length不為0的意思,

那么我們就把edittingKeyArr里面拆分出來 ,通過三個點的操作符,並且把column.key當前行的key值,也放到這個數組里面。


沒有這個字段,那么就把當前column.key添加進去。


這樣還不夠,這樣修改這個數組,還不是一個深度的watch

使用splice才會觸發這個視圖的更新。
splice會在你這個index索引的位置上,第二個參數傳入要刪除幾個元素,第三個參數是你要添加的元素。刪掉一個添加一個相當於是一個替換

這里為0,先來測試下

點擊都可以編輯了

點擊保存,變成編輯狀態
我們要判斷當前行的key在不在數組里。在的話,說明它是編輯狀態,

如果有這個數組,

那么就取索引號,

沒有這個數組,直接就-1

如果大於-1 說明在這個數組里面找到了當前這個單元格的key。說明他就是編輯狀態。


把修改后的對象替換到insideData里。用splice方法刪一個,然后替換一個。

通過提交一個input事件

來觸發父組件的v-model 來替換傳進來的tableData數據。

同時觸發on-edit事件

下面兩行代碼刪掉。刪掉后如下。

測試修改后,沒有替換

輸出值,看下實際的有沒有被改變


值沒有被改變 ,還是21

是因為我們的handleInput還沒有修改。文本框的值改變了要觸發handleInput事件

用bind來綁定,傳入三個值row、index、column這三個值


第四個參數就是原來默認傳入的值。前三個就是上面傳入的值。

修改后視圖更新了

注意事項
在封裝這個組件的時候,有些人會遇到這么個問題,直接去修改這個value值。

修改的時候你不是修改的insideData。而是你通過一個事件

通過input事件每次修改的時候,都觸發新的值,你是在handleInput里面去做input,然后去提交。然后父組件修改tableData

這樣就會有問題了。你每次在文本框內修改內容的時,其實都是通過input事件把修改后的東西,修改之后然后再新的表格數據那個數組,推送到父組件,父組件值改變之后,你綁定的這個tableData改變之后呢,他其實是會重新渲染這個組件,因為數據變了。視圖也要變化。
那你這個時候重新渲染,輸入框就被重新渲染了,你現在是編輯的狀態,是獲取焦點了。重新渲染的焦點就消失了。你再繼續輸入就沒法輸入了。所以你就需要輸入一次,點一下文本框旁邊的空白,點擊獲取焦點輸入一下。

演示這個效果
在這個地方觸發input

輸入一下焦點就失去了,是因為這個表格組件重新渲染了。再點擊文本框才能輸入,但是再輸入一次,又沒法輸入了。

所以這個地方不是在這里去觸發input,而是在點完保存之后,再去重新觸發視圖的渲染。這個時候就不會有問題了。


那么可以同時編輯多個單元的組件,我們就封裝完成了
注意點
就是在jsx里面沒法使用v-if 等這些指令的,

要通過在花括號里寫原生的js邏輯

綁定事件的時候呢,不需要傳參數就可以直接這樣

如果需要傳參數,就需要用bind方法,綁定到這個this上。

箭頭函數的方式傳值

本節代碼

結束
