ant-design-vue中table自定義列
阿新 • • 發佈:2021-03-05
#### 1. 使用背景
在專案中使用`ant-vue`的`a-table`控制元件過程中,需要顯示序號列或者在列中顯示圖片,超鏈,按鈕等UI資訊。經過查詢文件`customCell`和`customRender`可以實現以上需求,比如實現如下表格資料渲染
![樣式預覽](https://img2020.cnblogs.com/blog/392126/202103/392126-20210305134054656-233191640.png)
#### 2. slots&scopedSlots作用
在檢視文件過程中,在型別一欄中經常看到 `xxx|slot |slot-scope` 這樣的描述資訊。比如`customRender`在文件中的描述資訊
```text
customRender | 生成複雜資料的渲染函式.. | **Function(text, record, index) {}|slot-scope**
```
在最初一直以為在列中可以是如下配置的
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
const tableColumn = [
{
title: '遊戲名稱',
dataIndex: 'title',
customRender:'xxslot'
}
]
```
這樣定義後執行`npm run serve`在瀏覽器會出現`customRender is not function` 的錯誤資訊。以及後來看到有如下寫法
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
const tableColumn = [
{
title: '遊戲名稱',
dataIndex: 'title',
scopedSlots: {
customRender: "customRender"
}
}
]
```
還有很長一段時間不明白`scopedSlots`這個物件的屬性為啥是`customRender`, 還有其他的什麼屬性嗎?當時知識還不完善沒有理解到文件上`使用 columns 時,可以通過該屬性配置支援 slot-scope 的屬性`的含義
雖然知道怎麼用了,但還是有必要了解下它是如何執行的。我們知道在vue中可以通過`this.$slots`、`this.$scopedSlots`分別訪問靜態插槽和作用域插槽。在檔案`components\table\index.jsx`中可以找到元件庫對`scopedSlots`、`slots`轉換成具體函式的過程,程式碼如下
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
...
// 獲取插槽
const { $slots, $scopedSlots } = this;
// 轉換靜態插槽
Object.keys(slots).forEach(key => {
const name = slots[key];
if (column[key] === undefined && $slots[name]) {
column[key] = $slots[name].length === 1 ? $slots[name][0] : $slots[name];
}
});
// 轉換動態插槽
Object.keys(scopedSlots).forEach(key => {
const name = scopedSlots[key];
if (column[key] === undefined && $scopedSlots[name]) {
column[key] = $scopedSlots[name];
}
});
```
從以上程式碼也可以知道,如果您定義如下的列配置,自定插槽會失效,以下程式碼該列會全部顯示123
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
{
title: "customRender|slot-scope",
dataIndex: '',
customRender: () => 123,
scopedSlots: {
customRender: "customRender"
}
}
```
也就是說customRender定義成函式的優先順序高於作用域插槽
#### 3. customCell
`customCell`影響的是`vnode`中的屬性資訊,你可以改變當前列的樣式等相關資訊,在檔案 `components\vc-table\src\TableCell.jsx` 對應程式碼片段
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
...
if (column.customCell) {
tdProps = mergeProps(tdProps, column.customCell(record, index));
}
...
return (
{indentText}
{expandIcon}
{text}
);
```
所以這個物件可以傳遞值可以參考vue官方文件[深入資料物件](https://cn.vuejs.org/v2/guide/render-function.html#深入資料物件)中的描述。你可以返回如下對改變當前列的字型大小和顏色
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
return {
style: {
color: 'red',
fontSize: '14px'
}
}
```
也可通過如下改變顯示的內容
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
return {
domProps: {
innerHTML: record.title + "#" + (index + 1)
}
}
```
#### 4. customRender
`customRender`也可以影響當前列的顯示資訊,不過它更靈活。可以返回一段`jsx`獲取返回一個類似`customCell`一樣的屬性資訊。不過從程式碼來看,它只接收一下屬性**attrs**、**props**、**class**、**style**、**children**,而且它的優先順序也沒有`customCell`優先順序高。`customRender`可以是一個插槽,也可以是一個函式。
當作為插槽使用時程式碼應該如下所示
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
[{
title: "customRender|slot-scope",
dataIndex: '',
scopedSlots: {
customRender: "customRender"
}
},{
title: "customRender|slot-scope",
dataIndex: '',
slots: {
customRender: "customRender"
}
}]
```
從上邊瞭解到的插槽知識可以知道**作用域插槽的優先順序高於靜態插槽**也就是說,在一個列中分別配置了鍵值相等的靜態插槽和作用域插槽,將優先顯示作用域插槽的內容
當作為函式使用時,程式碼應該如下所示
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
[{
title: '遊戲特點',
dataIndex: 'desc',
customRender: (text, record, index) => {
if (index == 1) {
return {text} @小院不小
}
return {
attrs:{},
props:{},
class:{},
style:{},
children: text
}
}
}]
```
兩種返回值元件通過`isInvalidRenderCellText`函式判斷。判斷是否是`jsx`的方式主要程式碼如下
``` javascript
// 公眾號:小院不小 date 20210205 wx:464884492
function isValidElement(element) {
return (
element &&
typeof element === 'object' &&
'componentOptions' in element &&
'context' in element &&
element.tag !== undefined
);
}
```
通過上邊的說明,我們就能很好的使用`customRender`屬性了。不過我們還是有必要了解一下,這段屬性對應原始碼邏輯。在檔案`components\vc-table\src\TableCell.jsx` 對應的程式碼片段如下
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
if (customRender) {
text = customRender(text, record, index, column);
if (isInvalidRenderCellText(text)) {
tdProps.attrs = text.attrs || {};
tdProps.props = text.props || {};
tdProps.class = text.class;
tdProps.style = text.style;
colSpan = tdProps.attrs.colSpan;
rowSpan = tdProps.attrs.rowSpan;
text = text.children;
}
}
if (column.customCell) {
tdProps = mergeProps(tdProps, column.customCell(record, index));
}
```
#### 5. 總結
ant的元件很靈活,很多需要通過擴充套件來實現一些特殊的功能.`customRender`和`customCell`都可以實現自定義列資訊。在什麼場景下使用,還需要根據不同業務訴求。比如我要改變列字型,顏色等,我們就優先考慮`customCell`.根據上面的介紹這裡有一個面試題程式碼如下
```javascript
// 公眾號:小院不小 date 20210205 wx:464884492
{
title: "自定義列",
dataIndex: '',
customRender:()=> '函式渲染'
scopedSlots: {
customRender: "scopedSlots"
},
slots: {
customRender: "slots"
}
}
```
請問列`自定義列`最終渲染的內容是
+ A 函式渲染
+ B scopedSlots
+ C slots
如果想知道答案或需要Demo原始碼請掃描下方的二維碼,關注公眾號[**小院不小**],回覆`ant-table`獲取.
![公眾號](https://images.cnblogs.com/cnblogs_com/yfrs/1583406/o_210303114612