react组件插槽 - 实现自己的可扩展的组件

2019-06-04  本文已影响0人  小小的开发人员

需求
  我们自己写了个组件,引用组件时想要在组件中写入内容,并且写入的内容可以被组件识别、控制,用过Vue的同学肯定会立刻想到slot插槽,react也支持插槽功能,下面我们用react开发一个支持插槽功能的组件。

核心思想
  父组件在子组件中传入的三个div,这三个div会默认通过props传到子组件中,然后我们在子组件中控制children的渲染即可。

<Window display={this.state.display}>
//父组件在子组件中传入的三个div,
<div papa="title">title</div>
<div papa="content">content</div>
<div papa="foot">foot</div>
</Window>

  知道了react的插槽实现方式,我们来实现一个支持插槽的组件。

完成组件Pop

import React from 'react';
import {Fragment, Component} from 'react';
import { connect } from 'react-redux'
import './index.scss'
import { Icon, Button } from 'zent'

class Pop extends Component {

    constructor(props) {
        super(props);
        this.state = {}
        this.renderChild = this.renderChild.bind(this)
    }

    render() {
        return (
            <Fragment>
                <div className="pop-wrap">
                    <div className="pop-header">
                        <span className="left">{this.props.popTitle}</span>
                        <Icon className="right" type="close"/>
                    </div>
                    <div className="pop-content">
                        {Array.isArray(this.props.children) ?
                        this.props.children.map((child) => {
                            return this.renderChild(child)
                        }) : this.props.children && this.renderChild(this.props.children)}
                    </div>
                    <div className="pop-footer">
                        <Button.Group>
                            <Button size="small" className="cancel">取消</Button>
                            <Button size="small" type="primary" className="confirm">确定</Button>
                        </Button.Group>

                    </div>
                </div>
            </Fragment>
        )
    }

    renderChild (child) { // 控制内容的分发
        if (child.props.left) {
            return <div className="left" key="left">{child}</div>
        } else if (child.props.right) {
            return <div className="right" key="right">{child}</div>
        } else if (child.props.center) {
            return <div className="center" key="center">{child}</div>
        }
    }

}


const mapStateToProps = (state) => {
    return {
    }
}
const mapDispatchToProps = (dispatch) => {
    return {}
}

export default connect(mapStateToProps, mapDispatchToProps)(Pop)

Pop的scss文件

.pop-wrap {
  position:absolute;
  left:0;
  top: 0;
  bottom: 0;
  right: 0;
  margin: auto;
  z-index: 2;
  width: 350px;
  height: 300px;
  border: 1px solid #C8C8C8;
  border-radius: 2px;
}

.pop-header {
  height: 40px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid #C8C8C8;
  .left{
    flex: 10;
    margin-left: 10px;
  }
  .right {
    flex: 1;
    margin-right: 10px;
  }
}

.pop-content {
  display: flex;
  height: 220px;
  .left, .right, .center {
    display: flex;
    justify-content: center;
    padding-top: 10px;
  }
  .left,.right {
    flex: 1;
  }
  .center {
    width: 100%;
  }
  .right{
    border-left: 1px solid #C8C8C8;

  }
}

.pop-footer {
  height: 40px;
  display: flex;
  align-items: center;
  border-top: 1px solid #C8C8C8;
  flex-direction: row-reverse;
  .cancel, .confirm{
    margin-right: 10px;
  }
}

引用子组件



上一篇下一篇

猜你喜欢

热点阅读