Representar un componente de React dentro de una ventana emergente Bootstrap
-
21-12-2019 - |
Pregunta
Tengo un conjunto de imágenes que tienen ventanas emergentes usando el componente de interfaz de usuario emergente de arranque en el atributo/parámetro de contenido. Me gustaría agregar el componente ReactJS MusicList pero no pude entender la sintaxis o si es posible o no.
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} />
);
}
});
Solución
Bootstrap no facilita la representación de un componente dinámico dentro de una ventana emergente.Si el popover que desea presentar es estático, simplemente puede usar React's renderComponentToString
que toma un componente y devuelve una cadena de HTML a través de una devolución de llamada:
var html = React.renderComponentToString(<MusicList />);
$(this.getDOMNode()).popover({
html: true,
content: html
});
Sin embargo, si su componente tiene interactividad, esa estrategia no funcionará porque React nunca tiene la oportunidad de adjuntar controladores de eventos (o ejecutar cualquiera de sus métodos de ciclo de vida personalizados).De hecho, Bootstrap no proporciona los ganchos adecuados para hacer que su contenido emergente sea dinámico.
Dicho esto, es posible hacer que esto funcione parcheando Bootstrap.Creé una demostración en vivo que tiene contenido emergente dinámico:
http://jsfiddle.net/spicyj/q6hj7/
Tenga en cuenta que la hora actual se representa dentro de la ventana emergente mediante un componente de React que se actualiza cada segundo.
¿Cómo se creó este popover?
yo parcheé Bootstrap popover setContent
método para tomar un componente de React además de una cadena de texto o HTML.En lugar de usar jQuery html
o text
métodos que uso 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]);
}
};
Ahora es posible que escribas
$(this.getDOMNode()).popover({
react: true,
content: <MusicList />
});
en tus componentDidMount
método y hacer que se procese correctamente.Si miras en el JSFiddle vinculado, verás un archivo de propósito general <BsPopover />
contenedor que hice que se encarga de todas las llamadas de Bootstrap por usted, incluida la limpieza adecuada de los componentes emergentes una vez que el componente contenedor se elimina del DOM.
Otros consejos
Hay una nueva biblioteca llamada React-Bootstrap que está experimentando un desarrollo rápido.
https://react-bootstrap.github.io/components.html#popovers
React.Render (PosicionInstance, MountNode);
ShowMoreDails: Función (obj, columnas) {
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>
);
},
Después de haber publicado esta respuesta y haber probado y trabajado un poco con este trabajo, me doy cuenta de que no es óptimo.
Menús desplegable Bootstrap Close tan pronto como el usuario haya interactuado con él. Este podría no ser el comportamiento deseado (en mi caso, estoy insertando un DatePicker y el usuario no puede cambiar el mes sin tener que volver a abrir el menú para elegir la nueva fecha).
Tuve el mismo problema y me fui de una solución fácil y alternativa.
No quería usar React-Bootstrap (otras partes de mi aplicación no reactificaron y usarlo bootstrap, por lo que no quiero tener dos bibliotecas haciendo lo mismo).
El componente desplegable provisto de la caja por Bootstrap casi proporciona las mismas funcionalidades que la popover, excepto que es mucho más flexible. Este es el desplegable de arranque estándar:
<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>
Aquí es el mínimo que necesita para que funcione sin romperlo y puede incluir el elemento reaccionar dentro de él:
<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>
Todo lo que necesita para mantener es (i) la clase "desplegable" en el DIV de Wrapper, (ii) el atributo de palanca de datos "desplegable" en el gatillo (puede cambiar su activador a cualquier elemento HTML que desee) y (iii) el "menú desplegable" de la clase en el menú desplegable (también puede cambiarlo a cualquier elemento HTML que desee y no tiene que pegar el elemento "UL" propuesto por Bootstrap).
pierde algunas características en comparación con la popover (no puede definir sus propias transiciones, no puede mostrarlas en la parte superior, izquierda o derecha, pero solo a continuación, es un desplegable) pero obtiene un control total sobre el contenido de su desplegable / popover.
Otra forma de resolver esto para incluir el componente de reacción que desea ser el contenido de Popover en la función de renderización del componente que contiene la popover (es decir, 'la página'), pero colóquela dentro de un div que el estilo "se muestra: ninguno;"Así que eso no se muestra y no se ocupa de ningún espacio, sino que también le dé una identificación, por ejemplo.'PopoVovercontent'.Luego, cuando inicializa el contenido del conjunto de popover: document.getlementbyid ("PopoVoverContent").En Bootstrap 4 al menos, se necesita un elemento como contenido.
No es necesario modificar el código de bootstrap de esta manera, facilitando el mantenimiento / actualizaciones.