1

如何使用 Scala.js React 库从 React Bootstrap 库创建模态组件?

4

1 回答 1

1

Modal 必须更改状态(显示 = true/false)以显示/隐藏对话框这一事实使得解决方案变得不简单。我通过将它包装在一个具有可以更改的布尔状态的组件中来解决这个问题 - 当它需要显示/隐藏时,我会更改具有不纯效果的状态。

另一个问题是,如果 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()
  }
}

以及使用它的 Dialog 对象:

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
  }
}
于 2019-07-10T07:42:59.227 回答