我是榆树的新人。我正在试验它时发现这种语言。虽然信号的使用看起来很复杂。下面是我的网页的一个工作示例,它处理多个段落(添加,删除,编辑,......)。
-- start
main: Signal Html.Html
main = Signal.map (view actions.address) model
view: (Signal.Address Action) -> Model -> Html
view address model = ... (displaying paragraphs with buttons, ect)
此代码段启动模型。通过使用Signal.map
将操作映射到模型,我能够处理按钮中的点击事件(导入的Html +事件模块)
model: Signal Model
model = Signal.foldp update makeEmptyModel actions.signal
在这里,我从一个空模型开始。 update
功能允许我在按钮上单击事件后更新模型。
update: Action -> Model -> Model
update action model = ....
Action
是一种处理我已定义的多个动作的类型,例如" AddParagraph"," RemoveParagraph" ...
到目前为止这是有效的。现在,在检查包裹时,我找到了Keyboard
。这看起来很有趣,所以我想添加一个新功能。如果用户按下Alt + A,则会选择所有段落。 (如文件浏览器中的Ctrl + A)
但似乎并不容易将其与我现有的信号映射结合起来。我决定深入研究Signal
并找到Signal.merge
。所以我可以使用它吗?我将键盘信号合并到当前信号的尝试是
main = Signal.merge
(Signal.map (view actions.address) model)
(Signal.map (view actions.address) keysDown)
(keysDown来自import Keyboard exposing (keysDown)
import)
但这并不奏效。我收到了下一个错误
The 2nd argument to function `map` is causing a mismatch.
160│ Signal.map (view actions.address) keysDown)
^^^^^^^^
Function `map` is expecting the 2nd argument to be:
Signal { focused : Bool, selected : Bool, ... }
But it is:
Signal (Set.Set Char.KeyCode)
看来,当使用Signal.merge
时,它需要多个处理相同输出的信号。那就是我想要的。但这似乎并不起作用。
问题:如何将键盘信号添加到当前设计中?
或者我对Signal.merge
的期望是否错误?我是否将Signal.merge
用于错误目的?我应该使用Signal.map2
吗?如果是这样,我如何在当前示例*中使用它?或者有更好的方法吗?
答案 0 :(得分:3)
您发送给merge
的信号必须属于同一类型。在合并之前,您需要添加另一个将键盘输入映射到Action
的函数。
有几种方法可以实现这一目标。以下是使用基本计数器示例和Signal.merge
的示例。重要的是使用keyPressesToAction
信号映射函数
import Signal
import Html exposing (..)
import Html.Events exposing (..)
import Keyboard
import Char
type Action = NoOp | Increment | Decrement
actions : Signal.Mailbox Action
actions =
Signal.mailbox NoOp
update action model =
case action of
NoOp -> model
Increment -> model + 1
Decrement -> model - 1
model =
Signal.foldp update 0 (Signal.merge actions.signal keyPressesToAction)
keyPressesToAction =
let
keyCodeToAction keyCode =
case Char.fromCode keyCode of
'+' -> Increment
'-' -> Decrement
_ -> NoOp
in
Signal.map keyCodeToAction Keyboard.presses
main =
Signal.map (view actions.address) model
view address model =
div []
[ button [ onClick address Decrement ] [ text "-" ]
, text <| toString model
, button [ onClick address Increment ] [ text "+" ]
]
实现所需结果的另一种方法是使用port
专用于将按键转换为action
信号。这消除了合并信号的需要,因为它反而导致按键触发您已经设置的邮箱。
在这种情况下,model
函数会恢复原样,然后我们添加名为triggerActionOnKeyPress
的端口,它使用上面相同的keyPressesToAction
信号映射函数。以下是相关部分:
model =
Signal.foldp update 0 actions.signal
port triggerActionOnKeyPress : Signal (Task.Task Effects.Never ())
port triggerActionOnKeyPress =
Signal.map (Signal.send actions.address) keyPressesToAction