React.js 中的 Bootstrap 模式

IT技术 javascript twitter-bootstrap crud reactjs
2021-04-07 08:00:02

我需要通过单击 Bootstrap 导航栏中的按钮和其他位置(以显示组件实例的数据,即提供“编辑”功能来打开 Bootstrap Modal ,但我不知道如何完成此操作。这是我的代码:

编辑:代码已更新。

ApplicationContainer = React.createClass({
    render: function() {
        return (
            <div className="container-fluid">
            <NavBar />
                <div className="row">
                    <div className="col-md-2">
                        <ScheduleEntryList />
                    </div>
                    <div className="col-md-10">
                    </div>
                </div>
                <ScheduleEntryModal />
            </div>
        );
    }
});

NavBar = React.createClass({
    render: function() {
        return (
            <nav className="navbar navbar-default navbar-fixed-top">
                <div className="container-fluid">
                    <div className="navbar-header">
                        <a className="navbar-brand" href="#">
                            <span className="glyphicon glyphicon-eye-open"></span>
                        </a>
                    </div>
                    <form className="navbar-form navbar-left">
                        <button className="btn btn-primary" type="button" data-toggle="modal" data-target="#scheduleentry-modal">
                            <span className="glyphicon glyphicon-plus">
                            </span>
                        </button>
                    </form>
                    <ul className="nav navbar-nav navbar-right">
                        <li><a href="#"><span className="glyphicon glyphicon-user"></span> Username</a></li>
                    </ul>
                </div>
            </nav>
        );
    }
});

ScheduleEntryList = React.createClass({
    getInitialState: function() {
        return {data: []}
    },

    loadData: function() {
        $.ajax({
            url: "/api/tasks",
            dataType: "json",

            success: function(data) {
                this.setState({data: data});
            }.bind(this),

            error: function(xhr, status, error) {
                console.error("/api/tasks", status, error.toString());
            }.bind(this)
        });
    },

    componentWillMount: function() {
        this.loadData();
        setInterval(this.loadData, 20000);
    },

    render: function() {
        items = this.state.data.map(function(item) {
            return <ScheduleEntryListItem item={item}></ScheduleEntryListItem>;
        });

        return (
            <div className="list-group">
                <a className="list-group-item active">
                    <h5 className="list-group-item-heading">Upcoming</h5>
                </a>
                {items}
            </div>
        );
    }
});

ScheduleEntryListItem = React.createClass({
    openModal: function() {
        $("#scheduleentry-modal").modal("show");
    },

    render: function() {
        deadline = moment(this.props.item.deadline).format("MMM Do YYYY, h:mm A");

        return (
            <a className="list-group-item" href="#" onClick={this.openModal}>
                <h5 className="list-group-item-heading">
                    {this.props.item.title}
                </h5>
                <small className="list-group-item-text">
                    {deadline}
                </small>
            </a>
        );
    }
});

Modal = React.createClass({
    componentDidMount: function() {
        $(this.getDOMNode())
            .modal({backdrop: "static", keyboard: true, show: false});
    },

    componentWillUnmount: function() {
        $(this.getDOMNode())
            .off("hidden", this.handleHidden);
    },

    open: function() {
        $(this.getDOMNode()).modal("show");
    },

    close: function() {
        $(this.getDOMNode()).modal("hide");
    },

    render: function() {
        return (
            <div id="scheduleentry-modal" className="modal fade" tabIndex="-1">
                <div className="modal-dialog">
                    <div className="modal-content">
                        <div className="modal-header">
                            <button type="button" className="close" data-dismiss="modal">
                                <span>&times;</span>
                            </button>
                            <h4 className="modal-title">{this.props.title}</h4>
                        </div>
                        <div className="modal-body">
                            {this.props.children}
                        </div>
                        <div className="modal-footer">
                            <button type="button" className="btn btn-danger pull-left" data-dismiss="modal">Delete</button>
                            <button type="button" className="btn btn-primary">Save</button>
                        </div>
                    </div>
                </div>
            </div>

        )
    }
});

ScheduleEntryModal = React.createClass({
    render: function() {
        var modal = null;
        modal = (
            <Modal title="Add Schedule Entry">
                    <form className="form-horizontal">
                        <div className="form-group">
                            <label htmlFor="title" className="col-sm-2 control-label">Title</label>
                            <div className="col-sm-10">
                                <input id="title" className="form-control" type="text" placeholder="Title" ref="title" name="title"/>
                            </div>
                        </div>
                        <div className="form-group">
                            <label htmlFor="deadline" className="col-sm-2 control-label">Deadline</label>
                            <div className="col-sm-10">
                                <input id="deadline" className="form-control" type="datetime-local" ref="deadline" name="deadline"/>
                            </div>
                        </div>
                        <div className="form-group">
                            <label htmlFor="completed" className="col-sm-2 control-label">Completed</label>
                            <div className="col-sm-10">
                                <input id="completed" className="form-control" type="checkbox" placeholder="completed" ref="completed" name="completed"/>
                            </div>
                        </div>
                        <div className="form-group">
                            <label htmlFor="description" className="col-sm-2 control-label">Description</label>
                            <div className="col-sm-10">
                                <textarea id="description" className="form-control" placeholder="Description" ref="description" name="description"/>
                            </div>
                        </div>
                    </form>
            </Modal>
        );

        return (
            <div className="scheduleentry-modal">
                {modal}
            </div>
        );
    }
});

对代码的其他评论和改进表示赞赏。

6个回答

我最近正在寻找一个很好的解决方案,而无需将 React-Bootstrap 添加到我的项目中(因为 Bootstrap 4 即将发布)。

这是我的解决方案:https : //jsfiddle.net/16j1se1q/1/

let Modal = React.createClass({
    componentDidMount(){
        $(this.getDOMNode()).modal('show');
        $(this.getDOMNode()).on('hidden.bs.modal', this.props.handleHideModal);
    },
    render(){
        return (
          <div className="modal fade">
            <div className="modal-dialog">
              <div className="modal-content">
                <div className="modal-header">
                  <button type="button" className="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                  <h4 className="modal-title">Modal title</h4>
                </div>
                <div className="modal-body">
                  <p>One fine body&hellip;</p>
                </div>
                <div className="modal-footer">
                  <button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
                  <button type="button" className="btn btn-primary">Save changes</button>
                </div>
              </div>
            </div>
          </div>
        )
    },
    propTypes:{
        handleHideModal: React.PropTypes.func.isRequired
    }
});



let App = React.createClass({
    getInitialState(){
        return {view: {showModal: false}}
    },
    handleHideModal(){
        this.setState({view: {showModal: false}})
    },
    handleShowModal(){
        this.setState({view: {showModal: true}})
    },
    render(){
    return(
        <div className="row">
            <button className="btn btn-default btn-block" onClick={this.handleShowModal}>Open Modal</button>
            {this.state.view.showModal ? <Modal handleHideModal={this.handleHideModal}/> : null}
        </div>
    );
  }
});

React.render(
   <App />,
    document.getElementById('container')
);

主要思想是仅在要显示时(在 App 组件渲染函数中)将 Modal 组件渲染到 React DOM 中。我保留一些“视图”状态,指示当前是否显示模态。

'componentDidMount' 和 'componentWillUnmount' 回调通过 Bootstrap javascript 函数隐藏或显示模式(一旦它被渲染到 React DOM 中)。

我认为这个解决方案很好地遵循了 React 精神,但欢迎提出建议!

猜猜等待结束了。顺便说一句,我真的不喜欢您的解决方案包含 jQuery 的事实。
2021-05-25 08:00:02
添加on('hidden.bs.modal', this.props.handleHideModal);以正确处理弹出窗口的关闭。
2021-06-01 08:00:02
不得不更换$(this.getDOMNode())$(ReactDOM.findDOMNode(this))使它工作。可能不是显示模态的正确方法,但对我有用。
2021-06-05 08:00:02
根据stackoverflow.com/questions/10636667/...,如果模态容器具有固定或相对或绝对位置,或者位于具有固定/相对/绝对位置的元素内,则模态将出现在背景下。不幸的是,在这个解决方案中,模态容器嵌入在 react 组件中,这意味着一旦 react 组件在固定/相对/绝对 DOM 元素中呈现,就会发生模态出现在后台的问题。几个小时前我遇到了这个问题,并想出了一个新的解决方案。稍后会发布。
2021-06-10 08:00:02
@happy.cze 是的,我也发现了这个!否则,当您关闭然后重新打开模态时,最终会出现 2 个模态回落。谢谢!
2021-06-20 08:00:02

您可以使用 React-Bootstrap ( https://react-bootstrap.github.io/components/modal )。该链接有一个模态示例。加载 react-bootstrap 后,模态组件就可以用作react组件:

var Modal = ReactBootstrap.Modal;

然后可以用作react组件 <Modal/>

对于 Bootstrap 4,有 react-strap ( https://reactstrap.github.io )。React-Bootstrap 仅支持 Bootstrap 3。

我重新审视了这个并最终使用了 react-bootstrap,它很好地完成了这项工作。
2021-05-28 08:00:02
Reactstrap 很好用。如果您使用的是 bootstrap 4,推荐使用
2021-06-03 08:00:02
它不为模态提供 Provider 标签。如果你使用 Redux,我认为你会遇到麻烦
2021-06-11 08:00:02
我相信我的代码中已经有了更原始的版本。我需要的是能够在单击另一个组件(列表项)时显示模态,然后显示该列表项的数据。
2021-06-12 08:00:02
我仍然强烈推荐使用 react-bootstrap。它将防止您不得不重新发明轮子,并且您不必使用 jquery 来改变 DOM 以获得所需的模态行为(您通常希望避免在使用 react 时直接更改 DOM)。 <ModalTrigger/>可用于启动模态,或者如果您想自己处理模态的状态,则可以使用 react-bootstrap 示例(在答案中链接)的模态部分中的“自定义触发器”。
2021-06-12 08:00:02

getDOMNode()已弃用。而是用于ref访问 DOM 元素。这是工作模态组件(Bootstrap 4)。决定是否在父组件中显示 Modal 组件。

示例:https : //jsfiddle.net/sqfhkdcy/

class Modal extends Component {
    constructor(props) {
        super(props);
    }
    componentDidMount() {
        $(this.modal).modal('show');
        $(this.modal).on('hidden.bs.modal', handleModalCloseClick);
    }
    render() {
        return (
            <div>
                <div className="modal fade" ref={modal=> this.modal = modal} id="exampleModal" tabIndex="-1" role="dialog" aria- labelledby="exampleModalLabel" aria-hidden="true">
                    <div className="modal-dialog" role="document">
                        <div className="modal-content">
                            <div className="modal-header">
                                <h5 className="modal-title" id="exampleModalLabel">Modal title
                                </h5>
                                <button type="button" className="close" data- dismiss="modal" aria-label="Close">
                                    <span aria-hidden="true">&times;</span>
                                </button>
                            </div>
                            <div className="modal-body">
                                ...
                            </div>
                            <div className="modal-footer">
                                <button type="button" className="btn btn-secondary" data- dismiss="modal">Close</button>
                                <button type="button" className="btn btn-primary">Save changes</button>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

编辑:

以下是使其工作所需的导入:

import $ from 'jquery';
window.jQuery = $;
window.$ = $;
global.jQuery = $;
这个解决方案不再有效了吗?我遇到了这个错误。
2021-05-29 08:00:02
我还要补充 componentWillUnmount() { $(this.modal).modal('hide'); }
2021-06-05 08:00:02
你好。有很多依赖项要包含。我创建了 jsfiddle:jsfiddle.net/sqfhkdcy
2021-06-06 08:00:02

我只使用 bootstrap cdn (css + js) 来实现类似“reactstrap”的解决方案。我使用 props.children 将动态数据从父组件传递到子组件。您可以在此处找到更多相关信息通过这种方式,您拥有三个独立的组件:模态页眉、模态正文和模态页脚,它们彼此完全独立。


//Modal component
import React, { Component } from 'react';

export const ModalHeader = props => {
  return <div className="modal-header">{props.children}</div>;
};

export const ModalBody = props => {
  return <div className="modal-body">{props.children}</div>;
};

export const ModalFooter = props => {
  return <div className="modal-footer">{props.children}</div>;
};

class Modal extends Component {
  constructor(props) {
    super(props);
    this.state = {
      modalShow: '',
      display: 'none'
    };
    this.openModal = this.openModal.bind(this);
    this.closeModal = this.closeModal.bind(this);
  }

  openModal() {
    this.setState({
      modalShow: 'show',
      display: 'block'
    });
  }

  closeModal() {
    this.setState({
      modalShow: '',
      display: 'none'
    });
  }

  componentDidMount() {
    this.props.isOpen ? this.openModal() : this.closeModal();
  }

  componentDidUpdate(prevProps) {
    if (prevProps.isOpen !== this.props.isOpen) {
      this.props.isOpen ? this.openModal() : this.closeModal();
    }
  }

  render() {
    return (
      <div
        className={'modal fade ' + this.state.modalShow}
        tabIndex="-1"
        role="dialog"
        aria-hidden="true"
        style={{ display: this.state.display }}
      >
        <div className="modal-dialog" role="document">
          <div className="modal-content">{this.props.children}</div>
        </div>
      </div>
    );
  }
}

export default Modal;

//App component
import React, { Component } from 'react';
import Modal, { ModalHeader, ModalBody, ModalFooter } from './components/Modal';

import './App.css';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      modal: false
    };
    this.toggle = this.toggle.bind(this);
  }

  toggle() {
    this.setState({ modal: !this.state.modal });
  }

  render() {
    return (
      <div className="App">
        <h1>Bootstrap Components</h1>

        <button
          type="button"
          className="btn btn-secondary"
          onClick={this.toggle}
        >
          Modal
        </button>

        <Modal isOpen={this.state.modal}>
          <ModalHeader>
            <h3>This is modal header</h3>
            <button
              type="button"
              className="close"
              aria-label="Close"
              onClick={this.toggle}
            >
              <span aria-hidden="true">&times;</span>
            </button>
          </ModalHeader>
          <ModalBody>
            <p>This is modal body</p>
          </ModalBody>
          <ModalFooter>
            <button
              type="button"
              className="btn btn-secondary"
              onClick={this.toggle}
            >
              Close
            </button>
            <button
              type="button"
              className="btn btn-primary"
              onClick={this.toggle}
            >
              Save changes
            </button>
          </ModalFooter>
        </Modal>
      </div>
    );
  }
}

export default App;

这个解决方案看起来不错,但它并没有消除黑屏
2021-06-09 08:00:02

我创建了这个函数:

onAddListItem: function () {
    var Modal = ReactBootstrap.Modal;
    React.render((
        <Modal title='Modal title' onRequestHide={this.hideListItem}>
            <ul class="list-group">
                <li class="list-group-item">Cras justo odio</li>
                <li class="list-group-item">Dapibus ac facilisis in</li>
                <li class="list-group-item">Morbi leo risus</li>
                <li class="list-group-item">Porta ac consectetur ac</li>
                <li class="list-group-item">Vestibulum at eros</li>
            </ul>
        </Modal>
    ), document.querySelector('#modal-wrapper'));
}

然后在我的 Button 触发器上使用它。

要“隐藏”模态:

hideListItem: function () {
    React.unmountComponentAtNode(document.querySelector('#modal-wrapper'));
},