Javascript 如何在Elm中创建有状态、模块化、自包含的web组件?
假设您想要创建一个有3个按钮的UI。单击其中一个按钮时,其他按钮将被释放。在JavaScript中,您可以编写:Javascript 如何在Elm中创建有状态、模块化、自包含的web组件?,javascript,elm,Javascript,Elm,假设您想要创建一个有3个按钮的UI。单击其中一个按钮时,其他按钮将被释放。在JavaScript中,您可以编写: var元素=[“Foo”、“Bar”、“Tot”].map(函数(名称){ var元素=document.getElementById(名称); element.onclick=function(){ elements.map(函数(元素){ element.className='button'; }); element.className='按钮已选定'; }; 返回元素; })
var元素=[“Foo”、“Bar”、“Tot”].map(函数(名称){
var元素=document.getElementById(名称);
element.onclick=function(){
elements.map(函数(元素){
element.className='button';
});
element.className='按钮已选定';
};
返回元素;
});代码>
。按钮{
边框:1px纯黑;
光标:指针;
保证金:4倍;
填充:4px;
}
.选定{
背景色:#DDDDDD;
}
福
酒吧
托特
这是同一事物的另一个版本:)
Elm可以满足这些需求中的每一个,使您的组件具有状态、模块化、自包含和纯粹的特性。以下是Elm中使用的示例(请原谅内联样式):
import StartApp.Simple exposing(开始)
导入Html(Html、div、span、text)
导入Html.Attributes(id、类、样式)
导入Html.Events(onClick)
类型别名模型=
{元素:列表字符串
,选中:可能是字符串
}
init:模型
初始化=
{元素=[“Foo”,“Bar”,“Tot”]
,selected=Nothing
}
类型动作
=选择字符串
更新:操作->模型->模型
更新动作模型=
案例诉讼
选择s->
{model | selected=Just s}
视图:Signal.Address操作->模型->Html
视图地址模型=
让
btn文本=
跨度
[id txt
,按钮样式
,onClick地址[]
只是s->
如果s==txt,则
[(“背景色”和“#DDDDDD”)]
其他的
[]
在里面
div[]我刚刚看到Chad的答案,当时我正在写我的答案。这个答案也使用了,但是在Html中使用了原始的类名,并且有一个“更强大的”模型。更强模型的优点在于,你可以看到你在问题中提到的三个位。id名称和实际按钮之间的隐式耦合也较少。但它会给你留下一些重复的名称,你可能想要,也可能不想要。这取决于你想要这种耦合的程度
import StartApp.Simple as StartApp
import Html as H exposing (Html)
import Html.Attributes as HA
import Html.Events as HE
type alias Model =
{ foo : Bool
, bar : Bool
, tot : Bool
}
type Action
= Foo
| Bar
| Tot
model : Model
model =
{ foo = False
, bar = False
, tot = False
}
update : Action -> Model -> Model
update clicked _ =
case clicked of
Foo -> { model | foo = True }
Bar -> { model | bar = True }
Tot -> { model | tot = True }
view : Signal.Address Action -> Model -> Html
view addr { foo, bar, tot } =
[ foo, bar, tot ]
|> List.map2 (viewButton addr) buttons
|> H.div []
buttons : List (String, Action)
buttons =
[ ("Foo", Foo)
, ("Bar", Bar)
, ("Tot", Tot)
]
viewButton : Signal.Address Action -> (String, Action) -> Bool -> Html
viewButton addr (id, action) selected =
H.span
[ HA.id id
, HA.classList
[ ("button", True)
, ("selected", selected)
]
, HE.onClick addr action
]
[ H.text id
]
buttonStyle =
main =
StartApp.start
{ model = model
, view = view
, update = update
}
正如devdave所建议的,嵌套是我发现的模块化组件的唯一方法
我已经实现了一个类似的示例,您可以在这里看到:
其思想是子函数公开函数以获取其自身模型的属性。这些函数反过来可以为子组件调用更多嵌套函数
查看本回购协议的Readme.md
,了解代码示例:
抱歉,但这些答案都没有解释最重要的一点:这是如何模块化的?即,你如何能够将应用程序包含在另一个应用程序中?需要何种状态泵送?抱歉,但这些答案都没有解释最重要的一点:这是如何模块化的?即,你如何能够将应用程序包含在另一个应用程序中?什么状态指示泵送是必要的?@Viclib-看一看。示例1构建了一个简单的组件,然后以下示例以模块化的方式构建该组件。我发布的示例也可以这样做,但教程更详细。Elm体系结构教程上的示例不是模块化的。使用计数器需要手动将计数器的状态存储在其自己的模型上。经过足够的层之后,站点的顶级模型将成为一个巨大的平面ADT,并提及每个子模型的每个模式。想象一下:“data MySiteAdt=……state_of the_button_inside_the_other_div_inside_the_menu:IsSelected…”。这不是模块化的工作方式。父应用程序不需要有许多内部应用程序模型规范的副本。诚然,教程中描述的模块化会冒泡,因此您必须在所有父应用程序中考虑子状态。但这是使用StartApp。如果您放弃StartApp,直接使用端口,您可以实现ve更细粒度的模块化你说直接进入端口是什么意思?抱歉,但这些答案都没有解释最重要的一点:这是如何模块化的?即,你如何能够将应用程序包含在另一个应用程序中?需要什么样的状态泵送?你使用嵌套模块化Elm应用程序。因此,你有一个顶级的应用程序组件a使用更新和查看函数。然后,您可以通过在顶层模型记录中为其状态提供一个条目、一个ChildAction类型、一个更新函数中的条目(将ChildAction操作发送到子对象的更新方法)以及一个Signal.forwardTo标记子对象中的操作,将“子模块”嵌套在该子模块中。老实说,它的目前有很多重复的样板文件可以让它工作。我正在寻找一种方法来抽象它,但还没有发现任何优雅的东西。在Elm体系结构中,每个组件都依赖于它的直接子组件,但既不依赖于它的父组件,也不依赖于它的间接子组件。这就是可重用性:你可以在任何其他组件中使用任何组件,耦合将仅限于与子组件通信的父级。要实现模块化,您可能意味着,您必须提取组件中的通用功能,以便有通用的init update view函数,这些函数记录表示组件的各种功能。
import StartApp.Simple as StartApp
import Html as H exposing (Html)
import Html.Attributes as HA
import Html.Events as HE
type alias Model =
{ foo : Bool
, bar : Bool
, tot : Bool
}
type Action
= Foo
| Bar
| Tot
model : Model
model =
{ foo = False
, bar = False
, tot = False
}
update : Action -> Model -> Model
update clicked _ =
case clicked of
Foo -> { model | foo = True }
Bar -> { model | bar = True }
Tot -> { model | tot = True }
view : Signal.Address Action -> Model -> Html
view addr { foo, bar, tot } =
[ foo, bar, tot ]
|> List.map2 (viewButton addr) buttons
|> H.div []
buttons : List (String, Action)
buttons =
[ ("Foo", Foo)
, ("Bar", Bar)
, ("Tot", Tot)
]
viewButton : Signal.Address Action -> (String, Action) -> Bool -> Html
viewButton addr (id, action) selected =
H.span
[ HA.id id
, HA.classList
[ ("button", True)
, ("selected", selected)
]
, HE.onClick addr action
]
[ H.text id
]
buttonStyle =
main =
StartApp.start
{ model = model
, view = view
, update = update
}