假设您要创建一个包含3个按钮的UI。当您单击其中一个时,其他人将被释放。在JavaScript中,您可以写:
var elements = ["Foo","Bar","Tot"].map(function(name){
var element = document.getElementById(name);
element.onclick = function(){
elements.map(function(element){
element.className = 'button';
});
element.className = 'button selected';
};
return element;
});
.button {
border: 1px solid black;
cursor: pointer;
margin: 4px;
padding: 4px;
}
.selected {
background-color: #DDDDDD;
}
<div>
<span id='Foo' class='button'>Foo</span>
<span id='Bar' class='button'>Bar</span>
<span id='Tot' class='button'>Tot</span>
</div>
这是有状态的,但不是模块化的,自包含的,也不是纯粹的。事实上,状态(三元位)甚至不是很明显。你不能将它注入另一个模型,你想要多少次。
到目前为止,这里提供的大多数答案都是有状态的,但不是模块化的。问题在于,使用该策略时,如果父母不知道孩子的模型,则不能将组件放在另一个中。理想情况下,这将被抽象掉 - 父母不应该在其自己的模型上提及子节点的模型,也不需要从父节点到节点的手动管道状态。如果我想创建上面的应用程序列表,我不想将每个子节点的状态存储在父节点上。
如何在Elm中创建有状态,模块化,自包含的Web组件?
答案 0 :(得分:3)
Elm可以满足这些要求,使您的组件具有状态,模块化,自包含和纯粹。这是Elm使用StartApp.Simple的一个例子(原谅内联样式):
import StartApp.Simple exposing (start)
import Html exposing (Html, div, span, text)
import Html.Attributes exposing (id, class, style)
import Html.Events exposing (onClick)
type alias Model =
{ elements : List String
, selected : Maybe String
}
init : Model
init =
{ elements = [ "Foo", "Bar", "Tot" ]
, selected = Nothing
}
type Action
= Select String
update : Action -> Model -> Model
update action model =
case action of
Select s ->
{ model | selected = Just s }
view : Signal.Address Action -> Model -> Html
view address model =
let
btn txt =
span
[ id txt
, buttonStyle txt
, onClick address <| Select txt
] [ text txt ]
buttonStyle txt =
style (
[ ("border", "1px solid black")
, ("cursor", "pointer")
, ("margin", "4px")
, ("solid", "4px")
] ++ (styleWhenSelected txt))
styleWhenSelected txt =
case model.selected of
Nothing -> []
Just s ->
if s == txt then
[ ("background-color", "#DDDDDD") ]
else
[]
in
div [] <| List.map btn model.elements
main =
start
{ model = init
, update = update
, view = view
}
您有一个明确定义的静态类型模型,可以针对该模型执行的显式且有限数量的操作,以及类型安全的html呈现引擎。
请查看Elm Architecture Tutorial了解详情。
答案 1 :(得分:1)
在我写作的时候,我只看到了查德的回答。这个也使用了Elm Architecture,但在Html中使用了原始的类名,并且具有更强的&#34;模型。关于更强大的模型的好处在于你真正看到了你在问题中提到的三位。 id的名称和实际按钮之间的隐式耦合也较少。但它会留下一些您可能想要或不想要的重复名称。取决于你想要这种耦合的程度。
public static ArrayList<SimilarDogs> buildDogGroups(ArrayList<Dog> dogs){
ArrayList<SimilarDogs> similarDogGroups = new ArrayList<SimilarDogs>();
//Generate a KeyList
ArrayList<String> uniqueKeys = new ArrayList<>();
for(Dog dataRecord : dogs){
if(!uniqueKeys.contains(dataRecord.getType() + dataRecord.getFurColor() + dataRecord.getCountry())){
uniqueKeys.add(dataRecord.getType() + dataRecord.getFurColor() + dataRecord.getCountry());
}
}
//Generate SimilarDogGroups
for(String uniKey : uniqueKeys){
SimilarDogs smlDog = new SimilarDogs();
ArrayList<Dog> similarDogRecords = new ArrayList<Dog>();
for(DataRecord dataRecord : dogs){
if(uniKey.equals(dataRecord.getType() + dataRecord.getFurColor() + dataRecord.getCountry())){
similarDogRecords.add(dataRecord);
}
}
smlDog.setSameJobGroup(similarDogRecords);
similarDogGroups.add(smlDog);
}
return similarDogGroups;
}
答案 2 :(得分:1)
正如devdave建议的那样,嵌套是我发现模块化组件的唯一方法。
我已经实现了一个类似的示例,您可以在此处看到:http://afcastano.github.io/elm-nested-component-communication/
这个想法是孩子们公开函数来获取他们自己模型的属性。这个函数可以反过来调用子组件的更多嵌套函数。
查看此repo的Readme.md
以获取代码示例:
https://github.com/afcastano/elm-nested-component-communication
答案 3 :(得分:0)
这是同一件事的另一个版本:)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
import StartApp.Simple
type alias Model = Maybe String -- the id of the selected span
type Action = ButtonClick String
update : Action -> Model -> Model
update action model =
case action of
ButtonClick id ->
Just id
view : Signal.Address Action -> Model -> Html
view address model =
let
renderButton id' label' =
let
selectedClass =
case model of
Just modelId -> if modelId == id' then " selected" else ""
Nothing -> ""
in
span [ id id', class ("button" ++ selectedClass), onClick address (ButtonClick id') ] [ text label' ]
in
div []
[ renderButton "foo" "Foo"
, renderButton "bar" "Bar"
, renderButton "tot" "Tot"
]
main =
StartApp.Simple.start { model = Nothing, update = update, view = view }