如何将 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
(在本例中,a
是 String
),所以我添加了对 [=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") 中的循环。然而,它不知道传递给它的值的类型,并允许我们专注于转换值。
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 aMaybe a
(在本例中,a
是String
),所以我添加了对 [=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") 中的循环。然而,它不知道传递给它的值的类型,并允许我们专注于转换值。