【问题标题】:Rendering a React component inside a Bootstrap popover在 Bootstrap 弹出框内渲染 React 组件
【发布时间】:2013-11-30 18:16:10
【问题描述】:

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

                );
    }
});

【问题讨论】:

    标签: jquery twitter-bootstrap reactjs


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

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

      引导下拉菜单在用户与之交互后立即关闭。这可能不是我们想要的行为(在我的例子中,我插入了一个日期选择器,用户无法更改月份而无需重新打开菜单来选择新日期)。


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

      我不想使用 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 上的“下拉”类,(ii) 触发器上的数据切换属性“下拉”(您可以将触发器更改为您想要的任何 html 元素)和(iii) 下拉菜单中的“dropdown-menu”类(您也可以将其更改为您想要的任何html元素,而不必粘贴Bootstrap提出的“ul”元素)。

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

      【讨论】:

        【解决方案3】:

        有一个名为 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>
            );
        
        },
        

        【讨论】:

          【解决方案4】:

          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's setContent method 以在 HTML 或文本字符串之外采用 React 组件。我没有使用 jQuery 的 htmltext 方法,而是使用 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,您会看到我制作的通用 &lt;BsPopover /&gt; 包装器,它为您处理所有 Bootstrap 调用,包括在从 DOM 中删除包装器组件后正确清理弹出组件。

          【讨论】:

          • 在第一个渲染静态弹出框的示例中,React.renderComponentToString 具有an async API that returns the markup via a callback(尽管实际实现不是异步的,但 API 是这样设计的,以防将来需要)。因此,您需要将其更改为 React.renderComponentToString(&lt;MusicList /&gt;, function(markup) { $(this.getDOMNode()).popover({ html: true, content: markup }); }.bind(this));
          • (React v0.9 将 React.renderComponentToString 更改为具有同步 API;只是相应地更新了示例。)
          • 这对我有用,但我必须添加一个触发器:手动才能让它仅在单击链接时打开和关闭
          • 不需要修补 Bootstrap 的弹出框。添加事件处理程序可以通过简单地使用 jQuery 来完成:$(this.getDOMNode()).popover({ html: true, content: React.renderToString( &lt;input type='text' placeholder='path to image' name='icon' value={newStatus.icon} /&gt;) }).parent().on('change', 'input[name="icon"]', this.handleChange);
          • React.renderComponent(, $SomeJQueryNode[0]) 刚刚拯救了我的一天!谢谢!
          猜你喜欢
          • 1970-01-01
          • 2016-08-14
          • 1970-01-01
          • 2019-03-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多