javascript - ReactJs 中可重用的模态

标签 javascript reactjs modal-dialog

我正在尝试创建一个服务,该服务将显示确认对话框并捕获用户的操作(确认/取消),并且可以在任何组件中以较少的尝试重复使用。

到目前为止我尝试过的(使用 React gateway 注入(inject)我的对话框)

我创建了一个类似的服务:

var createConfirm = function(options, onConfirm, onCancel) {
  options = options || {};
  var actions = [
    <FlatButton
      label="Cancel"
      primary={true}
      onClick={onCancel}
    />,
    <RaisedButton
      label="OK"
      primary={true}
      onClick={onConfirm}
    />,
  ];
  return (
    <Gateway into="confirm-modal">
      <Dialog
        title={options.title || 'Confirmation'}
        actions={actions}
        modal={true}
        open={true}
      >
        {options.content || 'Are you sure?'}
      </Dialog>
    </Gateway>
  )
}

export default createConfirm;

然后在我的组件中,我将其注入(inject)到 render() 函数中:

...
{
   _this.state.isOpen && _this.confirmable
}

每当我需要显示确认模式时,我都会打电话

this.confirmable = createConfirm({
  title: 'CONFIRM',
  content: 'Are you sure to do that'
}, function() {
  console.log('user confirm')
  _this.setState({
    isOpen: false
  });
}, function() {
  console.log('user cancel')
  _this.setState({
    isOpen: false
  })
});
this.setState({isOpen: true});

我的问题

如您所见,我关闭“确认”对话框的方法是将 isOpen 状态设置为 false,这样它就不会被渲染。这是一个小作弊,似乎不是关闭对话框的 native 方式(丢失离开动画,看起来很奇怪......)。

那么我如何实现一个可以完全控制对话框的服务呢?

谢谢!

最佳答案

var Modal = React.createClass({
  displayName: 'Modal',
  backdrop: function() {
    return <div className='modal-backdrop in' />;
  },

  modal: function() {
    var style = {display: 'block'};
    return (
      <div
        className='modal in'
        tabIndex='-1'
        role='dialog'
        aria-hidden='false'
        ref='modal'
        style={style}
      >
        <div className='modal-dialog'>
          <div className='modal-content'>
            {this.props.children}
          </div>
        </div>
      </div>
    );
  },

  render: function() {
    return (
      <div>
        {this.backdrop()}
        {this.modal()}
      </div>
    );
  }
});

var Confirm = React.createClass({
  displayName: 'Confirm',
  getDefaultProps: function() {
    return {
      confirmLabel: 'OK',
      abortLabel: 'Cancel'
    };
  },

  abort: function() {
    return this.promise.reject();
  },

  confirm: function() {
    return this.promise.resolve();
  },

  componentDidMount: function() {
    this.promise = new $.Deferred();
    return React.findDOMNode(this.refs.confirm).focus();
  },

  render: function() {
    var modalBody;
    if (this.props.description) {
      modalBody = (
        <div className='modal-body'>
          {this.props.description}
        </div>
      );
    }

    return (
      <Modal>
        <div className='modal-header'>
          <h4 className='modal-title'>
            {this.props.message}
          </h4>
        </div>
        {modalBody}
        <div className='modal-footer'>
          <div className='text-right'>
            <button
              role='abort'
              type='button'
              className='btn btn-default'
              onClick={this.abort}
            >
              {this.props.abortLabel}
            </button>
            {' '}
            <button
              role='confirm'
              type='button'
              className='btn btn-primary'
              ref='confirm'
              onClick={this.confirm}
            >
              {this.props.confirmLabel}
            </button>
          </div>
        </div>
      </Modal>
    );
  }
});
 
var confirm = function(message, options) {
  var cleanup, component, props, wrapper;
  if (options == null) {
    options = {};
  }
  props = $.extend({
    message: message
  }, options);
  wrapper = document.body.appendChild(document.createElement('div'));
  component = React.render(<Confirm {...props}/>, wrapper);
  cleanup = function() {
    React.unmountComponentAtNode(wrapper);
    return setTimeout(function() {
      return wrapper.remove();
    });
  };
  return component.promise.always(cleanup).promise();
};


$(function() {
  return $('.removable').click(function() {
    return confirm('Are you sure?', {
      description: 'Would you like to remove this item from the list?',
      confirmLabel: 'Yes',
      abortLabel: 'No'
    }).then((function(_this) {
      return function() {
        return $(_this).parent().remove();
      };
    })(this));
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.1/react-with-addons.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.1/JSXTransformer.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">

<div id="row">
    <div class="well">
        <ul>
            <li>Foo <a href="#" class="removable"><i class="glyphicon glyphicon-trash"></i></a></li>
            <li>Bar <a href="#" class="removable"><i class="glyphicon glyphicon-trash"></i></a></li>
            <li>Baz <a href="#" class="removable"><i class="glyphicon glyphicon-trash"></i></a></li>
        </ul>
    </div>
</div>

关于javascript - ReactJs 中可重用的模态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41414894/

相关文章:

javascript - 如何在 Bootstrap 模式中动态调整字体大小?

javascript - 使用 OData 过滤器生成 Breeze.js 查询(多个谓词)

javascript - 验证密码至少为 6 个字符

javascript - 将以秒为单位的时间间隔转换为更易读的形式

javascript - 如何使用 babel 和 webpack 设置一个 react/node 项目?

html - Bootstrap 圆模态

javascript - 当我只对一个 div 使用 jQuery scrollLeft 时,整个页面在顶部滚动

javascript - 在 React/Redux 中测试连接的组件

reactjs - react 测试库 : can't acquire context from the given item

c# - 将BackgroundWorker转换为具有模态显示的Task.Run