Rendering di un componente React all'interno di un popover Bootstrap
-
21-12-2019 - |
Domanda
Ho una serie di immagini con popover che utilizzano il componente bootstrap popover ui nell'attributo/parametro del contenuto. Vorrei aggiungere il componente ReactJS MusicList ma non sono riuscito a capire la sintassi o se sia possibile o meno.
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} />
);
}
});
Soluzione
Bootstrap non semplifica il rendering di un componente dinamico all'interno di un popover.Se il popover che vuoi presentare è statico, puoi semplicemente usare quello di React renderComponentToString
che prende un componente e restituisce una stringa HTML tramite un callback:
var html = React.renderComponentToString(<MusicList />);
$(this.getDOMNode()).popover({
html: true,
content: html
});
Tuttavia, se il tuo componente ha interattività, quella strategia non funzionerà perché React non ha mai la possibilità di collegare gestori di eventi (o eseguire nessuno dei tuoi metodi personalizzati del ciclo di vita).In effetti, Bootstrap non fornisce gli hook adeguati per rendere dinamico il contenuto popover.
Detto questo, è possibile farlo funzionare applicando una patch a Bootstrap.Ho creato una demo live con contenuti popover dinamici:
http://jsfiddle.net/spicyj/q6hj7/
Tieni presente che l'ora corrente viene visualizzata all'interno del popover da un componente React che si aggiorna ogni secondo.
Come è stato creato questo popover?
Ho patchato Popover di Bootstrap setContent
metodo per prendere un componente React oltre a una stringa HTML o di testo.Invece di usare jQuery html
O text
metodi che utilizzo 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]);
}
};
Ora è possibile per te scrivere
$(this.getDOMNode()).popover({
react: true,
content: <MusicList />
});
nel tuo componentDidMount
metodo e renderlo correttamente.Se guardi nel JSFiddle collegato, vedrai un file general-scopo <BsPopover />
wrapper che ho creato che si occupa di tutte le chiamate Bootstrap per te, inclusa la corretta pulizia dei componenti popover una volta rimosso il componente wrapper dal DOM.
Altri suggerimenti
C'è una nuova biblioteca chiamata react-bootstrap che è in fase di sviluppo rapido.
https://react-bootstrap.github.io/components.html#Popovers
react.render.Render (positionerinstance, mountnode);
SHOWMOREDETAILS: funzione (OBJ, COLONNS) {
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>
);
},
. Dopo aver pubblicato questa risposta e avendo testato e ha funzionato un po 'con questo lavoro, mi rendo conto che non è ottimale.
Menu Dropdown Bootstrap si chiude non appena l'utente ha interagito con esso. Questo potrebbe non essere il comportamento desiderato (nel mio caso, sto inserendo un datepicker e l'utente non può cambiare mese senza dover riaprire il menu per scegliere la nuova data).
.
Ho avuto lo stesso problema e ho inventato una soluzione facile e alternativa.
Non volevo usare React-bootstrap (altre parti della mia app non sono reattificate e usano Bootstrap, quindi non voglio avere due librerie facendo la stessa cosa).
Il componente a discesa Fornito dalla scatola tramite Bootstrap offre quasi le stesse funzionalità del popolover, tranne che è molto più flessibile. Questo è il Dropdown standard 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>
.
Ecco il minimo che devi farlo funzionare senza romperlo e puoi includere qualsiasi elemento reagire all'interno di esso:
<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>
.
Tutto quello che devi tenere è (i) la classe "Dropdown" sul div wrapper, (ii) L'attributo di interruzione dati "Dropdown" sul trigger (è possibile modificare il trigger su qualsiasi elemento HTML che si desidera) e (iii) il menu a discesa Classe "sul menu a discesa (puoi anche cambiarlo su qualsiasi elemento HTML desiderato e non è necessario attaccare l'elemento" UL "proposto da Bootstrap).
Si perde alcune funzionalità rispetto al Popover (non è possibile definire le tue transizioni, non puoi visualizzarle in cima, sinistra o destra, ma solo sotto - è un ascensore) ma ottieni il controllo totale sul contenuto del tuo dropdown / aofover.
Un altro modo per risolvere questo per includere il componente React che si desidera essere il contenuto di Popoover nella funzione di rendering del componente contenente il popover (cioè "la pagina") ma metterlo all'interno di un div con stile "display: nessuno;"Quindi non viene visualizzato e prende spazio, anche dargli un ID, ad es.'PopoverContent'.Quindi, quando inizializza il contenuto del set di Popoover: Document.getElementByID ("POTOVERContent").In Bootstrap 4 almeno, ci vuole un elemento come contenuto.
Non è necessario modificare il codice bootstrap in questo modo, facilitare la manutenzione / aggiornamenti.