React.js 中的引导模式
Posted
技术标签:
【中文标题】React.js 中的引导模式【英文标题】:Bootstrap modal in React.js 【发布时间】:2015-03-30 06:49:19 【问题描述】:我需要通过单击 Bootstrap 导航栏和其他地方的按钮来打开 Bootstrap 模式(显示组件实例的数据,即提供“编辑”功能),但我没有不知道如何做到这一点。这是我的代码:
编辑:代码已更新。
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>×</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>
);
);
感谢其他 cmets 和对代码的改进。
【问题讨论】:
【参考方案1】:只需将href='#scheduleentry-modal'
添加到您要打开模式的元素中
或者使用 jQuery:$('#scheduleentry-modal').modal('show');
【讨论】:
我有什么办法可以用 React 做到这一点,因为我有时想用数据预填充它? 我不熟悉 ReactJS,但我认为这可能会有所帮助:react-bootstrap.github.io/components.html#modals 不熟悉主题的情况下为什么要发布回复? @jpcamara 为什么你会在 1.5 年后发表对这个问题毫无帮助的评论? 这与 React 无关【参考方案2】:您可以使用 React-Bootstrap (https://react-bootstrap.github.io/components/modal)。该链接有一个模态示例。一旦你加载了 react-bootstrap,modal 组件就可以作为一个 react 组件使用:
var Modal = ReactBootstrap.Modal;
然后可以用作反应组件
<Modal/>
.
对于 Bootstrap 4,有 react-strap (https://reactstrap.github.io)。 React-Bootstrap 仅支持 Bootstrap 3。
【讨论】:
我相信我的代码中已经有了一个更原始的版本。我需要的是能够在单击另一个组件(列表项)时显示模式,然后显示此列表项的数据。 我仍然强烈推荐使用 react-bootstrap。它将防止您不得不重新发明***,并且您不必使用 jquery 来改变 DOM 以获得所需的模态行为(您通常希望避免在使用 react 时直接更改 DOM)。<ModalTrigger/>
可用于启动模态,或者如果您想自己处理模态的状态,您可以使用 react-bootstrap 示例的模态部分中的“自定义触发器”(在答案中链接)。
我重新审视了这个并最终使用了 react-bootstrap,它很好地完成了这项工作。
它没有为模态提供 Provider 标签。我认为如果你使用 Redux 会遇到麻烦
Reactstrap 运行良好。如果您使用的是引导程序 4,建议使用【参考方案3】:
我创建了这个函数:
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'));
,
【讨论】:
【参考方案4】:我最近一直在寻找一个不错的解决方案,而无需将 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">×</span></button>
<h4 className="modal-title">Modal title</h4>
</div>
<div className="modal-body">
<p>One fine body…</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')
);
主要思想是仅在将要显示的 Modal 组件(在 App 组件的渲染函数中)呈现到 React DOM 中。我保留了一些“视图”状态来指示模态当前是否显示。
'componentDidMount' 和 'componentWillUnmount' 回调通过 Bootstrap javascript 函数隐藏或显示模式(一旦它被渲染到 React DOM 中)。
我认为这个解决方案很好地遵循了 React 精神,但欢迎提出建议!
【讨论】:
添加了on('hidden.bs.modal', this.props.handleHideModal);
以正确处理弹出窗口的关闭。
@happy.cze 是的,我也发现了这个!否则,当您关闭然后重新打开模态时,您最终会得到 2 个模态后退。谢谢!
必须将 $(this.getDOMNode())
替换为 $(ReactDOM.findDOMNode(this))
才能使其正常工作。可能不是显示模式的正确方法,但对我有用。
根据***.com/questions/10636667/…,如果模态容器具有固定或相对或绝对位置,或者在具有固定/相对/绝对位置的元素内,则模态将出现在背景下。不幸的是,在这个解决方案中,模态容器嵌入在反应组件中,这意味着一旦反应组件被渲染到固定/相对/绝对 DOM 元素中,就会发生模态出现在后台的问题。几个小时前我遇到了这个问题并想出了一个新的解决方案。稍后会发布。
猜猜等待结束了。顺便说一句,我不太喜欢您的解决方案包含 jQuery 的事实。【参考方案5】:
你可以试试这个模态:https://github.com/xue2han/react-dynamic-modal 它是无状态的,只有在需要的时候才可以渲染。所以非常好用。就像这样:
class MyModal extends Component
render()
const text = this.props;
return (
<Modal
onRequestClose=this.props.onRequestClose
openTimeoutMS=150
closeTimeoutMS=150
style=customStyle>
<h1>What you input : text</h1>
<button onClick=ModalManager.close>Close Modal</button>
</Modal>
);
class App extends Component
openModal()
const text = this.refs.input.value;
ModalManager.open(<MyModal text=text onRequestClose=() => true/>);
render()
return (
<div>
<div><input type="text" placeholder="input something" ref="input" /></div>
<div><button type="button" onClick=this.openModal.bind(this)>Open Modal </button> </div>
</div>
);
ReactDOM.render(<App />,document.getElementById('main'));
【讨论】:
【参考方案6】:感谢@tgrrr 提供了一个简单的解决方案,尤其是在不需要 3rd 方库时(例如 React-Bootstrap)。但是,这个解决方案有一个问题:模态容器嵌入在反应组件中,当外部反应组件(或其父元素)的位置样式为固定/相对/绝对时,这会导致modal-under-background issue。我遇到了这个问题并想出了一个新的解决方案:
"use strict";
var React = require('react');
var ReactDOM = require('react-dom');
var SampleModal = React.createClass(
render: function()
return (
<div className="modal fade" tabindex="-1" role="dialog">
<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">×</span></button>
<h4 className="modal-title">Title</h4>
</div>
<div className="modal-body">
<p>Modal content</p>
</div>
<div className="modal-footer">
<button type="button" className="btn btn-default" data-dismiss="modal">Cancel</button>
<button type="button" className="btn btn-primary">OK</button>
</div>
</div>
</div>
</div>
);
);
var sampleModalId = 'sample-modal-container';
var SampleApp = React.createClass(
handleShowSampleModal: function()
var modal = React.cloneElement(<SampleModal></SampleModal>);
var modalContainer = document.createElement('div');
modalContainer.id = sampleModalId;
document.body.appendChild(modalContainer);
ReactDOM.render(modal, modalContainer, function()
var modalObj = $('#'+sampleModalId+'>.modal');
modalObj.modal('show');
modalObj.on('hidden.bs.modal', this.handleHideSampleModal);
.bind(this));
,
handleHideSampleModal: function()
$('#'+sampleModalId).remove();
,
render: function()
return (
<div>
<a href="javascript:;" onClick=this.handleShowSampleModal>show modal</a>
</div>
)
);
module.exports = SampleApp;
主要思想是:
-
克隆模态元素(ReactElement 对象)。
创建一个 div 元素并将其插入到文档正文中。
在新插入的 div 元素中呈现克隆的模态元素。
渲染完成后,显示模态。另外,附加一个事件监听器,这样当modal被隐藏时,新插入的div元素就会被移除。
【讨论】:
谢谢您,无法弄清楚如何摆脱后台问题,您的建议非常有效!【参考方案7】:Reactstrap 也有一个implementation of Bootstrap Modals in React。该库针对 Bootstrap 版本 4,而 react-bootstrap 针对版本 3.X。
【讨论】:
一直在找这个!【参考方案8】: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">×</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 = $;
【讨论】:
嗨。有很多依赖项要包括在内。我创建了 jsfiddle:jsfiddle.net/sqfhkdcy 我还要加componentWillUnmount() $(this.modal).modal('hide');
这个解决方案还能用吗?我遇到了错误。【参考方案9】:
我只使用 bootstrap cdn (css + js) 来实现类似“reactstrap”的解决方案。我使用 props.children 将动态数据从父组件传递到子组件。你可以找到更多关于这个here。这样,您就拥有了三个独立的组件模态页眉、模态正文和模态页脚,它们彼此完全独立。
//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">×</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;
【讨论】:
这个解决方案看起来不错,但它并没有消除黑屏【参考方案10】:最快的解决方法是显式使用全局上下文中的 jQuery $(它已通过您的 $.modal() 进行扩展,因为您在脚本标记中引用了它):
window.$('#scheduleentry-modal').modal('show') // to show
window.$('#scheduleentry-modal').modal('hide') // to hide
所以这就是你如何在反应中处理它
import React, Component from 'react';
export default Modal extends Component
componentDidMount()
window.$('#Modal').modal('show');
handleClose()
window.$('#Modal').modal('hide');
render()
<
div className = 'modal fade'
id = 'ModalCenter'
tabIndex = '-1'
role = 'dialog'
aria - labelledby = 'ModalCenterTitle'
data - backdrop = 'static'
aria - hidden = 'true' >
<
div className = 'modal-dialog modal-dialog-centered'
role = 'document' >
<
div className = 'modal-content' >
// ...your modal body
<
button
type = 'button'
className = 'btn btn-secondary'
onClick =
this.handleClose
>
Close <
/button> < /
div > <
/div> < /
div >
【讨论】:
【参考方案11】:您可以使用来自 link 的 react-bootstrap 中的模型,它基本上是基于函数的
function Example()
const [show, setShow] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
return (
<>
<Button variant="primary" onClick=handleShow>
Launch demo modal
</Button>
<Modal show=show onHide=handleClose animation=false>
<Modal.Header closeButton>
<Modal.Title>Modal heading</Modal.Title>
</Modal.Header>
<Modal.Body>Woohoo, you're reading this text in a modal!</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick=handleClose>
Close
</Button>
<Button variant="primary" onClick=handleClose>
Save Changes
</Button>
</Modal.Footer>
</Modal>
</>
);
你可以把它转换成类组件
import React, Component from "react";
import Button, Modal from "react-bootstrap";
export default class exampleextends Component
constructor(props)
super(props);
this.state =
show: false,
close: false,
;
render()
return (
<div>
<Button
variant="none"
onClick=() => this.setState( show: true )
>
Choose Profile
</Button>
<Modal
show=this.state.show
animation=true
size="md" className="" shadow-lg border">
<Modal.Header className="bg-danger text-white text-center py-1">
<Modal.Title className="text-center">
<h5>Delete</h5>
</Modal.Title>
</Modal.Header>
<Modal.Body className="py-0 border">
body
</Modal.Body>
<Modal.Footer className="py-1 d-flex justify-content-center">
<div>
<Button
variant="outline-dark" onClick=() => this.setState( show: false )>Cancel</Button>
</div>
<div>
<Button variant="outline-danger" className="mx-2 px-3">Delete</Button>
</div>
</Modal.Footer>
</Modal>
</div>
);
【讨论】:
【参考方案12】:使用 React 功能组件的解决方案。
import React, useState, useRef, useEffect from 'react'
const Modal = ( title, show, onButtonClick ) =>
const dialog = useRef()
useEffect(() => $(dialog.current).modal(show ? 'show' : 'hide') , [show])
useEffect(() => $(dialog.current).on('hide.bs.modal', () =>
onButtonClick('close')) , [])
return (
<div className="modal fade" ref=dialog
id="modalDialog" tabIndex="-1" role="dialog"
aria-labelledby="modalDialogLabel" aria-hidden="true"
>
<div className="modal-dialog" role="document">
<div className="modal-content">
<div className="modal-header">
<h5 className="modal-title" id="modalDialogLabel">title</h5>
<button type="button" className="close" aria-label="Close"
onClick=() => onButtonClick('close')
>
<span aria-hidden="true">×</span>
</button>
</div>
<div className="modal-body">
...
</div>
<div className="modal-footer">
<button type="button" className="btn btn-secondary"
onClick=() => onButtonClick('close')>Close</button>
<button type="button" className="btn btn-primary"
onClick=() => onButtonClick('save')>Save</button>
</div>
</div>
</div>
</div>
)
const App = () =>
const [ showDialog, setShowDialog ] = useState(false)
return (
<div className="container">
<Modal
title="Modal Title"
show=showDialog
onButtonClick=button =>
if(button == 'close') setShowDialog(false)
if(button == 'save') console.log('save button clicked')
/>
<button className="btn btn-primary" onClick=() =>
setShowDialog(true)
>Show Dialog</button>
</div>
)
【讨论】:
我喜欢这种方法,但它不显示模态内容。以上是关于React.js 中的引导模式的主要内容,如果未能解决你的问题,请参考以下文章
如何从 react.js 中的 redux 存储向引导表插入数据?