转换 Html DOM

Transform Html DOM

我是 Elm 的新手,到目前为止我真的很喜欢它,但是我 运行 遇到了一个我似乎无法解决的问题。

我有一个HtmlDOM,例如

div []
  [ h1 [] [text "Headline 1"]
  , p [] [text "Some text"]
  , h2 [] [text "Headline 2"]
  ]

我想在每个 h[1-6] 元素中添加 a-links 并将其转换为类似(保持简单)

div []
  [ h1 [] [ text "Headline 1"
          , [a [name "headline"] [text "#"]
          ]
  , p [] [text "Some text"]
  , h2 [] [text "Headline 2"
          , [a [name "headline"] [text "#"]
          ]
  ]

这在概念上并不难。查看DOM,如果元素是h[1-6],添加一个a-link作为子元素。然而,我对 Elm 的理解还不足以让它工作。

这是我到目前为止一直在尝试的方法。

transform : Html a -> Html a
transform node =
    -- check if the tag is h1-h6
    case node.tag of
        -- add a-link to h1 children
        "h1" -> { node | children = (a [name "headline"] [text "#") :: node.children }
        "h2" -> { node | children = (a [name "headline"] [text "#") :: node.children }
        -- do this for all nodes in the tree
        _ -> { node | children = List.map transform node.children }

这行不通。

The type annotation for `transform` does not match its definition.

40| transform : Html a -> Html a
                ^^^^^^^^^^^^^^^^
The type annotation is saying:

    VirtualDom.Node a -> VirtualDom.Node a

But I am inferring that the definition has this type:

    { b | tag : String, children : List (Html a) }
    -> { b | children : List (Html a), tag : String }

我知道我不能 node.tag 因为通用类型 a 可能没有那个字段。它不会是类型安全的。例如,文本节点没有标签字段,但仍然是 Html.Html a.

的实例
> text "Hello World"
{ type = "text", text = "Hello World" } : Html.Html a

我的问题是,我该怎么做?我可以这样做吗?还是我不应该这样做?

无法修改 Html msg 类型的现有值。

它们是最终的内部结构,由 Virtual DOM 渲染到实际的 HTML 节点中作为程序的输出。

Html msgVirtualDom.Node a

的别名

您正试图将它们用作记录,但那只是一个 JavaScript 对象。

Elm REPL 在此处输出抽象数据结构的字符串表示:

> text "Hello World"
{ type = "text", text = "Hello World" } : Html.Html a -- not a record

与其尝试转换 Html msg -> Html msg,不如尝试这样的操作:

-- Input example: [ "#", "http://google.com/", "http://package.elm-lang.org/" ]

linksView : List String -> Html msg
linksView links =
    links
        |> List.map (\link -> a [ href link ] [ text link ])
        |> div [] -- Expected output: <div> with thre links

在 Elm 中,Html a 实际上只用作输出。您永远不会像 transform 函数尝试的那样将其用作输入。

创建一个模型来描述您的域,然后将其传递给 view 函数以呈现 html。

会更好地为您服务
type alias Article =
  { priority : Priority
  , headline : String
  , body : String
  }

type alias Model =
  List Article

type Priority = First | Second

您的视图可能如下所示:

view : Model -> Html msg
view =
  div [] << List.map viewArticle

viewArticle : Article -> Html msg
viewArticle article =
  let
    priorityTag =
      case article.priority of
        First -> h1
        Second -> h2
  in
    div []
      [ priorityTag []
        [ text article.headline
        , a [ name "headline" ] [ text "#" ]
        ]
      , p [] [ text article.body ]
      ]