我有一组使用bootstrap popover ui组件在内容属性/参数中使用popovers的图像我想添加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} />
);
}
});
答案 0 :(得分:39)
Bootstrap无法在弹出框中呈现动态组件。如果你想要呈现的popover是静态的,你可以简单地使用React的renderComponentToString
,它接受一个组件并通过回调返回一串HTML:
var html = React.renderComponentToString(<MusicList />);
$(this.getDOMNode()).popover({
html: true,
content: html
});
但是,如果您的组件具有任何交互性,则该策略将不起作用,因为React从未有机会附加事件处理程序(或运行任何自定义生命周期方法)。实际上,Bootstrap没有提供适当的钩子来使你的popover内容动态化。
也就是说,可以通过修补Bootstrap来完成这项工作。我创建了一个具有动态弹出窗口内容的实时演示:
的 http://jsfiddle.net/spicyj/q6hj7/ 强>
请注意,当前时间在弹出窗口中由每秒更新的React组件呈现。
这个popover是如何创建的?
我修补了Bootstrap popover's setContent
method以获取除HTML或文本字符串之外的React组件。我没有使用jQuery的html
或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]);
}
};
现在你可以写
了$(this.getDOMNode()).popover({
react: true,
content: <MusicList />
});
在您的componentDidMount
方法中并正确渲染它。如果您查看链接的JSFiddle,您将看到我制作的通用<BsPopover />
包装器,它会为您处理所有Bootstrap调用,包括在从包装器组件中移除包装器组件后正确清理弹出组件。 DOM。
答案 1 :(得分:2)
有一个名为React-Bootstrap的新库正在快速发展。
https://react-bootstrap.github.io/components.html#popovers
如果你包含这个模块,你就可以使popover成为一个你可以保存在变量中的组件,然后在你的渲染函数中使用。
他们的例子:
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);
我的代码:
showMoreDetails:function(obj,columns){
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>
);
},
答案 2 :(得分:0)
在发布此回复并对此解决方案进行了一些测试和工作之后,我意识到这不是最佳的。
Bootstrap下拉菜单会在用户与其进行交互后立即关闭。这可能不是所希望的行为(在我的情况下,我正在插入一个日期选择器,用户无法更改月份而无需重新打开菜单来选择新日期。)
我遇到了同样的问题,我提出了一个简单而另类的解决方案。
我不想使用react-bootstrap(我的app的其他部分没有被重新使用并使用bootstrap,所以我不想让两个库做同样的事情。)
Bootstrap开箱即用的下拉组件几乎提供与popover相同的功能,除了它更灵活。 这是标准的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>
这是您在不破坏它的情况下使其工作所需的最小值,您可以在其中包含其中的任何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>
您需要保留的是(i)课程&#34;下拉&#34;在包装器div上,(ii)数据切换属性&#34;下拉&#34;在触发器上(您可以将触发器更改为您想要的任何html元素)和(iii)类&#34;下拉菜单&#34;在下拉列表中(您也可以将其更改为您想要的任何html元素,并且您不必坚持使用Bootstrap提出的&#34; ul&#34;元素。)
与popover相比,你放弃了一些功能(你不能定义自己的过渡,你不能在顶部,左侧或右侧显示它们,但只能在下面 - 它是一个下拉列表)但你可以完全控制内容你的下拉/弹出窗口。
答案 3 :(得分:0)
解决此问题的另一种方法是在包含弹出框的组件(即“页面”)的渲染函数中包含要成为弹出框内容的react组件,但将其放置在样式为“ display:none; ”因此它不会显示且不占用空间,并为其指定一个ID,例如“ popOverContent”。然后,当您初始化弹出框设置内容时:document.getElementById(“ popOverContent”)。至少在引导程序4中,它将元素作为内容。
您无需以这种方式修改引导程序代码,从而使维护/更新更加容易。