弹窗在项目业务中很常见,接下来我们将基于antd的Modal组件实现2次封装。这个例子我们将实现一个选择城市的SelectCityDialog组件。效果图如下:
基本思路就是:
(1)弹窗组件的显示和隐藏由SelectCityDialog内部一个变量visable来控制,而这个值为true或者false则是由我们传入的值来控制。也就是说父组件传值给SelectCityDialog控制显示和隐藏
(2)由于我们要在外部(父组件)来打开这个弹窗,所以我们要在外部定义一个变量比如我们就叫vis,它每次值的变化则会传递给SelectCityDialog
(3)在SelectCityDialog内部,我们要点击取消或确定会关闭弹窗,而我们说过弹窗组件的显示和隐藏由SelectCityDialog内部一个变量visable来控制,而这个值为true或者false则是由我们传入的值来控制,而不是SelectCityDialog本身的visable来更改,所以关闭的时候我们需要让外部vis的值更改,进而引发SelectCityDialog传递过来的值发生更改。那怎么办呢?只能给组件传递一个函数,在关闭的时候让调用父组件的函数更改父组件内的vis的值更改,这样就能达到目的。
有点绕。但是只要我们理清楚这样一个关系就可以了。
(1)SelectCityDialog内部的visible===>控制SelectCityDialog显示、隐藏
(2)父组件的vis=====>传值给SelectCityDialog =====>引发visible变更
(3)SelectCityDialog关闭=======>调用父组件的函数====>设置父组件的vis为false,再次引发子组件的visible变更 接下来我们实现代码:
父组件,通过点击按钮打开弹窗
import SelectCityDialog from "../../components/SelectCityDialog/index"
import style from "./index.module.less"
function HouseStyle(props){
const [visiable,setVisiable]=useState(false)
const operDialogFunc=(flag)=>{
setVisiable(flag)
}
return(
<div>
<Button
size="large"
onClick={()=>operDialogFunc(true)}
icon={<IconFont type="icon-dingwei"
style={{fontSize:"18px",color:"#ff8c00"}} />}>
打开弹窗
</Button>
<SelectCityDialog
title="设置常用城市"
vis={visiable}
operDialogFunc={operDialogFunc}
>
</SelectCityDialog>
</div>
)
}
export default HouseStyle
接下来是selectCityDialog组件:
export default function SelectCityDialog(props){
let {title,operDialogFunc,vis}=props;
const [cityVisable,setCityVisable]=useState(false)
useEffect(()=>{
console.log("vis:",vis)
setCityVisable(vis)
},[vis])
return(
<Modal
title={title}
centered
visible={cityVisable}
onOk={() =>operDialogFunc(false)}
onCancel={() => operDialogFunc(false)}
width={1000}
>
<div className={style['cur-locate']}>
<div className={style['list-lf']}>当前定位</div>
<div className={style['list-rf']}></div>
</div>
<div className={style['recently-select']}>
<div className={style['list-lf']}>最近选择</div>
<div className={style['list-rf']}></div>
</div>
<div></div>
</Modal>
)
}
注意我们在useEffect里对传过来的变量vis进行了监听。这样每次vis改变,我们都重新对cityVisable进行重新赋值。
到此基本上实现了弹窗效果。
优化:
如果直接把该组件引入。这样父组件渲染完成的时候子组件已经先完成挂载。这样会导致一个问题:如果子组件中的数据有问题。这样父组件会直接报错挂掉。我们需要一种机制;在父组件渲染完成以后,子组件是完全不存在的。也就是子组件内的任何报错不会影响到父组件。所以我们需要让子组件最开始是完全销毁的。只有在点击打开的时候才让它真正渲染;实现方式也很简单:
visiable?
<SelectCityDialog
title="设置常用城市"
vis={visiable}
operDialogFunc={operDialogFunc} >
</SelectCityDialog>:null