溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

React Ant Design實(shí)現(xiàn)樹(shù)形表格的復(fù)雜增刪改

發(fā)布時(shí)間:2020-11-03 14:48:37 來(lái)源:億速云 閱讀:1057 作者:Leah 欄目:開(kāi)發(fā)技術(shù)

本篇文章給大家分享的是有關(guān)React Ant Design實(shí)現(xiàn)樹(shù)形表格的復(fù)雜增刪改,小編覺(jué)得挺實(shí)用的,因此分享給大家學(xué)習(xí),希望大家閱讀完這篇文章后可以有所收獲,話不多說(shuō),跟著小編一起來(lái)看看吧。

樹(shù)形表格的顯示

在antd中對(duì)于表格的key值有著嚴(yán)格的控制,每一個(gè)row都必須有一個(gè)獨(dú)一無(wú)二的key值,可以是數(shù)字也可以是字符串。這一點(diǎn)和我曾經(jīng)使用過(guò)得iview有著很大的區(qū)別。react使用key來(lái)代表每一行是為了避免重新渲染的問(wèn)題,這個(gè)優(yōu)化也在實(shí)際的開(kāi)發(fā)中帶來(lái)了不少的問(wèn)題。比如新建行時(shí)需要自定義新key。

下面直接上一下代碼及代碼效果,這是一個(gè)三級(jí)的樹(shù)形表格,且其中包含二級(jí)標(biāo)題。

最終效果 ​

React Ant Design實(shí)現(xiàn)樹(shù)形表格的復(fù)雜增刪改

colums標(biāo)題: 簡(jiǎn)易版標(biāo)題,隨著功能的增加,我們將增加colums的復(fù)雜度。

let columns = [
 {
  title: '題目',
  dataIndex: 'text'
 },
 {
  title: '類(lèi)型',
  children: [
   {
    title: '一級(jí)',
    dataIndex: 'text1'
   },
   {
    title: '二級(jí)',
    dataIndex: 'text2',
   }]
 },
 {
  title: '內(nèi)容',
  dataIndex: 'content'
 },
 {
  title: '答案',
  dataIndex: 'answer',
 },
 {
  title: '類(lèi)型',
  dataIndex: 'mark_type',
  className: 'line'
 },
 {
  title: '版本',
  dataIndex: 'version',
  className: 'line'
 },
 {
  title: '一級(jí)內(nèi)容點(diǎn)',
  dataIndex: 'value1',
  className: 'line'
 },
 {
  title: '二級(jí)內(nèi)容點(diǎn)',
  dataIndex: 'value2',
  className: 'line'
 },
 {
  title: '操作',
  key: 'action',
  width: 205
 }
];

data數(shù)據(jù):

let data = [{
   "key": 1,
   "text": "題目一",
   "children": [{
    "key": 11,
    "text1": "數(shù)學(xué)一",
    "children":[]
   }, {
    "key": 12,
    "text1": "語(yǔ)文一",
    "value1": "語(yǔ)文",
    "children": [{
     "key": 121,
     "value2": "選擇",
     "text2": "選擇題",
     "content": "題目?jī)?nèi)容",
     "answer": "A",
     "mark_type": "1",
     "version": "1"
    },{
     "key": 122,
     "value2":"填空",
     "text2": "填空題",
     "content": "題目?jī)?nèi)容",
     "answer": "梅花",
     "mark_type": "1",
     "version": "1"
    },{
     "key": 123,
     "value2": "閱讀",
     "text2": "閱讀題",
     "content": "題目?jī)?nèi)容",
     "answer": "野蠻生長(zhǎng)",
     "mark_type": "1",
     "version": "1"
    },{
     "key": 124,
     "value2": "文言文",
     "text2": "文言文",
     "content": "題目?jī)?nèi)容",
     "answer": "滕王閣序",
     "mark_type": "1",
     "version": "1"
    }],
   }],
  }, {
   "key": 2,
   "text": "題目二",
   "children": [ {
    "key": 21,
    "text1": "英語(yǔ)一",
    "value1": "英語(yǔ)",
    "children": [{
     "key": 211,
     "value2": "完型",
     "text2": "完形填空",
     "content": "題目?jī)?nèi)容",
     "answer": "ABC",
     "mark_type": "2",
     "version": "1"
    },{
     "key": 212,
     "value2": "一級(jí)代碼",
     "text2": "選擇",
     "content": "題目?jī)?nèi)容",
     "answer": "D",
     "mark_type": "2",
     "version": "1"
    }],
   }],
  }];

