基于React封装的Panle组件

React可以说是当前最火的前端框架了(官方低调的说是JS类库),相对于angularjs来说轻量不少,这也导致了,我们在处理具体的业务时会碰到很多React解决不了的东西,这时就需要第三方类库去处理。而Antd作为对React支持最好的页面渲染技术,自然而然的在React项目中广泛应用。

最近在研究React+Antd的框架搭建项目时,碰到了一些问题。之前使用Bootstrap+angularjs时,习惯了Bootstrap的那种方式,再使用到Antd时有点不适应。好在官方都有文档。

我们知道在单页面应用中,最常用的外层嵌套就应该是Panle(面板)了,我们可以在Panle中加入不同的东西,比如,table,form,报表等。但是遗憾的是,我没有再Antd中发现Panel组件,更多的是折叠面板,不符合我的需求。

在使用到Bootstrap时,一个基本的Panle包含Header,Body,Footer三部分。

Header是提示栏,title

Body应该是我的Form表单

Footer应该包含一些自定义操作按钮。

但在Antd中没有发现类似的组件,先考虑引入bootstrap,但是一想,antd中有很多组件都类似bootstrap,不能因为一个panel组件而引入整个bootstrap,而且bootstrap本身还有依赖于jquery,想了想不划算。

于是自己合计去封装一个Panle,正好对应着React一切皆组件的思想。

话不多说,来说一下思路。

首先,对于Header,我们来看看哪些东西需要我们封装。Header最主要的应该包含两部分,一个是title,一个是背景色(当然你也可以定义其他的属性,比如字体等,这里用title和背景色做用例)。

因为我们的不同模块对应着不同的title,那么这个title就需要作为参数传递过来。学过React的都知道,从父组件向子组件传递的属性,我们都可以在子组件中通过props属性来获取。

 

那么现在我们可以确定的是 props中至少包含{title:"",background:""}。

那Header就可以这么定义:

<div style={{ width: "100%", background: "#f5f5f5",lineHeight:"40px" }}>
                   <span style={{paddingLeft:"20px"}}>{this.props.title}</span> 
                </div>

其次Body体中我们怎么将父组件中的DOM元素Form表单传递给子组件。

当然在Bootstrap中很简单

<div class="panel panel-primary">
	<div class="panel-heading">
		<h3 class="panel-title">面板标题</h3>
	</div>
	<div class="panel-body">
		这是一个基本的面板
	</div>
	<div class="panel-footer">
		这里是Footer
	</div>
</div>

我们直接早panel-body中加入我们的form表单就行,但是使用React就不一样了,首相我想到的就是怎么将DOM元素加载到子组件中,是不是也是通过props的属性传递的。

下面我们来看一下props的值

这里注意一下children这个属性,他的类型是个react.element那它是不是就代表着DOM中的元素。

于是关于Body中的定义我们就可以这么定义:

<div style={{ width: "100%", height: "90%", textAlign: "center"}}>
                    <div style={{ width: "100%", height: "90%", textAlign: "center", marginTop: "20px" }}>
                        {this.props.children}
                    </div>
                </div>

然后,关于Footer的定义,其实我们在Footer主要需要两个按钮,一个保存,一个取消。一个向后台发起请求,一个取消表单然后返回或者做其他操作。

在React中怎么给在子组件中触发父组件的方法呢?

React给出的解决方案有好几个,可以通过父组件传递一个callback函数,让子组件触发父组件的函数,就可以了。另外一种就是通过上下文(这里不介绍这种方式)。

原理我们现在清除了,就可以定义Footer部分了:

<div style={{ width: "100%", height: "50px", background: "#f5f5f5" }}>
                    <div style={{ float: "right" , lineHeight: "50px"}}>
                        <span style={{ paddingRight: "10px" }}><Button type="primary" onClick={this.props.panelConfig.cancelFunction}>{this.props.panelConfig.cancel ? this.props.panelConfig.cancel : "Cancel"}</Button></span>
                        <span style={{ paddingRight: "10px" }}><Button type="primary" onClick={this.props.panelConfig.finishFunction}>{this.props.panelConfig.finish ? this.props.panelConfig.finish : "Save"}</Button></span>
                    </div>

                </div>

父组件中我们改善一下,将要传递的属性值都封装到一个对象中,然后通过props传递给子组件

const panel = {
            title: "Create NAS Client",
            size: "middle",
            cancelLable: "Cancel",
            finishLable: "Save",
            finishFunction: this.createNasClient,
            cancelFunction: this.returnList
        }

父组件render函数中:
 

