我将如何使用 Scala Js React 构建 Bootstrap React Modal
How would I build a Bootstrap React Modal using Scala Js React
我如何使用 Scala.js React 库从 React Bootstrap 库创建一个 Modal 组件?
模态框必须将状态 (show = true/false) 更改为 show/hide 对话框这一事实构成了解决方案 non-trivial。我通过将它包装在一个组件中来解决这个问题,该组件具有可以更改的布尔状态 - 当它需要 shown/hidden 时,我会更改效果不纯的状态。
另一个问题是,如果 Modal 具有需要更改状态的按钮,则它们的事件处理程序需要以某种方式访问此状态。我通过在创建时授予组件用户访问组件后端的权限解决了这个问题。
这是我对模态的实现:
class Modal(bs: BackendScope[Unit, Boolean], onHide: => Unit, children: Modal => Seq[ChildArg]) {
def render(show: Boolean) = {
val props = (new js.Object).asInstanceOf[Modal.Props]
props.show = show
props.onHide = () => {
dismiss()
onHide
}
Modal.component(props)(children(this): _*)
}
def dismiss() = {
bs.withEffectsImpure.setState(false)
}
}
object Modal {
@JSImport("react-bootstrap", "Modal")
@js.native
object RawComponent extends js.Object
@js.native
trait Props extends js.Object {
var show: Boolean = js.native
var onHide: js.Function0[Unit] = js.native
}
val component = JsComponent[Props, Children.Varargs, Null](RawComponent)
type Unmounted = Scala.Unmounted[Unit, Boolean, Modal]
def apply(onHide: => Unit = Unit)(children: Modal => Seq[ChildArg]): Unmounted = {
val component = ScalaComponent.builder[Unit]("Modal")
.initialState(true)
.backend(new Modal(_, onHide, children))
.renderBackend
.build
component()
}
}
以及使用它的对话框对象:
object Dialog {
object Response extends Enumeration {
type Response = Value
val OK, CANCEL = Value
}
import Response._
def prompt(title: String, body: String, okText: String): Future[Response] = {
// Add an element into which we render the dialog
val element = dom.document.body.appendChild(div(id := "dialog").render).asInstanceOf[Element]
// Create a promise of a return and a method to send it
val p = Promise[Response]
def respond(ret: Response) = {
// Remove the containing element and return the response
dom.document.body.removeChild(element)
p.success(ret)
}
Modal(respond(Response.CANCEL)) { modal =>
// Function to dismiss the dialog and respond
def quit(ret: Response) = {
modal.dismiss()
respond(ret)
}
// Create the components for our Modal
Seq(
ModalHeader(true,
ModalTitle(title)
),
ModalBody(body),
ModalFooter(
Button(variant = "secondary", onClick = () => { quit(Response.CANCEL) })("Cancel"),
Button(variant = "primary", onClick = () => { quit(Response.OK) })(okText)
)
)
}.renderIntoDOM(element).backend
p.future
}
}
我如何使用 Scala.js React 库从 React Bootstrap 库创建一个 Modal 组件?
模态框必须将状态 (show = true/false) 更改为 show/hide 对话框这一事实构成了解决方案 non-trivial。我通过将它包装在一个组件中来解决这个问题,该组件具有可以更改的布尔状态 - 当它需要 shown/hidden 时,我会更改效果不纯的状态。
另一个问题是,如果 Modal 具有需要更改状态的按钮,则它们的事件处理程序需要以某种方式访问此状态。我通过在创建时授予组件用户访问组件后端的权限解决了这个问题。
这是我对模态的实现:
class Modal(bs: BackendScope[Unit, Boolean], onHide: => Unit, children: Modal => Seq[ChildArg]) {
def render(show: Boolean) = {
val props = (new js.Object).asInstanceOf[Modal.Props]
props.show = show
props.onHide = () => {
dismiss()
onHide
}
Modal.component(props)(children(this): _*)
}
def dismiss() = {
bs.withEffectsImpure.setState(false)
}
}
object Modal {
@JSImport("react-bootstrap", "Modal")
@js.native
object RawComponent extends js.Object
@js.native
trait Props extends js.Object {
var show: Boolean = js.native
var onHide: js.Function0[Unit] = js.native
}
val component = JsComponent[Props, Children.Varargs, Null](RawComponent)
type Unmounted = Scala.Unmounted[Unit, Boolean, Modal]
def apply(onHide: => Unit = Unit)(children: Modal => Seq[ChildArg]): Unmounted = {
val component = ScalaComponent.builder[Unit]("Modal")
.initialState(true)
.backend(new Modal(_, onHide, children))
.renderBackend
.build
component()
}
}
以及使用它的对话框对象:
object Dialog {
object Response extends Enumeration {
type Response = Value
val OK, CANCEL = Value
}
import Response._
def prompt(title: String, body: String, okText: String): Future[Response] = {
// Add an element into which we render the dialog
val element = dom.document.body.appendChild(div(id := "dialog").render).asInstanceOf[Element]
// Create a promise of a return and a method to send it
val p = Promise[Response]
def respond(ret: Response) = {
// Remove the containing element and return the response
dom.document.body.removeChild(element)
p.success(ret)
}
Modal(respond(Response.CANCEL)) { modal =>
// Function to dismiss the dialog and respond
def quit(ret: Response) = {
modal.dismiss()
respond(ret)
}
// Create the components for our Modal
Seq(
ModalHeader(true,
ModalTitle(title)
),
ModalBody(body),
ModalFooter(
Button(variant = "secondary", onClick = () => { quit(Response.CANCEL) })("Cancel"),
Button(variant = "primary", onClick = () => { quit(Response.OK) })(okText)
)
)
}.renderIntoDOM(element).backend
p.future
}
}