增加子項(xiàng)數(shù)據(jù)

增加子項(xiàng)數(shù)據(jù)使用操作中的增加按鈕進(jìn)行增加,增加按鈕設(shè)置為圖形,更為形象具體清晰化。

 //button樣式使用antd自帶icon樣式
<Button type="primary" shape="circle" icon="plus" size={'small'}
   onClick={this.handleAdd.bind(this, record)}
 />

注意事項(xiàng):

1、對(duì)于最子項(xiàng)來(lái)說(shuō)沒(méi)有增加子項(xiàng)選擇,需要對(duì)不同數(shù)據(jù)行進(jìn)行不同處理

2、不同數(shù)據(jù)行新增數(shù)據(jù)的內(nèi)容不同,字段也不同

3、新增之后需要點(diǎn)擊確認(rèn)或者取消

4、加入數(shù)據(jù)點(diǎn)擊確認(rèn)之后需要添加于當(dāng)前key下的children中

本想使用antd自帶的editable屬性,但是這個(gè)屬性不支持二級(jí)標(biāo)題的編輯,所以只有自己寫(xiě)render

這個(gè)問(wèn)題,在7102年就提出來(lái)了,但是已經(jīng)8102年了快9102年都沒(méi)有更新。

新增一級(jí)類(lèi)型題目樣式

React Ant Design實(shí)現(xiàn)樹(shù)形表格的復(fù)雜增刪改

新增二級(jí)類(lèi)型題目樣式

React Ant Design實(shí)現(xiàn)樹(shù)形表格的復(fù)雜增刪改

這里就部分render代碼:

//分級(jí)標(biāo)題
{
 title: '類(lèi)型', 
 children: 
 [{
  title: '一級(jí)',
  dataIndex: 'text1',
  render: (text, record) => {
   if (this.state.isEditing && this.state.editingOneKey === record.key)
    return <Input defaultValue={text} onChange={(e) => { this.changeEdit(e, record.key, 'text1') }} />
   return text
  }
 },
 {
  title: '二級(jí)',
  dataIndex: 'text2',
  render: (text, record) => {
   if (this.state.isEditing && this.state.editingTwoKey === record.key)
    return <Input defaultValue={text} onChange={(e) => { this.changeEdit(e, record.key, 'text2') }} />
   return text
  }
 }]
}

//select選擇
{
 title: '內(nèi)容',
 dataIndex:'content',
 render:(text, record) => {
  if (text === 0)
   text = '內(nèi)容一';
  if (text === 1)
   text = '內(nèi)容二';
  if (this.state.isEditing && this.state.editingTwoKey === record.key) {
   return <Select defaultValue={text} onChange={(e) => {
    this.changeEdit(e, record.key, 'flag')
   }} getPopupContainer={triggerNode => triggerNode.parentNode}>
    <Option value='0'>有效</Option>
    <Option value='1'>無(wú)效</Option>
   </Select>
  }
  return text
 }
}

注意展開(kāi)

如果對(duì)一行未展開(kāi)的行下新增數(shù)據(jù),那么無(wú)法看到打開(kāi)的編輯狀態(tài)是一個(gè)非常糟糕的問(wèn)題。所以我們需要在新增子項(xiàng)的時(shí)候自動(dòng)展開(kāi)父項(xiàng)。

//steate初始化 
expandedRows: [] //展開(kāi)行
//render 初始化
<Table
  bordered
  expandedRowKeys={this.state.expandedRows}
  onExpandedRowsChange={this.changeExpandedRows.bind(this)}
/>

//自動(dòng)展開(kāi)變化,獲取當(dāng)前展開(kāi)行
changeExpandedRows = (expandedRows) => {
  this.setState({
   expandedRows
  })
 };

//增加函數(shù)中
let rows = this.state.expandedRows;
rows.push(record.key);
this.setState({
 expandedRows: rows
});

刪除行數(shù)據(jù)

刪除在antd中相較比較簡(jiǎn)單,因?yàn)閍ntd的table每行都有key屬性,key是唯一且必須的屬性,所以只要過(guò)濾掉包含目的key的數(shù)據(jù)即可視為刪除。因?yàn)檫@是樹(shù)形數(shù)據(jù),普通的遍歷無(wú)法進(jìn)行操作,所以使用深度優(yōu)先遍歷來(lái)進(jìn)行數(shù)據(jù)處理,也可以使用廣度優(yōu)先,根據(jù)數(shù)據(jù)來(lái)變更。

handleDelete = (key) => {
  let data = this.state.data;
  data = dsFilter(data, key);

  this.setState({
   data
  });

  function dsFilter(dealData, dealKey) {
   for (let i = 0; i < dealData.length; i++) {
    if (dealData[i].children && dealData[i].children.length > 0) {
     dealData[i].children = dsFilter(dealData[i].children, dealKey);
    }
   }
   return dealData.filter(item => item.key !== dealKey);
  }
 };

修改某些字段

修改和新增的colums相同,不過(guò)修改需要保存之前的值。需要在input或select中設(shè)置defaultValue={text}來(lái)保證初始值相同

保存

無(wú)論是新增修改還是刪除,都需要進(jìn)行保存。這里使用&#10003;和&#10007; 來(lái)代表確定和取消。

同時(shí)需要注意,如果在一行的編輯中點(diǎn)擊其他行的操作,需要將之前行的操作視為取消。

React Ant Design實(shí)現(xiàn)樹(shù)形表格的復(fù)雜增刪改

<div>
 <Button shape="circle" icon="check" size={'small'} style={{ backgroundColor: '#65BF34', color: '#FFF', border: 'none' }}
   onClick={this.saveEdit.bind(this, record.key)}
 />
 <Button shape="circle" icon="close" size={'small'} style={{ backgroundColor: '#FF3333', color: '#FFF', border: 'none' }}
   onClick={this.cancelEdit.bind(this, record.key)}
 />
</div>

修改順序

修改順序就是修改數(shù)據(jù)在數(shù)組中的順序,使用簡(jiǎn)單的temp進(jìn)行交換即可。

shiftUp = (key) => {
  let data = this.state.data;
  data = dsShift(data, key);
  this.setState({
   data
  });

  function dsShift(dealData, dealKey) {
   for (let i = 0; i < dealData.length; i++) {
    if (dealData[i].children && dealData[i].children.length > 0) {
     dealData[i].children = dsShift(dealData[i].children, dealKey);
    }
    if (dealData[i].key === dealKey) {
     if (i === 0) {
      message.warning('該行已置頂!');
      break;
     }
     let temp = dealData[i - 1];
     dealData[i - 1] = dealData[i];
     dealData[i] = temp;
     break;
    }
   }
   return dealData;
  }
 };

 shiftDown = (key) => {
  let data = this.state.data;
  data = dsShift(data, key);
  this.setState({
   data
  });

  function dsShift(dealData, dealKey) {
   for (let i = 0; i < dealData.length; i++) {
    if (dealData[i].children && dealData[i].children.length > 0) {
     dealData[i].children = dsShift(dealData[i].children, dealKey);
    }
    if (dealData[i].key === dealKey) {
     if (i === dealData.length - 1) {
      message.warning('該行已置尾!');
      break;
     }
     let temp = dealData[i + 1];
     dealData[i + 1] = dealData[i];
     dealData[i] = temp;
     break;
    }
   }
   return dealData;
  }
 };

總結(jié)

在進(jìn)行表格數(shù)據(jù)操作中,需要進(jìn)行變量的保存,這里就沒(méi)有多寫(xiě)了??偟膩?lái)說(shuō)antd是個(gè)好組件,大部分功能都很齊全,但是很多細(xì)節(jié)還是需要自己進(jìn)行完善。

補(bǔ)充知識(shí):Antd(Ant-design),嵌套子表格(expandedRowRender)的異步獲取數(shù)據(jù)

