React中的模式对话框
对于React的模式对话框,有很多方法可以实现但是并没有一个绝对正确的方法。这句话怎么理解呢?让我们先看看一个模式对话框的特性:
模式对话框的实现思路下面的这些图片是常见模式对话框的例子: 这些模式对话框都有一个全局的背景遮罩层、有头部或描述内容、有一些功能按钮、可以随意设定的宽度和高度、位置居中。 在React中有三种方式实现模式对话框:
那这三种实现方式有什么问题呢: 第一种方式有定位问题。如果你用这种方式实现模式对话框,你的HTML上下文会影响当前模式对话框的展示效果,所以这种方式很有可能会出现一些意向不到的问题。你真的认为position: fixed可以让某个元素相对与浏览器窗口绝对定位吗?请看这个例子:https://output.jsbin.com/fepime/,使用开发人员工具看看 .top-div 和 .fixed-div 的样式你就懂了。 第二种方式首先对于单元测试不友好,因为我们不得不把对话框作为body的子元素(或者其他某个真实DOM的子元素)来显示,那么得有浏览器的真实DOM才能看到效果。而且这种方式看起来挺“骇客”的,我们按照单向数据流的思路开发了整套个标准合理的React组件,最后不得不用ReactDOM.unstable_renderSubtreeIntoContainer() 方法装载一个组件到body元素中,最终可能会导致虚拟DOM与真实DOM不一致或者服务端渲染遇到问题。‘unstable’前缀的含义是React官方明确告诉你:这玩意有坑,踩上了别怪我。详情请看React官方对unstable_renderSubtreeIntoContainer的说明。 第三种方式在笔者看来是最合理最优秀的,下面就谈谈这种实现方式的思路。 全局数据流控制模式对话框实际上就是用flux或redux的方式去控制对话框显示或关闭。如果之前用过flux之类思路的工具,后面的内容分分钟就理解了。 先看下模式对话框的组件结构:
在这些组件之外,还有store来存储全局模式对话框的相关数据。store.currentModal 用于指示显示哪个模式框的字符串,如果为 null 则表示没有任何模式框要显示,所以整个工程一次只显示一个模式框。 下面我们看看组件实现过程。 首先我们在任何位置都可以修改 store 。当我们通过某种方式将store.currentModal 的值修改为signIn 后,ModalConductor 会触发重新渲染并在内部判断要渲染SignIn 组件。 这是 ModalConductor的示意代码,通过switch语句判断要显示的组件: import React from 'react'; import ExportDataModal from './ExportDataModal.jsx'; import SignInModal from './SignInModal.jsx'; import FeedbackModal from './FeedbackModal.jsx'; import BoxDetailsModal from './BoxDetailsModal.jsx'; const ModalConductor = props => { switch (props.currentModal) { case 'EXPORT_DATA': return <ExportDataModal {...props}/>; case 'SOCIAL_SIGN_IN': return <SignInModal {...props}/>; case 'FEEDBACK': return <FeedbackModal {...props}/>; case 'EDIT_BOX': return <BoxDetailsModal {...props}/>; default: return null; } }; export default ModalConductor; 下面模式对话框组件的代码结构: import React from 'react'; import ModalWrapper from '../ModalWrapper.jsx'; const SignIn = props => { const signIn = provider => { props.hideModal(); props.signIn(provider); }; return ( <ModalWrapper {...props} title="Sign in" width={400} showOk={false} > <p>Choose your flavor</p> <button onClick={() => signIn('facebook')}>Facebook</button> <button onClick={() => signIn('google')}>Google</button> <button onClick={() => signIn('twitter')}>Twitter</button> </ModalWrapper> ); }; export default SignIn; 他内部使用了一个名为ModalWrapper 的包装组件,用来显示模式对话框的效果,可以直接使用https://github.com/reactjs/react-modal或者自己实现,如下是一个模式框的包装组件: import React from 'react'; const {PropTypes} = React; const ModalWrapper = props => { const handleBackgroundClick = e => { if (e.target === e.currentTarget) props.hideModal(); }; const onOk = () => { props.onOk(); props.hideModal(); }; const okButton = props.showOk ? ( <button onClick={onOk} disabled={props.okDisabled} > {props.okText} </button> ) : null; return ( <div onClick={handleBackgroundClick}> <header> <h1>{props.title}</h1> <button onClick={props.hideModal}>Close</button> </header> {props.children} {okButton} </div> ); }; ModalWrapper.defaultProps = { title: '',showOk: true,okText: 'OK',okDisabled: false,width: 400,onOk: () => {} }; export default ModalWrapper; (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |