React中的模式对话框

前端之家收集整理的这篇文章主要介绍了React中的模式对话框前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

对于React的模式对话框,有很多方法可以实现但是并没有一个绝对正确的方法。这句话怎么理解呢?让我们先看看一个模式对话框的特性:

  1. 能够浮现在最上层,阻止用户的其他操作。
  2. 能够处理鼠标和键盘事件,例如关闭窗口事件。
  3. 接受外部传入一个回调函数,当用户进行某些操作的时候调用他,例如点击“确定”或“取消”按钮。
  4. 接受外部参数,可以设定大小、文字、处理器等等。

模式对话框的实现思路

下面的这些图片是常见模式对话框的例子:

这些模式对话框都有一个全局的背景遮罩层、有头部或描述内容、有一些功能按钮、可以随意设定的宽度和高度、位置居中。

在React中有三种方式实现模式对话框:

  1. 使用一个常规的组件作为一个模式对话框的包装组件,然后将我们自定义内容作为子组件传递给模式对话框。例如这个项目:https://github.com/reactjs/react-modal
  2. 将模式对话框放置到HTML结构的顶层,将其设置为 document.body 的子元素。例如:https://github.com/tajo/react-portal
  3. 将模式对话框作为整个组件结构中的顶层组件(根元素的子组件),通过全局的数据来控制他显示或隐藏。

那这三种实现方式有什么问题呢:

第一种方式有定位问题。如果你用这种方式实现模式对话框,你的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之类思路的工具,后面的内容分分钟就理解了。

先看下模式对话框的组件结构:

  • App.jsx——整个工程的根组件,通常不会在这里有什么特殊的处理。它首先会渲染其他所有的顶层组件,然后再最后渲染模式对话框组件。
  • ModalConductor.jsx——模式框的管理组件,由他来控制当前应该渲染哪个模式框。
  • SignIn.jsx、EditScreen.jsx等组件——具体样式的模式对话框。

在这些组件之外,还有store来存储全局模式对话框的相关数据。store.currentModal 用于指示显示哪个模式框的字符串,如果为 null 则表示没有任何模式框要显示,所以整个工程一次只显示一个模式框。

下面我们看看组件实现过程。

首先我们在任何位置都可以修改 store 。当我们通过某种方式将store.currentModal 的值修改signIn 后,ModalConductor 会触发重新渲染并在内部判断要渲染SignIn 组件。

这是 ModalConductor的示意代码,通过switch语句判断要显示的组件:

  1. import React from 'react';
  2.  
  3. import ExportDataModal from './ExportDataModal.jsx';
  4. import SignInModal from './SignInModal.jsx';
  5. import FeedbackModal from './FeedbackModal.jsx';
  6. import BoxDetailsModal from './BoxDetailsModal.jsx';
  7.  
  8. const ModalConductor = props => {
  9. switch (props.currentModal) {
  10. case 'EXPORT_DATA':
  11. return <ExportDataModal {...props}/>;
  12.  
  13. case 'SOCIAL_SIGN_IN':
  14. return <SignInModal {...props}/>;
  15.  
  16. case 'FeedBACK':
  17. return <FeedbackModal {...props}/>;
  18.  
  19. case 'EDIT_Box':
  20. return <BoxDetailsModal {...props}/>;
  21.  
  22. default:
  23. return null;
  24. }
  25. };
  26.  
  27. export default ModalConductor;

下面模式对话框组件的代码结构:

  1. import React from 'react';
  2.  
  3. import ModalWrapper from '../ModalWrapper.jsx';
  4.  
  5. const SignIn = props => {
  6. const signIn = provider => {
  7. props.hideModal();
  8. props.signIn(provider);
  9. };
  10.  
  11. return (
  12. <ModalWrapper
  13. {...props}
  14. title="Sign in"
  15. width={400}
  16. showOk={false}
  17. >
  18. <p>Choose your flavor</p>
  19. <button onClick={() => signIn('facebook')}>Facebook</button>
  20. <button onClick={() => signIn('google')}>Google</button>
  21. <button onClick={() => signIn('twitter')}>Twitter</button>
  22. </ModalWrapper>
  23. );
  24. };
  25.  
  26. export default SignIn;

他内部使用了一个名为ModalWrapper 的包装组件,用来显示模式对话框的效果,可以直接使用https://github.com/reactjs/react-modal或者自己实现,如下是一个模式框的包装组件:

  1. import React from 'react';
  2. const {PropTypes} = React;
  3.  
  4. const ModalWrapper = props => {
  5. const handleBackgroundClick = e => {
  6. if (e.target === e.currentTarget) props.hideModal();
  7. };
  8.  
  9. const onOk = () => {
  10. props.onOk();
  11. props.hideModal();
  12. };
  13.  
  14. const okButton = props.showOk
  15. ? (
  16. <button
  17. onClick={onOk}
  18. disabled={props.okDisabled}
  19. >
  20. {props.okText}
  21. </button>
  22. ) : null;
  23.  
  24. return (
  25. <div onClick={handleBackgroundClick}>
  26. <header>
  27. <h1>{props.title}</h1>
  28.  
  29. <button onClick={props.hideModal}>Close</button>
  30. </header>
  31.  
  32. {props.children}
  33.  
  34. {okButton}
  35. </div>
  36. );
  37. };
  38.  
  39. ModalWrapper.defaultProps = {
  40. title: '',showOk: true,okText: 'OK',okDisabled: false,width: 400,onOk: () => {}
  41. };
  42.  
  43. export default ModalWrapper;

猜你在找的React相关文章