如何将 class 添加到 elm 脚本中 table 的所有列

how to add class to all columns of a table in elm script

elm 脚本从后端代码中获取一个 csv 字符串 csv。我想创建一个 table 和 每个单元格的 class 名称应该是列名称 .

table行可以从rows = String.split "\n" csv获取。如果我不需要定义 classes,可以通过在 rows 上应用双重嵌套 List.map 来创建 table。但是为了给每个单元格提供 class,我需要保存包含列(或 class)名称的行的第一个元素,并将它与剩余的每一行配对。由于 elm 中没有 for 循环,我的策略是定义一个递归函数来创建所有 tr 元素并使用 List.map 连接 tr 元素。此函数的输入是名为 names 的第一行和名为 cols 的另一行。他们都是List String。每次运行时,它都会使用两个列表的头部(来自List.head)创建一个td,然后将两个列表的剩余元素(来自List.drop)传递给递归。但是我无法连接两个返回的组件。

createRow names cols =
    case cols of
        [] -> text ""
        _ ->
            let
                c0 = (List.head cols)
                c = (List.drop 1 cols)
                n0 = (List.head names)
                n = (List.drop 1 names)
            in
                td [] [text <| toString <| c0]
                , createRow n c 

我应该在 in 块中放什么?还是有更好的方法来达到我的目的?

在递归函数中,您需要传递(部分计算的)结果,以便您可以在每次调用中修改它,并且 return 一旦您完成递归。所以这可能看起来像这样:

createRow : List String -> List String -> List (Html msg) -> List (Html msg)
createRow names cols cells =
    case cols of 
        [] -> cells
        col :: remainingCols ->
            let
                name = 
                    names
                    |> List.head
                    |> Maybe.withDefault ""
                remainingNames = List.drop 1 names
                cell =
                    td [class name] [text col]
            in
            createRow remainingNames remaningCols (cells ++ [ cell ])

这里还有一些其他值得注意的变化:

  • 我使用模式匹配从其余部分(也称为尾部)中提取 cols 列表的头部
  • List.head returns a Maybe a(在本例中,aString),所以我添加了对 [=16 的调用=]
  • 因为cols是一个List String,你不需要调用toString,可以直接传递给text
  • 当您第一次调用此函数时,您将为 cells 参数传入 []

首先,我建议您不要手动解析 CSV。包管理器上有多个 CSV 解析器可用,因此我们可以专注于如何处理这些值。

https://package.elm-lang.org/packages/periodic/elm-csv/latest/Csv 是一个选项,但是它们在解析后都给你一个 Csv 类型,看起来像这样:

type alias Csv =
    { headers : List String
    , records : List (List String)
    }

正如您所提到的,每行中的值与 headers 一样多(否则 CSV 将无效)。 Dropping/casing 通过递归可以完成工作,但我们可以通过依赖列表操作来完成大部分工作,从而更具声明性:

classTable : Csv -> Html msg
classTable csv =
    table []
        (csv.records |> List.map (tableRow csv.headers))


tableRow : List String -> List String -> Html msg
tableRow headers values =
    let
        insertNextCellInRow ( header, value ) row =
            td [ class header ] [ text value ] :: row
    in
    tr []
        (List.map2 Tuple.pair headers values
            |> List.foldr insertNextCellInRow []
        )

注意:List.foldr 是递归的,用于命令式语言 ("for each item in this list, apply this function and collect the results in this other list") 中的循环。然而,它不知道传递给它的值的类型,并允许我们专注于转换值。