最近正在开发自己开源的通用爬虫的前端界面,用的是ant-design-pro进行的二次开发,遇到的坑还是很多的,因此接下来分享的内容大多都是和ant-design有关的,经验都来自于自己的填坑之旅。本篇我们来讲讲怎么实现Modal组件的全屏功能。
我们希望实现一下功能
- 用户能够通过全屏控制图标进行全屏及非全屏操作
- 支持初始全屏弹窗,支持隐藏全屏控制图标
寻找图标嵌入点
按照惯例,全屏控制图标都是放置在弹窗的头部区域,靠近关闭按钮附近。在浏览过官方组件使用文档之后,大致发现有两个地方可以实现此功能。
- closeIcon
此属性可以实现自定义关闭图标,我们在此处可以插入两个图标,一个用于关闭,一个用来控制全屏操作,同时防止全屏操作触发关闭指令,我们应该在后者的点击事件中阻止事件的冒泡。 - title
此属性用来展示标题内容。我们注意到它不仅支持字符串,也支持ReactNode类型的数据,因此我们可以在此处实现自定义图标,并通过样式控制悬浮到头部右侧。
嵌入控制图标
此处我们选择title
属性来实现,通过增加一个中间层在用户传入的title
中添加一个全屏控制弹窗
const { title } = this.props;
return (
<>
{title}
<button
type="button"
className="ant-modal-close"
style={{ right: 42 }}
>
<span className="ant-modal-close-x">
<Icon className="ant-modal-close-icon" type="arrows-alt" />
</span>
</button>
</>
);
上述代码中的全屏控制按钮copy自弹窗中的关闭按钮,唯一的不同就是图标的位置及图标类型。我们将上述代码封装成一个函数,将其执行结果赋予modal
的title
属性。
实现效果如下:
实现全屏控制功能
上述我们提到要实现用户能够自由控制全屏及退出全屏的功能。因此我们定义一个名为fullScreen
的state
属性来控制当前的弹窗状态。
// 切换当前全屏状态
toggleFullScreen = () => {
const { fullScreen } = this.state;
this.setState({
fullScreen: !fullScreen,
});
};
titleRender = () => {
const { title } = this.props;
const { fullScreen } = this.state;
return (
<>
{title}
<button
type="button"
className="ant-modal-close"
style={{ right: 42 }}
onClick={this.toggleFullScreen}
>
<span className="ant-modal-close-x">
<Icon className="ant-modal-close-icon" type={fullScreen ? 'shrink' : 'arrows-alt'} />
</span>
</button>
</>
);
};
同时我们希望通过css来控制全屏的样式,因此我们需要通过上述fullScreen
来给予modal
不同的样式名。
const { fullScreen } = this.state;
render() {
<Modal
wrapClassName={`${fullScreen ? 'modal-wrap-fullscreen' : ''}`}
title={this.titleRender()}
{...rest}
/>
}
上述代码我们通过modal-wrap-fullscreen
来控制全屏的时候的样式,这边需要css控制的样式主要有:
- 控制
modal
高度为浏览器可视区域高度,这边可以通过100vh
来实现,宽度为100%
即可 - 控制
modal
的body
高度为浏览器可视区域高度 - 头部区域高度 - 底部区域高度。这边如果需要实现无底部区域等情况,还可以继续细分赋予Modal
不同的wrapClassName
来控制 - 可以将边角由圆角改成直角
其它控制参数
- 默认全屏功能
要实现默认全屏功能,那么用户得传入一个参数表明默认全屏。此处我们同样在props
增加一个参数名为fullScreen
的参数,并且state
中的初始值由props
中的参数决定即可。 - 隐藏控制图标
同样我们增加一个名为maxmin
的属性来控制
titleRender = () => {
const { title, maxmin } = this.props;
const { fullScreen } = this.state;
return (
<>
{title}
{maxmin && (
<button
type="button"
className="ant-modal-close"
style={{ right: 42 }}
onClick={this.toggleFullScreen}
>
<span className="ant-modal-close-x">
<Icon className="ant-modal-close-icon" type={fullScreen ? 'shrink' : 'arrows-alt'} />
</span>
</button>
)}
</>
);
};
结语
上述代码只是为了说明实现思路作为参考,可能并不完整。详细可以查看我托管的代码,当然我封装的代码中实现的功能会更多一点,具体可以看这。