【问题标题】:How to toggle show/hide element in Fable?如何在寓言中切换显示/隐藏元素?
【发布时间】:2019-05-24 02:21:42
【问题描述】:

我想在 Fable 中有一个简单的显示/隐藏内容行为。 类似于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>

最合适的方法是什么?

【问题讨论】:

    标签: html f# togglebutton fable-f#


    【解决方案1】:

    这是一个比您意识到的要大得多的问题,因为在它下面是“我应该如何最好地安排我的 Fable 应用程序”的问题?您在回答中采用的方法与在 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 等函数中重用此函数。

    现在,我之前提到过,如果您的网络应用程序变大,我会推荐一种不同的架构。我推荐的架构是Elmish。它基于Elm 中使用的架构;如果你不熟悉它,其基本思想类似于 React。这是一个模型/更新/视图架构。 模型 是不可变的数据结构。还定义了一个 message 类型;在 Elmish 中,这可能是一个 F# 区分联合。 update 函数将模型和消息作为其两个参数,并返回一个新模型。 view 函数接受一个模型和一个“dispatch”函数作为它的两个参数(“dispatch”函数将由 Elmish 提供,你不必编写它) 并返回类似 HTML 元素的抽象树。 Elmish 然后将这些元素传递给 React 之类的东西来进行实际的 DOM 更新。 (本质上,React 将区分“旧”DOM 树和“新”DOM 树,其过程很像 Elm 的 the one described here)。

    所有这些都需要考虑,所以让我们看一个简单的示例,它只是切换div 的可见性。 注意:我没有对此进行测试,只是将它输入到 Stack Overflow 答案框中。下面的代码可能存在错误;它旨在作为说明性示例而不是工作示例。 (有关 Elmish 的一个非常全面的实际工作示例,请参阅 https://mangelmaxime.github.io/fulma-demo/ - 尽管请注意,该示例具有一个高级架构,在数据模型中包含了多个父子层次结构的“层”,并且可能很难将您的想法包裹起来乍一看)。

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

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

    (更高级的模型可能涉及Map&lt;string, bool&gt; 类型以跟踪多个divs 的可见状态)。

    消息类型也很简单,所以为了让它更有趣,我们将允许“显示”、“隐藏”“切换”消息:

    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"
            ]
    

    【讨论】:

    • 评论框中的占位符说要避免在这里写“感谢您的出色回答”,但您明白了。
    • 嗯,实际上我对 Elmish 有点熟悉,因为我什至在我的应用程序中使用它(没有我对它的深刻理解,是的)。我只是懒得为这么简单的事情介绍新的模型和信息,想看看社区的意见。好吧,现在我知道混合架构可能是我能做的最糟糕的事情,而正确地实现东西并不是这样的 PITA。所以,是的,很棒的答案,它有帮助。
    【解决方案2】:

    我最好的尝试是从问题中的链接中笨拙地翻译 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"一样使用

    【讨论】:

      猜你喜欢
      • 2022-12-20
      • 1970-01-01
      • 2017-08-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-02
      相关资源
      最近更新 更多