在Bootstrap弹出窗口中渲染React组件 [英] Rendering a React component inside a Bootstrap popover

查看:211
本文介绍了在Bootstrap弹出窗口中渲染React组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一组图像,它们在content属性/参数中使用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} />

                );
    }
});

解决方案

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 Popover的setContent方法除了HTML或文本字符串外,还可以使用React组件.我使用的是React.renderComponent:

,而不是使用jQuery的htmltext方法.

// 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中删除后,将正确清理弹出框组件.

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.

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} />

                );
    }
});

解决方案

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 renderComponentToString which takes a component and returns a string of HTML through a callback:

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.


That said, it's possible to make this work by patching Bootstrap. I've created a live demo that has dynamic popover content:


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

Note that the current time is rendered within the popover by a React component that updates every second.


How was this popover created?

I patched Bootstrap popover's setContent method to take a React component in addition to an HTML or text string. Instead of using jQuery's html or text methods, I use 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 componentDidMount method 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.

这篇关于在Bootstrap弹出窗口中渲染React组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