如何在寓言中切换显示/隐藏元素?

时间:2018-12-25 10:41:58

标签: html f# togglebutton fable-f#

我想在寓言中有一个琐碎的显示/隐藏内容行为。 类似于this

function myFunction() {
  var x = document.getElementById("myDIV");
  if (x.style.display === "none") {
    x.style.display = "block";
  } else {
    x.style.display = "none";
  }
}
<button onclick="myFunction()">Click Me</button>

<div id="myDIV">
  This is my DIV element.
</div>

最合适的方法是什么?

2 个答案:

答案 0 :(得分:5)

这是一个比您意识到的要大得多的问题,因为在下面是“我应该如何最好地安排我的寓言应用程序”的问题?您在答案中采用的方法与在Javascript应用程序中使用JQuery大致平行:您编写直接操纵DOM以获得所需结果的代码。如果那是您选择的建筑风格-对于真正简单的应用程序,这是一个完美的选择-那么您的答案就不会有太多改善。 “直接操作DOM”方法唯一会遇到问题的情况是,您的应用程序的大小会变得比平凡大。届时,您将需要一个更好的体系结构。稍后我将推荐一个更好的体系结构,但首先,我建议对您的代码进行一些细微调整。将toggle函数移到toggleButton之外将使其更加通用:

module Markup

open System
open Fable.Helpers.React
open Fable.Helpers.React.Props
open Fable.Import

let toggleBlockElem id _ = 
    let contentElement = Browser.document.getElementById id
    let display = if contentElement.style.display = "none" then "block" else "none"
    contentElement.style.display <- display

let toggleButton text content =
    let id = Guid.NewGuid().ToString()

    div [] 
        [
            button [ OnClick (toggleBlockElem id) ] [ str text ]
            div [ Id id ] [ str content ]
        ]

如果您发现自己需要这些功能,可以在toggleLinktoggleCheckbox之类的函数中重复使用此功能。

现在,我之前提到过,如果您的Web应用程序变大,我会建议使用其他体系结构。我推荐的架构是Elmish。它基于Elm中使用的体系结构;如果您不熟悉它,其基本思想类似于React。这是一个模型/更新/视图架构。 模型是一个不变的数据结构。还定义了消息类型;在Elmish中,这可能是F#歧视的工会。 更新函数将模型和消息作为两个参数,并返回一个新模型。 view 函数采用一个模型和一个“ dispatch ”函数作为其两个参数(Elmish将提供“ dispatch”函数,您不必编写它)并返回类似HTML元素的抽象树。然后,Elmish将这些元素传递给诸如React之类的东西,以进行实际的DOM更新。 (实际上,根据Elm的the one described here过程,反应将区分“旧” DOM树和“新” DOM树)。

所有这些都需要花很多钱,因此让我们看一个简单的示例,该示例仅切换div的可见性。 注意:我尚未对此进行测试,只是将其输入到“堆栈溢出”答案框中。以下代码中可能存在错误;它仅是说明性示例,而不是工作示例。 (有关运行中的Elmish的一个非常详尽的工作示例,请参见https://mangelmaxime.github.io/fulma-demo/ -尽管请注意,该示例具有在数据模型中包含多个父子层次结构“层”的高级体系结构,可能很难包装您的乍一看。

让我们从定义数据模型开始。由于这是一个简单的示例,因此该模型同样是简单的。实际上,这很琐碎,我将向其中添加一些额外的数据,以便使用记录类型而不是单个布尔值实际上是有意义的:

type Model = { Visible: bool;
               DataNotAppearingInThisFilm: int }

(更高级的模型可能涉及Map<string, bool>类型,以跟踪多个div的可见状态)。

消息类型也是微不足道的,因此为了使它有趣一点,我们将允许“显示”,“隐藏” “切换”消息:

type Msg =
    | Show
    | Hide
    | Toggle

(更高级的版本是Show of string等,将div的ID传递给显示)。

update函数同样简单:

let update msg model =
    match msg with
    | Show -> { model with Visible = true }
    | Hide -> { model with Visible = false }
    | Toggle -> { model with Visible = not model.Visible }

最后,view函数将如下所示:

let view model dispatch =
    div [] 
        [
            button [ OnClick (fun _ -> dispatch Toggle) ] [ str (if model.Visible then "Hide" else "Show") ]
            div [ Display (if model.Visible then "block" else "none") ] [ str "content" ]
        ]

或者,将toggleButton拉出自己的功能,以便我可以演示其工作原理:

let toggleButton dispatch text content =
    div [] 
        [
            button [ OnClick (fun _ -> dispatch Toggle) ] [ str text ]
            div [ Display (if model.Visible then "block" else "none") ] [ str content ]
        ]

let view model dispatch =
    div []
        [
            str "Other elements might go here"
            toggleButton dispatch (if model.Visible then "Hide" else "Show") "content"
        ]

请注意我需要如何将dispatch函数作为参数传递给toggleButton,以便toggleButton能够为其OnClick构造正确的行为。

将所有这些放在一起看起来像这样:

open ALotOfModules

type Model = { Visible: bool;
               DataNotAppearingInThisFilm: int }

type Msg =
    | Show
    | Hide
    | Toggle

let update msg model =
    match msg with
    | Show -> { model with Visible = true }
    | Hide -> { model with Visible = false }
    | Toggle -> { model with Visible = not model.Visible }

let toggleButton dispatch text content =
    div [] 
        [
            button [ OnClick (fun _ -> dispatch Toggle) ] [ str text ]
            div [ Display (if model.Visible then "block" else "none") ] [ str content ]
        ]

let view model dispatch =
    div []
        [
            str "Other elements might go here"
            toggleButton dispatch (if model.Visible then "Hide" else "Show") "content"
        ]

答案 1 :(得分:0)

我的最佳尝试是从问题链接中愚蠢地翻译JavaScript:

module Markup

open System
open Fable.Helpers.React
open Fable.Helpers.React.Props
open Fable.Import

let toggleButton text content =
    let id = Guid.NewGuid().ToString()

    let toggle _ = 
        let contentElement = Browser.document.getElementById id
        let display = if contentElement.style.display = "none" then "block" else "none"
        contentElement.style.display <- display

    div [] 
        [
            button [ OnClick toggle ] [ str text ]
            div [ Id id ] [ str content ]
        ]

要像Markup.toggleButton "title" "a lot of content"

一样使用