modal react 实现_react native modal 实现alert - CSDN
  • Modal 简述 模态对话框。需要用户处理事务,又不希望跳转页面以致打断...Modal 是组件库中开发的第一个组件, 做这个组件时的想法是先自实现后再和 Antd 做个对比,看看与大神的差距。 核心功能点提取 根据 Antd M...

    Modal 简述

    模态对话框。需要用户处理事务,又不希望跳转页面以致打断工作流程时,可以使用 Modal 在当前页面正中打开一个浮层,承载相应的操作。

    另外当需要一个简洁的确认框询问用户时,可以使用 Modal.confirm() 等语法糖方法。

    核心功能点提取

    根据 Antd Modal 文档提供的接口来实现 Modal.

    在这里插入图片描述

    核心实现

    Modal 组件的特殊在于它有两种用法:

    1. 通常用法:<Modal visible={this.state.visible} {...props}></Modal>
    2. 调用静态方法: Modal.confirm({ title: '取消后,已编辑的脚本信息将不会保存,请确认是否取消。', okText: '确认取消', cancelText: '暂不取消', onOk() { me.props.onCancel(); } })

    我的想法是这两种调用都在 internalModal.tsx 中统一维护

    在这里插入图片描述
    顺着这个思路, 对于 Modal.tsx
    1)不会维护 render 方法, 而是在 componentDidMount / componentDidUpdate 生命周期中调用 internalModal.tsx 完成渲染
    2)Modal.tsx 中维护相关静态方法 confirm, error, info 等。

    // Modal.tsx
    export default class Modal extends React.Component<ModalProps, {}> {
        static propTypes = {
    		...
        };
    
        static confirm(content) {
            const modal = new InternalModal();
            const props = {
                ...Modal.defaultProps,
                title: '提示',
                children: content,
                cancelButton: true,
                okButton: true,
                okButtonText: '确定',
                cancelButtonText: '取消',
                closable: false,
                visible: true,
                onOk() {
                    modal.destroy();
                },
                onCancel() {
                    modal.destroy();
                }
            };
            modal.render(props);
        }
    
        private modal;
        constructor(props: ModalProps) {
            super(props);
            this.modal = new InternalModal();
        }
    
        componentWillUnmount() {
            this.modal.destory();
            this.modal = null;
        }
    
        componentDidMount() {
            this.modal.render(this.props);
        }
    
        componentDidUpdate() {
            this.modal.render(this.props);
        }
    
        componentWillReceiveProps(nextProps) {
            if (nextProps.visible) {
                this.modal.show();
            } else {
                this.modal.hide();
            }
        }
    
        render() {
            return null;
        }
    }
    

    接下来就是最关键的 internalModal.tsx :

    export default class InternalModal {
    
        private props;
    
        render(props) {
            const {...} = this.props;
    
            this.createContainer();
            const icon = require('../../assets/icon/info.svg') as string;
    
            const modalDOM = ...;
    
            ReactDOM.render({modalDOM}, modalContainer,
    	        () => {
    	            if (visible) {
    	                this.show();
    	            }
    	        });
        }
    
    	...
    
        createContainer() {
            if (!modalContainer) {
                modalContainer = document.createElement('div');
                document.body.appendChild(modalContainer);
            }
        }
    
        destroy() {
            if (modalContainer) {
                ReactDOM.unmountComponentAtNode(modalContainer);
            }
        }
    
        show() {
            if (modalContainer) {
                modalContainer.style.display = 'block';
            }
        }
    
        hide() {
            if (modalContainer) {
                modalContainer.style.display = 'none';
            }
        }
    }
    

    从代码可以发现 internalModal 的实现要点:

    1. 作为一个普通 js 类 (并没有继承 React.Component) ,提供一个 render 方法,render 中通过 ReactDOM.render(element, container[, callback]) 渲染弹出窗口

    2. 在 document 上创建一个 div container 乘放 Modal,通过 css display 控制显示/隐藏,其实也可以使用 React Portal.

    3. 可以用一些第三方库比如react-transition-group 来增强 Modal 显示/隐藏的动画效果。

    更多组件

    更多组件自实现系列,更多文章请参考:

    从Antd 源码到自我实现之 Form表单

    从Antd 源码到自我实现之 Grid 栅格系统

    从Antd 源码到自我实现之 Menu 导航菜单

    展开全文
  • 身为一个程序员,尤其是前端工程师不得不面向产品编程,由于原型图上满满的弹窗,逼迫我们不得不封装一个弹窗组件来应付产品的需求二、需要实现Modal组件的API1、通过传入一个visible来控制弹框的显示与隐藏,数据...

    一、背景

    众所周知,产品经理有三宝:弹窗、浮层和引导。身为一个程序员,尤其是前端工程师不得不面向产品编程,由于原型图上满满的弹窗,逼迫我们不得不封装一个弹窗组件来应付产品的需求

    二、需要实现的Modal组件的API

    1、通过传入一个visible来控制弹框的显示与隐藏,数据类型为boolean
    2、通过传入一个title来设置弹框的标题,数据类型为string
    3、通过传入一个onOk函数来设置弹框确认按钮的操作,数据类型为function
    4、通过传入一个onCancel函数来设置弹框关闭取消按钮的操作,数据类型为function
    5、通过传入一个children来设置弹框主体内容,数据类型为element

    三、Modal组件具体代码实现

    import React, { Component } from 'react'
    import Button from '../Button/Button'
    import PropTypes from 'prop-types'
    import './GYModal.less'
    export default class GYModal extends Component {
      static propTypes = {
        visible: PropTypes.bool,
        title: PropTypes.string,
        onOk: PropTypes.func,
        onCancel: PropTypes.func,
        children: PropTypes.element
      }
      static defaultProps = {
        visible: false,
        title: '标题',
        onOk: () => {},
        onCancel: () => {}
      }
      render () {
        const {
           visible,
           title,
           children,
           onOk,
           onCancel
        } = this.props,
        show = { zIndex: 2000, opacity: 1 },
        hide = { zIndex: -1, opacity: 0 },
        contShow = { width: '600px', height: '600px' },
        contHide = { width: '0px', height: '0px' }
        return (
          <div className="gy-modalContainer" style={ visible ? show : hide }>
            <div className="mask" onClick={onCancel}></div>
            <div className="innerContent" style={ visible ? contShow : contHide }>
              <div className="innerContent-header">
                <div className="innerContent-title">{title}</div>
              </div>
              <div className="innerContent-center">
                {children}
              </div>
              <div className="innerContent-footer">
                <Button type='cancel' onClick={onCancel}>取消</Button>
                <Button type='primary' onClick={onOk}>确定</Button>
              </div>
            </div>
          </div>
        )
      }}复制代码

    注意:这里在打开和关闭弹框时,增加了css3动画过滤效果。一开始为了实现动画过渡效果,我首先想到的是通过改变display: none到display: block,并且设置transition: all .3s ease来实现过滤动画效果,后来发现根本没有效果,原因是transition是不支持display属性的过渡的,当然你可以通过js的settimeout来实现,这边就直接用css3来实现动画过渡效果了。Modal组件最外层容器通过改变z-index和opacity来实现过渡动画效果,而Modal组件的弹框内容部分主要是通过改变弹框的width和height来实现过渡动画效果的,这两个部分的动画效果都是由visible来控制的。

    .gy-modalContainer{
      position: fixed;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      opacity: 1;
      transition: all .3s cubic-bezier(.075, .82, .165, 1);
      z-index: -1;
      .mask{
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        z-index: 2;
        background-color: rgba(0,0,0,.3);
      }
      .innerContent{
        position: absolute;
        left: 50%;
        top: 50%;
        width: 600px;
        height: 600px;
        height: auto;
        z-index: 3;
        background-color: #FFFFFF;
        transition: all .3s cubic-bezier(.075, .82, .165, 1);
        transform-origin: 75.5px 221.5px 0px;
        transform: translate(-50%,-50%);
        border-radius: 4px;
        .innerContent-header{
          padding: 13px 16px;
          border-radius: 4px 4px 0 0;
          background: #fff;
          color: rgba(0,0,0,.65);
          border-bottom: 1px solid #e9e9e9;
          .innerContent-title{
            margin: 0;
            font-size: 14px;
            line-height: 21px;
            font-weight: 500;
            color: rgba(0,0,0,.85);
          }
        }
        .innerContent-center{
          padding: 16px;
          font-size: 12px;
          line-height: 1.5;
        }
        .innerContent-footer{
          border-top: 1px solid #e9e9e9;
          padding: 10px 16px 10px 10px;
          border-radius: 0 0 4px 4px;
          display: flex;
          align-items: center;
          justify-content: flex-end;
        }
      }}复制代码


    四、使用Modal组件

    以下是render函数中的代码


    以下是展示效果




    展开全文
  • 注:本文Demo环境使用的是我平时开发用的配置:这里是地址...了解React。 使用过webpack3。 熟悉es6语法。 项目说明项目结构截图项目运行说明 npm install npm run start npm run startfe 登录localhost:8088查看de

    代码地址如下:
    http://www.demodashi.com/demo/12315.html

    注:本文Demo环境使用的是我平时开发用的配置:这里是地址

    本文适合对象

    1. 了解React。
    2. 使用过webpack3。
    3. 熟悉es6语法。

    项目说明

    项目结构截图

    项目运行说明

    1. npm install
    2. npm run start
    3. npm run startfe
    4. 登录localhost:8088查看demo

    Modal组件分析

    Modal组件是属于一个网站中比较常用的基础组件,但是在实现方面上稍微复杂一些,对场景支持的需求度较高。

    这里是Antd中Modal组件的演示Demo

    首先分析这个组件的组成结构:
    1. title Modal弹层的标题部分。
    2. content Modal弹层的主体部分。
    3. footer Modal弹层最后的button部分。
    4. background 整个黑色背景

    其次,这个弹层不能生硬的出现,所以一定要有动画效果。

    最后,弹层是在合适的地方通过用户交互的形式出现的,所以又一个控制器来控制Modal弹层的出现和关闭。

    Modal组件的实现

    静态组件

    首先来思考如何实现静态组件部分的代码。

    先在components下面创建我们的modal组件结构。
    - -components/
    - -modal/
    - -modal.js
    - -modal.scss

    这里样式文件使用scss,如果不熟悉的同学可以使用css代替或者先学习一下scss语法规则。

    modal.js中创建出组件的基础部分。

    import React, { Component } from 'react';
    import PropTypes from 'prop-types';
    import './modal.scss';
    
    export default class Modal extends Component {
        constructor(props) {
            super(props);
        }
        render() {
            return (
                <div>Modal</div>
            );
        }
    }
    
    Modal.propTypes = {};
    Modal.defaultProps = {};
    

    接下来分析我们的组件都需要预留哪些接口:
    1. 开关状态isOpen
    2. Modal标题title
    3. Modal主体内容children
    4. Modal类名className
    5. 点击黑色区域是否可以关闭maskClosable
    6. 关闭按钮文案 cancelText
    7. 确认按钮文案 okText
    8. 关闭按钮回调函数 onCancel
    9. 确认按钮回调函数 onOk

    目前能想到的接口有这些,接下来我们可以补充一下我们的代码。

    // 刚才的代码部分
    Modal.propTypes = {
        isOpen: PropTypes.bool.isRequired,
        title: PropTypes.string.isRequired,
        children: PropTypes.oneOfType([PropTypes.element, PropTypes.string]).isRequired,
        className: PropTypes.string,
        maskClosable: PropTypes.bool,
        onCancel: PropTypes.func,
        onOk: PropTypes.func,
        okText: PropTypes.string,
        cancelText: PropTypes.string
    };
    
    Modal.defaultProps = {
        className: '',
        maskClosable: true,
        onCancel: () => {},
        onOk: () => {},
        okText: 'OK',
        cancelText: 'Cancel'
    };
    

    定义好接口之后,我们可以根据我们的接口来完善一下Modal组件。

    export default class Modal extends Component {
        constructor(props) {
            super(props);
            this.state = {
                isOpen: props.isOpen || false
            };
        }
        componentWillReceiveProps(nextProps) {
            if('isOpen' in nextProps) {
              this.setState({
                isOpen: nextProps.isOpen
              });
            }
      }
        render() {
            const {
                title,
                children,
                className,
                okText,
                cancelText,
                onOk,
                onCancel,
                maskClosable
            } = this.props;
            return (
                <div className={`mocal-container ${className}`}>
                    <div className="modal-body">
                        <div className={`modal-title ${type}`}>{title}</div>
                    <div className="modal-content">{children}</div>
                    <div className="modal-footer">
                        <button className="ok-btn" onClick={onOk}>{okText}</button>
                        <button className="cancel-btn" onClick={onCancel}>{cancelText}</button>
                    </div>
                    </div>
                </div>
            );
        }
    }

    接下来是Modal组件的样式:

    .modal-container {
        background-color: rgba(33, 33, 33, .4);
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        bottom: 0;
        opacity: 1;
        .modal-body {
            background-color: #fff;
            border-radius: 5px;
            padding: 30px;
            width: 400px;
            position: absolute;
            left: 50%;
            top: 40%;
            transform: translate3d(-50%, -50%, 0);
            .modal-title {
                text-align: center;
                font-size: 18px;
                font-weight: bold;
            }
            .modal-content {
                min-height: 100px;
            }
            .modal-footer {
                text-align: center;
                button {
                    margin: 0 20px;
                    padding: 8px 27px;
                    font-size: 16px;
                    border-radius: 2px;
                    background-color: #ffd900;
                    border: 0;
                    outline: none;
                    &:hover {
                        cursor: pointer;
                        background-color: #fff000;
                    }
                }
            }
        }
    }

    基础部分写完之后,我们可以来验证一下自己的组件是否能够正常运行了。

    我们在直接在containers里面的hello里面引入Modal测试即可:

    import React, { Component } from 'react';
    import Modal from 'components/modal';
    
    export default class Hello extends Component {
        render() {
            return (
                <Modal
                    title="Demo"
                    okText="确认"
                    cancelText="取消"
                >
                    <div>Hello world!</div>
                </Modal>
            );
        }
    }

    node启动开发机,登录到localhost:8088,可以看到我们的组件运行良好:

    但是似乎还是有一点瑕疵,我们的Modal不可能只有一个状态,因此我们需要一个type接口,来控制我们显示哪一种Modal,比如success、error等。

    继续改造Modal.js

    Modal.PropTypes = {
        // ...
        type: PropTypes.oneOf(['alert', 'confirm', 'error'])
    };
    Modal.defaultProps = {
        // ...
        type: 'alert',
    };

    我们在scss中稍微改变一点样式,能让我们分辨出来。
    基本上都是使用特定的icon图片来作区分,这里为了简化代码量,直接使用emoji字符来代替了。

    .modal-title {
        // ...
        &.error:before {
                content: '❌';
                display: inline-block;
          }
          &.success:before {
                content: '✔';
                color: rgb(75, 231, 14);
                display: inline-block;
          }
          &.confirm:before {
                content: '❓';
                display: inline-block;
          }
          &.alert:before {
                content: '❕';
                display: inline-block;
          }
    }

    现在在看我们的组件,可以看到已经有区分度了:

    正常情况下,我们会继续细分很多东西,比如什么情况下不显示按钮组,什么情况下只显示确认按钮等。这里就不进行细分工作了。

    挂载方法

    Modal组件的骨架搭好之后,我们可以开始考虑组件需要的方法了。

    首先组件是要可以关闭的,并且我们无论点击确认或者取消或者黑色弹层都要可以关闭组件。

    而且当我们组件打开的时候,需要给body加上类名,方便我们之后的一切操作。

    
    const modalOpenClass = 'modal-open';
    
    const toggleBodyClass = isOpen => {
        const body = document.body;
        if(isOpen) {
            body.classList.add(modalOpenClass);
        } else {
            body.classList.remove(modalOpenClass);
        }
    }
    
    export default class Modal extends Component {
        /// ...
        constructor(props) {
            // ...
            toggleBodyClass(props.isOpen);
        }
        // 关闭弹层函数
        close() {
            this.setState() {
                isOpen: false
            };
            toggleBodyClass(false);
        }
        // 点击确认回调函数
        onOkClick() {
            this.props.onOk();
            this.close();
        }
        // 点击取消的回调函数
        onCancelClick() {
            this.props.onCancel();
            this.close();
        }
        // ...
    }

    这些函数因为都要绑定到dom节点上,因此要提前绑定this,因此我们可以写一个工具函数,创建一个lib文件夹,在lib下创建一个util.js文件。

    // lib/util
    export default {
        bindMethods(methods, obj) {
            methods.forEach(func => {
                if(typeof func === 'function') {
                    obj[func] = obj[func].bind(this);
                }
            })
        }
    }

    然后在我们的Modal组件中引入util文件,绑定函数的this。

    // Modal.js
    import util from 'lib/util';
    
    // ...
    constructor(props) {
        // ...
        util.bindMethods(['onCancelClick', 'onOkClick', 'close'], this);
    }
    // ...

    然后我们就可以将刚才的点击函数都替换掉:

    render() {
        // ...
        return (
                <div className={`mocal-container ${className}`} onClick={maskClosable ? this.close : () => {}}>
                    <div className="modal-body">
                        <div className={`modal-title ${type}`}>{title}</div>
                    <div className="modal-content">{children}</div>
                    <div className="modal-footer">
                        <button className="ok-btn" onClick={this.onOkClick}>{okText}</button>
                        <button className="cancel-btn" onClick={this.onCancelClick}>{cancelText}</button>
                    </div>
                    </div>
                </div>
            );
    }

    去实验一下代码,发现确实可以关闭了。

    控制器

    Modal组件主体部分写完之后,我们还要考虑考虑实际业务场景。

    我们都知道React是一个组件化的框架,我们写好这个Modal组件后,不可能是将这个组件嵌套在其他组件内部使用的,而是要直接在body下面占满全屏显示,所以写到这里为止是肯定不够的。

    并且在网站中,一般都是有一个按钮,当用户点击之后,才弹出Modal提示用户。

    因此,我们现在这种通过组件调用的方式是肯定不行的,因此还要对这个Modal组件进行封装。

    modal目录下创建一个index.js文件,代表我们整个Modal组件的入口文件。

    然后在index.js中书写我们的主要控制器代码:

    // index.js
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import Modal from './modal';
    
    const show = (props) => {
        let component = null;
        const div = document.createElement('div');
        document.body.appendChild(div);
    
        const onClose = () => {
            ReactDOM.unmountComponentAtNode(div);
            document.body.removeChild(div);
    
            if(typeof props.onClose === 'function') {
                props.onClose();
            }
        }
    
        ReactDOM.render(
            <Modal
                {...props}
                onClose={onClose}
                ref={c => component = c}
                isOpen
            >{props.content}</Modal>,
            div
        );
        return () => component.close();
    }
    
    const ModalBox = {};
    ModalBox.confirm = (props) => show({
        ...props,
        type: 'confirm'
    });
    
    ModalBox.alert = (props) => show({
        ...props,
        type: 'alert'
    });
    
    ModalBox.error = (props) => show({
        ...props,
        type: 'error'
    });
    
    ModalBox.success = (props) => show({
        ...props,
        type: 'success'
    });
    
    export default ModalBox;
    

    这段控制器的代码比较简单。

    show函数用来控制Modal组件的显示,当show之后,在body下面创建一个div,然后将Modal组件熏染到这个div下面,并且在删除的时候一起将div和Modal组件都删除掉。

    ModalBox就负责我们平时动态调用,根据我们传入不同的type值而显示不同type的Modal组件。

    现在我们可以去改造一下container的入口文件了:

    // hello.js
    
    import React, { Component } from 'react';
    import Modal from 'components/modal';
    
    export default class Hello extends Component {
        render() {
            return (
                <div>
                <button onClick={() => Modal.confirm({
                    title: 'Demo',
                    content: 'Hello world!',
                    okText: '确认',
                    cancelText: '取消',
                    onOk: () => console.log('ok'),
                    onCancel: () => console.log('cancel')
                })}>click me!</button>
            </div>
            );
        }
    }

    到此为止,我们点击click me的按钮之后,可以正常显示和关闭Modal组件了,并且点击确认和取消按钮的时候,都会调用相对应的回调函数来显示'ok' 'cancel'字样。

    动画效果

    生硬的Modal组件自然不是我们最终追求的效果,所以我们还要加上最后一个部分:动画效果。

    React实现动画的方式有很多,但是总结起来可能只有两种:
    1. 使用css3实现动画。
    2. 根据react的状态管理利用js实现动画。

    在复杂动画的情况下,一般选择第二种,因此我这里也是使用第三方react动画库来实现Modal的动画效果。

    考虑到动画结束,删除组件之后还应该有一个回调函数,因此这里采用的是react-motion动画库,而不是常见的CSSTransitionGroup动画库。

    在增加动画效果之前,我们要增加一个刚才提到的动画结束之后的回调函数,因此还需要增加一个接口。

    onRest: PropTypes.func

    并且将这个接口的默认值改为空函数:

    onRest: () => {}

    这里就不介绍具体的react-motion的使用方法了,直接展示最终的代码:

    import { Motion, spring, presets } from 'react-motion';
    
    export default class Modal extends Component {
        constructor(props) {
            // ...
            util.bindMethods(['onCancelClick', 'onOkClick', 'close', 'onRest'], this);
        }
        // ...
        // 动画结束之后的回调函数
        onRest() {
            const { isOpen } = this.state;
            if(!isOpen) {
                this.props.onClose();
            }
            this.props.onRest();
      }
      render() {
        // ...
        return (
            <Motion
                defaultStyle={{
                    opacity: 0.8,
                    scale: 0.8
                }}
                style={{
                    opacity: spring(isOpen ? 1 : 0, presets.stiff),
                    scale: spring(isOpen ? 1 : 0.8, presets.stiff)
                }}
                onRest={this.onRest}
            >
                {
                     ({
                        opacity,
                        scale
                    }) => (
                        <div
                            className={`modal-container ${className}`}
                            style={{opacity}}
                            onClick={maskClosable ? this.close : () => {}}
                        >
                            <div
                                className="modal-body"
                                style={{
                                    opacity,
                                    transform: `translate3d(-50%, -50%, 0) scale(${scale})`
                                }}
                            >
                                <div className={`modal-title ${type}`}>{title}</div>
                                <div className="modal-content">{children}</div>
                                <div className="modal-footer">
                                    <button className="ok-btn" onClick={this.onOkClick}>{okText}</button>
                                    <button className="cancel-btn" onClick={this.onCancelClick}>{cancelText}</button>
                                </div>
                            </div>
                            </div>
                        )
                    }
                </Motion>
            );
        }
    }

    到此为止,整个Modal组件就已经完成了,希望这份demo对学习react的同学有所帮助。

    结语

    在设计基础组件的时候,一定要尽可能多的考虑业务场景,然后根据业务场景去设计接口,尽量保证基础组件能够在所有的场景中都可以正常使用。

    这份Demo是在React15.6.0版本下书写的,因为React已经升级到16版本,并且16增加了新的createPortal()方法,所以Modal组件的实现方式会有所变化,具体的实现方法在下一篇文章介绍。React15.6.0实现Modal弹层组件

    代码地址如下:
    http://www.demodashi.com/demo/12315.html

    注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

    展开全文
  • React Modal 的一种粗暴实现modal什么的很好做不就是个bool吗,要么显示要么隐藏。一开始这个modal很简单,const modal =(isShow)=><div style={{display:isShow?"block":"none"}}>Balbala但是这个样子的modal很突兀...

    React Modal 的一种粗暴实现

    modal什么的很好做不就是个bool吗,要么显示要么隐藏。

    一开始这个modal很简单,

    const modal =(isShow)=><div style={{display:isShow?"block":"none"}}>Balbala</div>

    但是这个样子的modal很突兀,很粗暴,连你自己也忍不住想加一个fade动画的吧。

    在jquery里面那是相当好用,一个接口就搞定了。

    fade-out;fade-in用css实现,很常规。

    在react里面怎么实现呢。

    本文来讲一讲对于modal 的一种粗暴的解决方案,带fadeIn fadeOut动画解决方案。

    @-webkit-keyframes fadeIn {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
    @keyframes fadeIn {
      from {
        opacity: 0;
      }
      to {
        opacity: 1;
      }
    }
    .fade-in {
      -webkit-animation: fadeIn ease .3s forwards;
              animation: fadeIn ease .3s forwards;
    }
    @-webkit-keyframes fadeOut {
      from {
        opacity: 1;
      }
      to {
        opacity: 0;
      }
    }
    @keyframes fadeOut {
      from {
        opacity: 1;
      }
      to {
        opacity: 0;
      }
    }
    .fade-out {
      -webkit-animation: fadeOut ease .3s forwards;
              animation: fadeOut ease .3s forwards;
    }
    .modal.fade-out{
        pointer-events: none;
    }

    在使用react的时候将你的modal放在父级组件的时候:

    1. 通过props提供接口访问。至少需要两个接口,一个bool变量用来控制是否显示,一个关闭的回调函数用来改变它的状态:bool isVisible,void onClose()

    2. 除了通过接口的方法控制以外,还可以使用ref。 在modal内部实现显示隐藏的逻辑。然后ref到组件实例,至少需要两个接口void show();void hide(),然而这种方式实现起来的缺陷就是,每次使用的时候得先ref到组件的实例;这种写法自身需要维护自己的显示隐藏状态。

    在生命周期 componentWillMount时判断初始状态是否为显示。如果初始状态为不显示,则延迟挂载,防止fadeIn动画闪烁的副作用。

    如果一开始modal就是不可见状态的话,modal在挂载的时候会fadeOut一下,那么你就会看见在视图上你的弹窗突然一下消失。实际上,我们并不想让它发生消失这件事。因为一开始的时候他是藏起来的就可以了。然而fadeoout这类的动画它是把opacity从1变到0;

    所以我们不得不需要一个状态 hide 在一开始的时候将自己设置为hide,在props发生改变的时候对modal的显示和隐藏状态作出改变。并且至此以后再也不需要这个hide了。因为model已经进入了。

    将真实render在componentWillReceiveProps中判断好逻辑后再显示出来。

    class Modal extends Component {
        constructor(props){
            super(props);
            this.isFixed = false;
        }
    
        componentWillMount(){
            console.log(this.props);
            /*
             * 初始状态为false的情况下,默认不可见;
             * 为防止fadeOut触发,做以下操作。
             * */
            if( this.props.visible ){
                this.isFixed = true;
                this.render    = this.renderCurrent;
            }
        }
    
        componentWillReceiveProps(np){
            /*
            * magic
            */
            if( this.props.visible !== np.visible ){
                if( !this.isFixed ){
                    this.render    = this.renderCurrent;
                    this.isFixed = true;
                }
            }
        }
    
        renderCurrent(){
            const { visible,onClose } = this.props;
            return <div onClick={onClose}
                        className={visible ? "modal fade-in" : "modal fade-out"}>
                <div className="content">
                    <div>BALABALABLA</div>
                </div>
            </div>
        }
        render(){
            return <div/>
        }
    }

    在组件的上下文通过成员变量isFixed 来判断是不是已经完成了我们的modal fix行为。

    因为js的灵活性,这样实现起来是没有问题的,对于性能来说,也没有问题。

    如果你要快速实现一个modal,并要求能够有fadeIn,fadeOut 这种过度下过的话。
    这个是来的最简单的方式了。

    在antd中,实现modal通过在React的RootNode createClass完成。
    当第一次render的时候,如果你的modal是不显示的话,它在Dom里面其实就是个


    当props发生有关isVisible的变化的时候,才真正的渲染了modal的dom结构。isVisible再次变化为false的时候,dom结构还是modal的dom结构,改变的只是一个fade类名。

    如果不使用第三方框架。强烈建议这种野路子的写法。

    当然,你还需要一个wrap层,弄成fixed的,然后你的modal窗体应该是absolute的,通过margin调整位置。给你的wrap在设置一个rgba的浅黑色背景,然后再在wrap上增加点击效果,使它可以点击遮罩关闭。

    当然这个时候你又遇到了另一个新问题

    因为事件传递,你又到modal的事件handle里加上了preventDefault。

    到此 基本上实现了一个可以用的modal 了。

    另外的,给这个modal增加一些新的props,像增加一些诸如 title啊content啊 contentGetter啊这种东西,哇晒可以复用了。

    当然,fadeout之外也可以使用slide,flip, scale,boom等。

    那么如何实现 在函数内部调用一个方法来显示一个modal呢。

    比如:

    handleBtnClick(){
        modal.info("hello");
        modal.confirm({
            title:"dasd",
            content:"dasdas",
            onOk(){},
            onCancel(){}
        })
        modal.modal(reactElement)
        modal.warning({
        })
    }

    这种写法也是很风骚,那么怎么实现呢。下次再说啊。

    展开全文
  • react native 原生modal默认不能覆盖Android的statusbar.这对于一个强迫症患者来说真是难受。一开始尝试将statabar透明但还是不能绘制到statusbar。最后无奈之下只好参考react native的modal去自己写一个啦。 参考...

    react native 原生modal默认不能覆盖Android的statusbar.这对于一个强迫症患者来说真是难受。一开始尝试将statabar透明但还是不能绘制到statusbar。最后无奈之下只好参考react native的modal去自己写一个啦。
    参考modal目录:node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/modal/
    3DCF58A7-5C63-45B3-927B-F60E890DA8FF.png
    打开ReactModalHostManager 可以看到
    public class ReactModalHostManager extends ViewGroupManager<ReactModalHostView>
    ReactModalHostManager封装的是ReactModalHostView这个ViewGroup.
    于是打开ReactModalHostView这个View找到关键代码

      protected void showOrUpdate() {
        // If the existing Dialog is currently up, we may need to redraw it or we may be able to update
        // the property without having to recreate the dialog
        if (mDialog != null) {
          if (mPropertyRequiresNewDialog) {
            dismiss();
          } else {
            updateProperties();
            return;
          }
        }
    
        // Reset the flag since we are going to create a new dialog
        mPropertyRequiresNewDialog = false;
        int theme = R.style.Theme_FullScreenDialog;
        if (mAnimationType.equals("fade")) {
          theme = R.style.Theme_FullScreenDialogAnimatedFade;
        } else if (mAnimationType.equals("slide")) {
          theme = R.style.Theme_FullScreenDialogAnimatedSlide;
        }
        Activity currentActivity = getCurrentActivity();
        Context context = currentActivity == null ? getContext() : currentActivity;
        mDialog = new Dialog(context, theme);
        mDialog.setContentView(getContentView());
        updateProperties();
    
        mDialog.setOnShowListener(mOnShowListener);
        mDialog.setOnKeyListener(
          new DialogInterface.OnKeyListener() {
            @Override
            public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
              if (event.getAction() == KeyEvent.ACTION_UP) {
                // We need to stop the BACK button from closing the dialog by default so we capture that
                // event and instead inform JS so that it can make the decision as to whether or not to
                // allow the back button to close the dialog.  If it chooses to, it can just set visible
                // to false on the Modal and the Modal will go away
                if (keyCode == KeyEvent.KEYCODE_BACK) {
                  Assertions.assertNotNull(
                    mOnRequestCloseListener,
                    "setOnRequestCloseListener must be called by the manager");
                  mOnRequestCloseListener.onRequestClose(dialog);
                  return true;
                } else {
                  // We redirect the rest of the key events to the current activity, since the activity
                  // expects to receive those events and react to them, ie. in the case of the dev menu
                  Activity currentActivity = getCurrentActivity();
                  if (currentActivity != null) {
                    return currentActivity.onKeyUp(keyCode, event);
                  }
                }
              }
              return false;
            }
          });
    
        mDialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
        if (mHardwareAccelerated) {
          mDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
        }
    
        if (currentActivity == null || !currentActivity.isFinishing()) {
          mDialog.show();
        }
      }

    可以看到modal其内部也封装的Dialog,那么我们只需要将dialog替换为popwindow是不是也可以做到呢?
    于是开始写代码。经过一番bug调试完成。效果如下:
    modalAndroid.gif
    注意:
    1:popupWindow.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));//不设置 不是全屏 周围会有空白部分
    popupWindow一定要设置背景否则周围会显示一点空隙。

    完整代码:https://github.com/wuyunqiang/AndroidToRN

    展开全文
  • 效果展示 测试组件 class Test extends Component { constructor(props) { super(props) this.state = { modalVisible: false } } render() { return ( ...
  • 这是react-modal官网的配置参数。 模态框的手动实现,并不算太难,这个组件用着还不错。 2,配置参数介绍 import React, { Component } from 'react'; import Modal from 'react-modal' import './App.css'; ...
  • React-Native中Modal的使用 /** * React Native App * dongtao 2017/04/22 * @flow */ import React, { Component } from 'react';import { AppRegistry, StyleSheet, Text, Modal, PixelRatio, View} from 'rea...
  • Modal 是可以覆盖在原生视图上。 属性: animationType:显示和隐藏的动画 slide:从底部弹出 fade:渐隐渐显 none:无 onRequestClose:android 按返回键时回调。 onShow:modal显示时回调。 ...
  • 我们在React Native很容易实现但是我们要进行分装成我们自己经常使用的。那么如下: 其中要注意的地方有几个 地区 1:这个位子是设置成位于使得背景颜色是透明。如果你想使用其他的方式:加一个《View》这种方式,...
  • React-Modal实现弹窗加载PDF并提供打印功能的组件 需求很简单,需要一个窗口展示不同的PDF,并提供打印功能。使用React+Ant Design实现此功能。 刚开始想的有点复杂,研究了一天的和React相关的各种开源组件,期望...
  • DialogModal.js /** * Created by zhoujian on 2019/4/9. */ import React, {Component} from 'react'; import { StyleSheet, Text, ... Modal, TouchableOpacity } from 'react-native...
  • React Native(RN)给我们提供了有Alert,但使用局限性很大,没有办法自定义,要实现自定义的弹框,我们应该如何来实现呢,这里提供两种方法:第一就是native本地来实现,然后暴露给RN来条用,第二就是使用组件Modal...
  • 今天迭代版本围绕这个Modal遇到了一些问题,可是一个用法简单到不能再简单的Modal组件会有什么问题呢? 是,错误的产生没有任何报错,连警告都没有,无从查起,就是导航出现了问题,卡死在当前界面,杀死程序之后...
  • 主流modal大多需要在组件内使用state控制是否显示,在多个地方调用的时候很不方便,所以基于 context 提供一个更加易用的调用方式。 use-modal 支持主流的modal, 理论上只要modal通过类似于 show props 控制显示的,...
  • 一、简单版,入门 1.学习网址:... 2.新建一个test.js npm install @material-ui/core --save 然后将如下代码复制到test.js上 ...import React, { Component } from 'react'; import CircularProgress f...
  • 原生有Dialog,Toast之类的弹窗控件,React-Native虽然也有Dialog,但是并不好用,所幸有Modal这个组件,使用起来简单,而且还比较好用。 之前一直有知道这个控件,但因为没有需要用到所以没有看过如何使用,今天...
  • React Hooks: use modal

    2019-09-30 15:19:00
    useModal: ...export const useModal = (initTitle: string, initContent: string | React.ReactElement) => { const [visible, setVisible] = useState(false); const [title, setTitle] = useSt...
  • 使用时注意,可以把Modal看成一个仅提供功能的外壳,它不包含任何样式,只负责显示/隐藏和动画效果实现Modal的子组件通常为一个View容器,在该View容器实现渲染界面和样式相关。在很多APP应用模态框的时候,出于...
1 2 3 4 5 ... 20
收藏数 4,018
精华内容 1,607
关键字:

modal react 实现