2013-11-17 5 views
28

У меня есть набор изображений, которые имеют popovers с использованием компонента bootstrap popover ui в атрибуте/параметре контента, который я хотел бы добавить в компонент ReactJS MusicList, но я не мог понять синтаксис или это возможно или нет.Рендеринг компонента React внутри Bootstrap popover

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

       ); 
    } 
}); 

ответ

39

Bootstrap не позволяет легко отображать динамический компонент внутри popover. Если поповер вы хотите представить статичен, вы можете просто использовать РЕАКТ renderComponentToString, который принимает компонент и возвращает строку HTML с помощью обратного вызова:

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

Однако, если компонент имеет какую-либо интерактивность, что стратегия выиграла» t, потому что у React никогда не было возможности присоединить обработчики событий (или запустить любой из ваших пользовательских методов жизненного цикла). Действительно, Bootstrap не обеспечивает правильные перехваты, чтобы сделать ваш popover-контент динамичным.


Сказали, что это возможно сделать, исправляя Bootstrap. Я создал живую демонстрацию, которая имеет динамическое содержание поповера:

popover demo screenshot
http://jsfiddle.net/spicyj/q6hj7/

Обратите внимание, что текущее время оказывается в пределах на пирог React компонент, который обновляет каждый второй.


Как был создан этот popover?

Я исправил Bootstrap popover's setContent method, чтобы взять компонент React в дополнение к HTML или текстовой строке. Вместо того, чтобы использовать 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 для вас, включая правильную очистку компонентов popover после удаления компонента-оболочки из DOM.

+0

В вашем первом примере для рендеринга статического popover 'React.renderComponentToString' имеет [асинхронный API, который возвращает разметку через обратный вызов] (http://facebook.github.io/react/docs/top-level- api.html # react.rendercomponenttostring) (хотя фактическая реализация не является асинхронной, но API разработан таким образом в случае необходимости в будущем). Таким образом, вам нужно будет изменить это на 'React.renderComponentToString (, function (markup) {$ (this.getDOMNode()). Popover ({html: true, content: markup});} .bind (this)); '. –

+1

Спасибо, только что исправлено. –

+0

(React v0.9 изменил 'React.renderComponentToString', чтобы иметь синхронный API, просто обновил пример соответственно.) –

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> 
    ); 

}, 
0

После отправил этот ответ, и испытав и работал немного с этой работой, вокруг, я понимаю, что это не является оптимальным.

Выпадающее меню Bootstrap закрывается, как только пользователь взаимодействует с ним. Это может быть не желаемое поведение (в моем случае, я вставляю datepicker, и пользователь не может изменить месяц без необходимости повторного открытия меню, чтобы выбрать новую дату).


У меня была такая же проблема, и я придумал легкое и альтернативное решение.

Я не хотел использовать реакцию-бутстрап (другие части моего приложения не подвергаются реактированию и не используют бутстрап, поэтому я не хочу, чтобы две библиотеки делали то же самое).

Выпадающий компонент, предоставленный из коробки 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) класс «выпадающий список» на обертке div, (ii) атрибут «перетаскивание» данных в триггер (вы можете изменить триггер на любой элемент html, который вы хотите), и (iii) класс «выпадающий список», меню "в раскрывающемся списке (вы также можете изменить его на любой элемент html, который вы хотите, и вам не нужно вставлять элемент« ul », предложенный Bootstrap).

Вы потеряете несколько функций по сравнению с popover (вы не можете определить свои собственные переходы, вы не можете отображать их сверху, влево или вправо, но только ниже - это выпадающий список), но вы получаете полный контроль над содержимое вашего раскрывающегося списка/popover.

Смежные вопросы