Bootstrap ポップオーバー内で React コンポーネントをレンダリングする
-
21-12-2019 - |
質問
コンテンツ属性/パラメータでブートストラップポップオーバー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} />
);
}
});
解決
ブートストラップは、ポップオーバー内で動的コンポーネントをレンダリングすることを容易にしません。存在したいPopoverが静的である場合は、コンポーネントを取得するReactのrenderComponentToString
を単純に使用し、コールバックを介してHTML文字列を返します。
var html = React.renderComponentToString(<MusicList />);
$(this.getDOMNode()).popover({
html: true,
content: html
});
.
しかし、あなたのコンポーネントに対話性がある場合、その戦略は反応がイベントハンドラを添付する機会がない(またはカスタムライフサイクルメソッドのいずれかを実行する)ので機能しません。確かに、ブートストラップはポップオーバコンテンツを動的にするための適切なフックを提供しません。
それは言った、これはブートストラップをパッチすることによってこの作業をすることが可能です。動的ポップオーバーコンテンツを持つライブデモを作成しました:
http://jsfiddle.net/spicyj/q6hj7/
現在時刻は、2秒ごとに更新される反応成分によってポップオーバー内にレンダリングされます。
このポップオーバはどのように作成されましたか?
パッチブートストラップポップオーバーのPopoverのsetContent
メソッド 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 />
});
.
他のヒント
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);
私のコード:
詳細を表示:関数(obj, 列){
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>
);
},
この返信を投稿し、この回避策でテストされ、少し働いた後、私はそれが最適ではないことを理解しています。
ブートストラップドロップダウンメニューユーザーがそれと対話したらすぐに閉じます。これは望ましい行動ではないかもしれません(私の場合では、私はDatePickerを挿入していて、ユーザーはメニューを再度開くことなく月を変更することはできません)。
私は同じ問題を抱えていて、簡単で代替の解決策を思いついた。
私はReact-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>
.
これはあなたがそれを破壊せずに仕事をする必要がある最小値です、そしてあなたはその中のどちらかどちらでも含めることができます:
<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)ラッパー・ディビングのクラス "dropdown"(ii)トリガーのdata-treggle属性 "dropdown"(あなたが欲しいHTML要素に変更することができます) (iii)ドロップダウンの「ドロップダウンメニュー」クラス「希望のHTML要素に変更することもでき、BootStrapで提案されている「UL」要素をスティッキする必要はありません)。
ポップオーバーと比較していくつかの機能を緩めます(あなた自身の遷移を定義することはできません(あなた自身の遷移を定義することはできません、あなたはそれらを上、左または右に表示することはできません、しかしそれはドロップダウンです)ですが、それはドロップダウンです)あなたのドロップダウン/ポップオーバーの。
これを解決するためのもう1つの方法で、ポップオーバーを含むコンポーネントのレンダリング関数内のPopoverコンテンツになりたいです(つまり、 'ページ')がdivをスタイルで配置します "display:none;""そのため、表示されず、スペースを占有しないように、ID、例えばIDを与えます。'PopoverContent'。次に、ポップオーバーセットのコンテンツを初期化すると、Document.GetElementByID( "PopoverContent")。ブートストラップ4で少なくとも、コンテンツとして要素を取ります。
このようにブートストラップコードを変更する必要はなく、メンテナンス/更新を容易にします。