使用阿里的ant-design開(kāi)源框架,要在表格里面嵌套子表格,需要在用戶點(diǎn)擊父表格的一行數(shù)據(jù)后,獲取該行的key,然后去異步請(qǐng)求后臺(tái)的數(shù)據(jù)用來(lái)填充子表格的內(nèi)容。

如果這樣寫(xiě)(省略無(wú)關(guān)代碼):

expandedRowRender = (record) => {
 
  dispatch({
    type: 'flow/getPlanList',
    payload: {
      contractId: record.contract_id, // 該參數(shù)是從父表格帶過(guò)來(lái)的key
    },
    callback: () => {
      const {
       flow: { data },
      } = this.props; 
 
      this.setState({
       secData: data.list,
      });
 
      console.log("返回?cái)?shù)據(jù)(PlanList):" + JSON.stringify(this.state.secData));
    }
  });
  
  return (
    <Table
      columns={secColumns}
      dataSource={this.state.secData}
      pagination={false}
    />
  );
};
 
render() {
  return(
    <Card>
     {this.renderForm()}
     <div>
       <Table
        expandedRowRender={this.expandedRowRender}
        loading={loading}
        rowSelection={rowSelection}
        dataSource={list}
        columns={columns}
        pagination={paginationProps}
        scroll={{ x: 2500}}
        size = 'middle' 
        expandRowByClick={true}
        onSelect={this.seFn}
       />
     </div>
    </Card>
  ) 
}

則會(huì)出現(xiàn)不斷的發(fā)起請(qǐng)求的現(xiàn)象:

React Ant Design實(shí)現(xiàn)樹(shù)形表格的復(fù)雜增刪改

這是因?yàn)?,expandedRowRender 實(shí)際上是在 Table 組件的 render 方法中調(diào)用的,React render 中用 dispatch 會(huì)造成重復(fù)調(diào)用的問(wèn)題,dispatch -> setState -> render -> dispatch -> setState -> render,循環(huán)往復(fù)。所以應(yīng)該把 dispatch 放在 onExpand 中。

onExpand = (expanded, record) => {
  const { dispatch } = this.props;
 
  dispatch({
    type: 'flow/getPlanList',
    payload: {
     contractId: record.contract_id,
    },
    callback: () => {
      const {
        flow: { data },
      } = this.props; 
 
      this.setState({
        secData: data.list ,
      });
 
     console.log("返回?cái)?shù)據(jù)(PlanList):" + JSON.stringify(this.state.secData));
    }
  });
}

但是單純的這樣做,又會(huì)帶來(lái)新的問(wèn)題,就是子表格的所有數(shù)據(jù)都變成了相同的。

本人的解決辦法是使用鍵值對(duì)。

onExpand = (expanded, record) => {
  const { dispatch } = this.props;
 
  if (expanded === false) {
   // 因?yàn)槿绻粩嗟奶砑渔I值對(duì),會(huì)造成數(shù)據(jù)過(guò)于龐大,浪費(fèi)資源,
   // 因此在每次合并的時(shí)候講相應(yīng)鍵值下的數(shù)據(jù)清空
   console.log("合并!");
   this.setState({
    subTabData: {
     ...this.state.subTabData,
     [record.contract_id]: [] ,
    }
   });
  } else {
   console.log("展開(kāi)!");
   dispatch({
    type: 'flow/getPlanList',
    payload: {
     contractId: record.contract_id,
    },
    callback: () => {
     const {
      flow: { data },
     } = this.props; 
 
     this.setState({
      subTabData: {
       ...this.state.subTabData,
       [record.contract_id]: data.list ,
      }
     });
 
     console.log("返回?cái)?shù)據(jù)(PlanList):" + JSON.stringify(this.state.subTabData));
    }
   });
  }
 }

以上就是React Ant Design實(shí)現(xiàn)樹(shù)形表格的復(fù)雜增刪改,小編相信有部分知識(shí)點(diǎn)可能是我們?nèi)粘9ぷ鲿?huì)見(jiàn)到或用到的。希望你能通過(guò)這篇文章學(xué)到更多知識(shí)。更多詳情敬請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI