twitter-bootstrap 在 Bootstrap 弹出窗口中渲染 React 组件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20033522/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rendering a React component inside a Bootstrap popover
提问by Fredrick Thornton
I have a set of images that have popovers using the bootstrap popover ui component in the content attribute/parameter i would like to add the ReactJS MusicList Component but I couldn't figure out the syntax or whether it's possible or not.
我有一组图像在内容属性/参数中使用 bootstrap popover ui 组件具有弹出窗口,我想添加 ReactJS MusicList 组件,但我无法弄清楚语法或是否可能。
var MusicList = React.createClass({
render : function(){
return(<ul><li>Here</li></ul>);
}
});
var PopoverImage = React.createClass({
componentDidMount:function(){
$("#"+this.getDOMNode().id).attr('data-component','<span>here</span>');
$("#"+this.getDOMNode().id).popover({
html:true,
content:
});
},
render:function(){
return(
<img href="#" id={this.props.friend.uid+'_popover'} data-html={true} className="smallImage" src={this.props.friend.pic_small} rel="popover" data-original-title={this.props.friend.name} />
);
}
});
回答by Sophie Alpert
Bootstrap doesn't make it easy to render a dynamic component within a popover. If the popover you want to present is static, you can simply use React's renderComponentToStringwhich takes a component and returns a string of HTML through a callback:
Bootstrap 并不能轻松地在弹出窗口中呈现动态组件。如果您想要呈现的弹出框是静态的,您可以简单地使用 React 的renderComponentToString,它接受一个组件并通过回调返回一串 HTML:
var html = React.renderComponentToString(<MusicList />);
$(this.getDOMNode()).popover({
html: true,
content: html
});
However, if your component has any interactivity, that strategy won't work because React never has a chance to attach event handlers (or run any of your custom lifecycle methods). Indeed, Bootstrap doesn't provide the proper hooks to make your popover content dynamic.
但是,如果您的组件具有任何交互性,则该策略将不起作用,因为 React 永远没有机会附加事件处理程序(或运行任何自定义生命周期方法)。确实,Bootstrap 没有提供适当的钩子来使您的弹出窗口内容动态化。
That said, it's possible to make this work by patching Bootstrap. I've created a live demo that has dynamic popover content:
也就是说,可以通过修补 Bootstrap 来完成这项工作。我创建了一个具有动态弹出内容的现场演示:

http://jsfiddle.net/spicyj/q6hj7/

http://jsfiddle.net/spicyj/q6hj7/
Note that the current time is rendered within the popover by a React component that updates every second.
请注意,当前时间是由每秒更新的 React 组件在弹出窗口中呈现的。
How was this popover created?
这个弹窗是如何创建的?
I patched Bootstrap popover's setContentmethodto take a React component in addition to an HTML or text string. Instead of using jQuery's htmlor textmethods, I use React.renderComponent:
我修补了Bootstrap popover 的setContent方法,除了 HTML 或文本字符串之外,还采用了 React 组件。我没有使用jQueryhtml或text方法,而是使用React.renderComponent:
// Patch Bootstrap popover to take a React component instead of a
// plain HTML string
$.extend($.fn.popover.Constructor.DEFAULTS, {react: false});
var oldSetContent = $.fn.popover.Constructor.prototype.setContent;
$.fn.popover.Constructor.prototype.setContent = function() {
if (!this.options.react) {
return oldSetContent.call(this);
}
var $tip = this.tip();
var title = this.getTitle();
var content = this.getContent();
$tip.removeClass('fade top bottom left right in');
// If we've already rendered, there's no need to render again
if (!$tip.find('.popover-content').html()) {
// Render title, if any
var $title = $tip.find('.popover-title');
if (title) {
React.renderComponent(title, $title[0]);
} else {
$title.hide();
}
React.renderComponent(content, $tip.find('.popover-content')[0]);
}
};
Now it's possible for you to write
现在你可以写了
$(this.getDOMNode()).popover({
react: true,
content: <MusicList />
});
in your componentDidMountmethod and have it render properly. If you look in the linked JSFiddle, you'll see a general-purpose <BsPopover />wrapper I made that takes care of all the Bootstrap calls for you, including properly cleaning up the popover components once the wrapper component is removed from the DOM.
在您的componentDidMount方法中并使其正确呈现。如果您查看链接的 JSFiddle,您会看到<BsPopover />我制作的一个通用包装器,它为您处理所有 Bootstrap 调用,包括在包装器组件从 DOM 中删除后正确清理弹出组件。
回答by ml242
There is a new library called React-Bootstrap that is undergoing rapid development.
有一个名为 React-Bootstrap 的新库正在快速开发中。
https://react-bootstrap.github.io/components.html#popovers
https://react-bootstrap.github.io/components.html#popovers
If you include this module you have the ability to make the popover its own component that you can save in a variable and then use in your render function.
如果你包含这个模块,你就可以让 popover 成为它自己的组件,你可以将它保存在一个变量中,然后在你的渲染函数中使用。
Their example:
他们的例子:
const positionerInstance = (
<ButtonToolbar>
<OverlayTrigger trigger="click" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}>
<Button bsStyle="default">Click</Button>
</OverlayTrigger>
<OverlayTrigger trigger="hover" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}>
<Button bsStyle="default">Hover</Button>
</OverlayTrigger>
<OverlayTrigger trigger="focus" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}>
<Button bsStyle="default">Focus</Button>
</OverlayTrigger>
<OverlayTrigger trigger="click" rootClose placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}>
<Button bsStyle="default">Click + rootClose</Button>
</OverlayTrigger>
</ButtonToolbar>
);
const positionerInstance = (
<ButtonToolbar>
<OverlayTrigger trigger="click" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}>
<Button bsStyle="default">Click</Button>
</OverlayTrigger>
<OverlayTrigger trigger="hover" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}>
<Button bsStyle="default">Hover</Button>
</OverlayTrigger>
<OverlayTrigger trigger="focus" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}>
<Button bsStyle="default">Focus</Button>
</OverlayTrigger>
<OverlayTrigger trigger="click" rootClose placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}>
<Button bsStyle="default">Click + rootClose</Button>
</OverlayTrigger>
</ButtonToolbar>
);
React.render(positionerInstance, mountNode);
React.render(positionerInstance, mountNode);
my code:
我的代码:
showMoreDetails: function(obj, columns){
showMoreDetails:函数(对象,列){
var popOver = (
<Popover>
<table>
{
columns.map(col =>
<tr>
<td style={{textAlign:'right', padding:5}}>
{col.label}:
</td>
<td style={{padding:5}}>
{obj[col.key]}
</td>
</tr>
)
}
</table>
</Popover>
);
return(
<OverlayTrigger trigger='click' rootClose placement='left' overlay={popOver}>
<div className="popover-more">more...</div>
</OverlayTrigger>
);
},
回答by Freddo
After having posted this reply and having tested and worked a little bit with this work-around, I realize that it is not optimal.
在发布此回复并测试并使用此解决方法进行了一些工作后,我意识到它不是最佳选择。
Bootstrap dropdown menus close as soon as the user has interacted with it. This might not be the desired behavior (in my case, I am inserting a datepicker and the user cannot change month without having to reopen the menu to choose new date).
一旦用户与之交互,引导下拉菜单就会关闭。这可能不是所需的行为(在我的情况下,我插入了一个日期选择器,用户无法更改月份而不必重新打开菜单来选择新日期)。
I had the same issue and I came up with an easy and alternative solution.
我遇到了同样的问题,我想出了一个简单的替代解决方案。
I did not want to use react-bootstrap (other parts of my app are not reactified and use bootstrap, so I do not want to have two libraries doing the same thing).
我不想使用 react-bootstrap (我的应用程序的其他部分没有反应并使用 bootstrap,所以我不想让两个库做同样的事情)。
The dropdown component provided out of the box by Bootstrap almost provide the same functionalities as the popover, except it is way more flexible. This is the standard Bootstrap dropdown:
Bootstrap 开箱即用的下拉组件几乎提供了与弹出框相同的功能,只是它更灵活。这是标准的 Bootstrap 下拉菜单:
<div class="dropdown">
<button id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown trigger
<span class="caret"></span>
</button>
<ul class="dropdown-menu" aria-labelledby="dLabel">
...
</ul>
</div>
Here is the minimum you need to make it work without breaking it and you can include whichever React element within it:
这是在不破坏它的情况下使其工作所需的最低限度,您可以在其中包含任何 React 元素:
<div className="dropdown">
<button data-toggle="dropdown">
Dropdown trigger
</button>
<div className="dropdown-menu">
<myGreatReactIntervactiveComponent
value={this.props.value}
onChange={this.handleChange}
onClick={this.handleClick}
children={this.greatChildrenForMyGreatREactInteractiveComponent}
/>
</div>
</div>
All you need to keep is (i) the class "dropdown" on the wrapper div, (ii) the data-toggle attribute "dropdown" on the trigger (you can change your trigger to whatever html element you want) and (iii) the class "dropdown-menu" on the dropdown (you can also change it to whatever html element you want and you do not have to stick the "ul" element proposed by Bootstrap).
您需要保留的是 (i) 包装器 div 上的“下拉”类,(ii) 触发器上的数据切换属性“下拉”(您可以将触发器更改为您想要的任何 html 元素)和 (iii)下拉菜单中的“下拉菜单”类(您也可以将其更改为您想要的任何 html 元素,而不必粘贴 Bootstrap 建议的“ul”元素)。
You loose a few features compared to the popover (you cannot define your own transitions, you cannot have display them on top, left or right, but only below -- it is a dropdown) but you gain total control over the content of your dropdown/popover.
与弹出框相比,您失去了一些功能(您不能定义自己的过渡,也不能将它们显示在顶部、左侧或右侧,而只能显示在下方——它是一个下拉列表)但您可以完全控制下拉列表的内容/弹出。
回答by Skill M2
Another way to solve this to include the react component you want to be the popover content in the render function of the component containing the popover (i.e. 'the page') but place it inside a div with style "display: none;" so that is not displayed and takes up no space, also give it an id, e.g. 'popOverContent'. Then when you initialize the popover set content: document.getElementById("popOverContent"). In bootstrap 4 at least, it takes an element as content.
解决此问题的另一种方法是在包含弹出框的组件(即“页面”)的渲染函数中包含您想要作为弹出框内容的 react 组件,但将其放置在样式为“display: none;”的 div 中。以便不显示并且不占用空间,还给它一个id,例如'popOverContent'。然后当你初始化 popover set 内容时:document.getElementById("popOverContent")。至少在 bootstrap 4 中,它将一个元素作为内容。
You don't need to modify the bootstrap code this way, making maintenance/updates easier.
您不需要以这种方式修改引导程序代码,从而使维护/更新更容易。

