admin 发表于 2022-3-2 23:24:47

react中如何实现类型vue中的slot功能?

react中最重要的两个概念:props和state。props代表的是父组件传递过来的数据。而state则代表组件内部的状态。我们要实现slot的结构。就只能依靠props了。在react中,传递props的时候。我们除了可以传递正常的数据外。还可以把jsx作为一个数据给传递过去。这样,我们就可以定制组件内部的slot结构。我们先看一个截图:


仔细看。会发现这两个表格只有右侧的操作按钮不同。其他数据和交互基本上一样。我们不需要重写这样相同的逻辑。所以打算把这个表格封装一下。在需要展示右侧操作按钮的时候,传递过去。不需要右侧的操作按钮的时候不展示。我们看看代码:

首先我们封装这个表格:


import {useState} from "react"
import {Button,Table,Space,Row,Col,Checkbox } from "antd"

function QuotaTable(props){
    let {columns,dataSource,renderTitleRtConts=<span></span>}=props
    // renderTitleRtConts 头部右侧操作内容
    console.log("renderTitleRtConts:",renderTitleRtConts)

    const =useState([])
    const =useState(false)


    const selectAll=(e)=>{
      if(e.target.checked){
          let keys=[];
          dataSource.forEach(i=>keys.push(i.key))
          setSelectedRowKeys(keys)
      }else{
          setSelectedRowKeys([])
      }
      setIsCheckeAll(e.target.checked)
      }
      const rowSelection = {
      onChange: (selectedRowKeys, selectedRows) => {
          console.log("selectedRowKeys:",selectedRowKeys)
          if(selectedRowKeys.length===dataSource.length){
            setSelectedRowKeys(selectedRowKeys)
            setIsCheckeAll(true)
          }else{
            setSelectedRowKeys(selectedRowKeys)
            setIsCheckeAll(false)
          }
      },
      selectedRowKeys,
      getCheckboxProps: (record) => ({
          disabled: record.name === 'Disabled User',
          name: record.name,
      }),
      };

    return(
      <div>
            <Table
                title={(data) =>
                <div className="table-title">
                  <Row>
                        <Col span={12}>
                            <Checkbox onChange={(e)=>selectAll(e)} checked={isCheckeAll}>全选</Checkbox>
                            已选<span className="num">{selectedRowKeys.length}</span>个对象,共1200个对象
                        </Col>
                        <Col span={12} >
                            <div className="table-title-rt">{renderTitleRtConts}</div>
                        </Col>
                  </Row>
                </div>
            }
            hideSelectAll={true}
            rowSelection={rowSelection}
            columns={columns}
            dataSource={dataSource}
            >
            </Table>
      </div>
    )
}
export default QuotaTable
然后我们看如下两个用到这个表格的地方是如何使用的:

页面A:
//页面A里用到封装的表格。注意renderTitleRtConts把jsx传递过去

const remove=()=>{

      Modal.confirm({
      title:"确定移除定额?",
      width:520,
      content:<p>移除定额仅取消本门店的定额数据,不影响基础定额以及分配的其他门店,确认移除吗?</p>,
      okText:"确定",
      cancelText:"取消",
      onCancel:()=>{
         
      },
      onOK:()=>{

      }
      })
}

//添加定额
const addQuota=()=>{
    console.log("shopQuotaRef.current:",shopQuotaRef.current)
    shopQuotaRef.current.showModelRef(true)
}
const editQuota=()=>{
    console.log("编辑定额")
}


<Tabs defaultActiveKey="1" size="large">
                {
                  combo.map(item=>
                        ( <TabPane tab={item.name} key={item.id} >
                              <div className="tab-container">
                                    <div className="tree-menu">
                                        <Tree
                                          defaultExpandParent
                                          onSelect={onSelect}
                                          treeData={treeData}
                                          titleRender={renderTitle}
                                        />
                                    </div>
                                    <div className="content">
                                    <QuotaTable
                                          columns={columns}
                                          dataSource={data}   
                                          renderTitleRtConts={
                                              <Space >
                                                <Button type="primary" onClick={addQuota}>添加定额</Button>
                                                <Button type="primary" onClick={editQuota}>编辑</Button>
                                                <Button type="primary" onClick={remove}>移除</Button>
                                              </Space>                                             
                                          }>
                                        </QuotaTable>
                                    </div>
                              </div>
                            </TabPane>
                        )
                )
            }
如上代码点击“添加定额”时再出现一个弹窗。弹窗内容就是我们封装的表格
//注意这个弹窗中不需要右侧操作按钮。我们不传

import {useHistory} from "react-router-dom"
import {Button,Space,Table,Row,Col ,Checkbox,Menu,Dropdown ,Modal , } from "antd";
import {useState,forwardRef,useImperativeHandle} from "react"
import "./quotaModalStyles//addShopQuotaModal.less"
import QuotaTable from "../quotaTable"
const menu = (
<Menu>
    <Menu.Item>
      <a target="_blank" rel="noopener noreferrer" >
       删除
      </a>
    </Menu.Item>
    <Menu.Item >
      <a target="_blank" rel="noopener noreferrer" >
      移动
      </a>
    </Menu.Item>
    <Menu.Item >
      <a target="_blank" rel="noopener noreferrer" >
       其他
      </a>
    </Menu.Item>
   
</Menu>
);

const columns = [
    {
      title: '名称',
      dataIndex: 'name',
      
    },
    {
      title: '编号',
      dataIndex: 'code',
    },
    {
      title: '产品类型',
      dataIndex: 'type',
    },
    {
      title: '单位',
      dataIndex: 'unit',
    },
   {
      title: '销售价格',
      dataIndex: 'price',
    },
    {
      title: '辅料',
      dataIndex: 'fuliao',
    },
    {
      title: '状态',
      dataIndex: 'status',
    },
    {
      title: '备注',
      dataIndex: 'mark',
    },
    {
      title: '操作',
      dataIndex: 'operate',
      render:()=>{
      return(
          <Space>
            <span>详情</span>
            <span>
            <Dropdown overlay={menu}>
                <a className="ant-dropdown-link" onClick={e => e.preventDefault()}>
                ...
                </a>
            </Dropdown>
            </span>
          </Space>
      )
      }
    }
];

const data = [];
for (let i = 0; i < 10; i++) {
    data.push({
      key: i,
      name: `天然气安装 ${i}`,
      code: `00000-${i}`,
      type:"1",
       unit: `米`,
       price:2349.00,
       fuliao:2,
       status:`${i}`,
       mark:"xxxxxxxxxxx",
       operate:null
    });
}


function AddShopQuotaModal(props,ref){

const router=useHistory()
const =useState(false)
const =useState(false)
const =useState([])


useImperativeHandle(ref, () => ({
    showModelRef:()=> operateModal('show'),
    hideModelRef:()=> operateModal('hidden')
}))

   // modal的显示与隐藏
const operateModal=(type)=>{
    if(type==="show"){
      setVis(true)
    }else{
      setVis(false)
    }
}
    return (
      <Modal
          width={1000}
          title="添加定额"
          visible={vis}
          onOk={(e)=>{operateModal("hidden")}}
          onCancel={(e)=>{operateModal("hidden")}}
         >      
            <QuotaTable
                columns={columns}
                dataSource={data}
            >
            </QuotaTable>         
      </Modal>
    )
}

export default forwardRef(AddShopQuotaModal)
不得不说。react的jsx真的厉害
页: [1]
查看完整版本: react中如何实现类型vue中的slot功能?