29

我有一组图像,它们在内容属性/参数中使用引导弹出框 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} />

                );
    }
});
4

4 回答 4

39

Bootstrap 无法轻松地在弹出框内渲染动态组件。如果您要呈现的弹出框是静态的,您可以简单地使用 React renderComponentToString,它接受一个组件并通过回调返回一个 HTML 字符串:

var html = React.renderComponentToString(<MusicList />);
$(this.getDOMNode()).popover({
    html: true,
    content: html
});

但是,如果您的组件具有任何交互性,那么该策略将不起作用,因为 React 永远没有机会附加事件处理程序(或运行任何自定义生命周期方法)。事实上,Bootstrap 没有提供适当的钩子来使您的弹出内容动态化。


也就是说,可以通过修补 Bootstrap 来完成这项工作。我创建了一个具有动态弹出内容的现场演示:

弹窗演示截图
http://jsfiddle.net/spicyj/q6hj7/

请注意,当前时间由每秒更新的 React 组件在弹出框内呈现。


这个弹出框是如何创建的?

我修补了Bootstrap 弹出框的setContent方法,除了 HTML 或文本字符串外,还采用了 React 组件。我没有使用 jQueryhtmltext方法,而是使用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 中删除包装器组件后正确清理弹出组件。

于 2013-11-17T20:47:51.583 回答
2

有一个名为 React-Bootstrap 的新库正在快速开发中。

https://react-bootstrap.github.io/components.html#popovers

如果您包含此模块,则您可以使弹出框成为自己的组件,您可以将其保存在变量中,然后在您的渲染函数中使用。

他们的例子:

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:函数(obj,列){

    var popOver = (
        <Popover>
            <table>
                {
                    columns.map(col =>
                            <tr>
                                <td style={{textAlign:'right', padding:5}}>
                                    {col.label}:&nbsp;
                                </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>
    );

},
于 2015-09-28T17:54:02.873 回答
0

解决此问题的另一种方法是在包含弹出框(即“页面”)的组件的渲染函数中包含您希望成为弹出框内容的反应组件,但将其放置在样式为“显示:无”的 div 中;所以它不会显示并且不占用空间,也给它一个id,例如'popOverContent'。然后在初始化弹出框集内容时:document.getElementById("popOverContent")。至少在 bootstrap 4 中,它需要一个元素作为内容。

您不需要以这种方式修改引导代码,使维护/更新更容易。

于 2019-01-29T23:08:54.497 回答
0

在发布此回复并测试并使用此解决方法进行了一些工作后,我意识到它不是最佳的。

一旦用户与之交互,引导下拉菜单就会关闭。这可能不是所需的行为(在我的情况下,我正在插入一个日期选择器,并且用户无法更改月份而无需重新打开菜单以选择新日期)。


我有同样的问题,我想出了一个简单的替代解决方案。

我不想使用 react-bootstrap(我的应用程序的其他部分没有反应并使用引导程序,所以我不想让两个库做同样的事情)。

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>

这是在不破坏它的情况下使其工作所需的最低要求,您可以在其中包含任何 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) 包装 div 上的类“dropdown”,(ii) 触发器上的 data-toggle 属性“dropdown”(您可以将触发器更改为您想要的任何 html 元素)和 (iii)下拉菜单中的“下拉菜单”类(您也可以将其更改为您想要的任何 html 元素,而不必粘贴 Bootstrap 提出的“ul”元素)。

与弹出框相比,您失去了一些功能(您无法定义自己的过渡,您无法在顶部、左侧或右侧显示它们,而只能在下方显示它们——它是一个下拉列表),但您可以完全控制下拉列表的内容/弹出窗口。

于 2016-01-14T20:38:13.030 回答