return (
            <div style={{ width: "100%", paddingTop: '50px' }}>
                <CustomPanle panelConfig={panel}>
                    <Form {...formItemLayout}>
                        <Form.Item label="Nas Name">
                            {getFieldDecorator('nasName', {
                                rules: [

                                    {
                                        required: true,
                                        message: 'Please input your E-mail!',
                                    },
                                ],
                            })(<Input />)}
                        </Form.Item>
                        <Form.Item label="Nas Start IP" hasFeedback >
                            {getFieldDecorator('nasStartIp', {
                                rules: [
                                    {
                                        required: true,
                                        message: 'Please input your password!',
                                    },
                                    {
                                        validator: this.validateToNextPassword,
                                    },
                                ],
                            })(<Input />)}
                        </Form.Item>
                        <Form.Item label="Nas End IP" hasFeedback >
                            {getFieldDecorator('nasEndIp', {
                                rules: [
                                    {
                                        required: true,
                                        message: 'Please confirm your password!',
                                    },
                                    {
                                        validator: this.compareToFirstPassword,
                                    },
                                ],
                            })(<Input onBlur={this.handleConfirmBlur} />)}
                        </Form.Item>
                        <Form.Item
                            label={
                                <span>
                                    Shared Secret&nbsp;
                                </span>
                            }
                        >
                            {getFieldDecorator('shareSecurity', {
                                rules: [{ required: true, message: 'Please input your discription!', whitespace: true }],
                            })(<TextArea />)}
                        </Form.Item>
                        <Form.Item label="DM-Attribute" hasFeedback >
                            {getFieldDecorator('dmAttribute', {
                                rules: [
                                    {
                                        required: true,
                                        message: 'Please confirm your password!',
                                    },
                                    {
                                        validator: this.compareToFirstPassword,
                                    },
                                ],
                            })(<Select
                                mode="multiple"
                                placeholder="Please select"
                                defaultValue={[]}
                                onChange={this.handleChange}
                                style={{ width: '100%' }}
                            >
                                {children}
                            </Select>)}
                        </Form.Item>
                        <Form.Item label="COA-Attribute" hasFeedback >
                            {getFieldDecorator('coaAttribute', {
                                rules: [
                                    {
                                        required: true,
                                        message: 'Please confirm your password!',
                                    },
                                    {
                                        validator: this.compareToFirstPassword,
                                    },
                                ],
                            })(<Select
                                mode="multiple"
                                placeholder="Please select"
                                defaultValue={[]}
                                onChange={this.handleChange}
                                style={{ width: '100%' }}
                              >
                                {children}
                              </Select>)}
                        </Form.Item>
                    </Form>
                </CustomPanle>
            </div >
        );
    }

那我们在子组件中就可以通过this.props.panelConfig来获取对应的属性,然后绑定到Dom上:

return (
            <div style={{ width: "100%", height: this.state.height, border: "1px solid #ddd" }}>
                <div style={{ width: "100%", background: "#f5f5f5",lineHeight:"40px" }}>
                   <span style={{paddingLeft:"20px"}}>{this.props.panelConfig.title}</span> 
                </div>
                <div style={{ width: "100%", height: "90%", textAlign: "center"}}>
                    <div style={{ width: "100%", height: "90%", textAlign: "center", marginTop: "20px" }}>
                        {this.props.children}
                    </div>
                </div>
                <div style={{ width: "100%", height: "50px", background: "#f5f5f5" }}>
                    <div style={{ float: "right" , lineHeight: "50px"}}>
                        <span style={{ paddingRight: "10px" }}><Button type="primary" onClick={this.props.panelConfig.cancelFunction}>{this.props.panelConfig.cancel ? this.props.panelConfig.cancel : "Cancel"}</Button></span>
                        <span style={{ paddingRight: "10px" }}><Button type="primary" onClick={this.props.panelConfig.finishFunction}>{this.props.panelConfig.finish ? this.props.panelConfig.finish : "Save"}</Button></span>
                    </div>

                </div>
            </div>
        );

这样就可以达到不同组建中Panel共享的目的。

这里也可以扩展其他的属性,比如根据不同的需求调整panel的大小,可以传递一个size的属性,然后子组件根据size的值来设置Panel的大小。当然还有背景色。

看一下有没有执行父类的方法

首先在父组件中定义cancel和save的方法:

createNasClient = () => {
        console.log("创建----");
        // history.push("/index/policy-engine/nas-client")
    }
    returnList = () => {
        console.log("取消----");
        // history.push("/index/policy-engine/nas-client")
    }

点击save和cancel,查看依稀爱控制台:

说明已经成功触发了父组件的方法,那么当我们点击的时候就可以做一些操作。

看一下最终效果:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值