如何在纯 Purescript 中添加 onclick 侦听器?

How do I add an onclick listener in plain Purescript?

我刚刚开始学习 Purescript。我想在一个简单的网页中进行试验。我想从只学习 plain Purescript 开始,不使用任何框架,例如 Halogen 或 Pux 等

我想我需要使用 purescript-web-html 包来注册按钮点击事件。我进行了搜索,但没有找到任何使用此包来侦听和处理 html 元素事件的初级示例。

<script>
   function log_click() {
      console.log("clicked");
   }

   document.addEventListener('DOMContentLoaded', function() {  
                
      document.getElementById('myButton').onclick = log_click;
   });
</script>
<body>
  <button id="myButton" >click me</button>
</body>

这是我的纯 Purescript 尝试:

logClick :: Effect Unit
logClick = log "button clicked"

main :: Effect Unit
main = do

  w <- window
  doc <- document w
  buttonMaybe <- getElementById "myButton" $ toNonElementParentNode doc

  myEventTarget <- case buttonMaybe of
    Nothing -> throw "element with id 'myButton' not found."
    Just myButtonElem -> toEventTarget myButtonElem

  let listener =  eventListener logClick 

  addEventListener click listener true myEventTarget

您的尝试即将完成。就是几个小问题。

首先toEventTarget是纯函数,不是效果。所以你不能把它放在 <-.

的右边

但不用担心:如果您有一个纯值,可以很容易地使用 pure:

将其包装在效果中
  myEventTarget <- case buttonMaybe of
    Nothing -> throw "element with id 'myButton' not found."
    Just myButtonElem -> pure $ toEventTarget myButtonElem

Second,你在 eventListener 中遇到了相反的问题:它是一个有效的函数,但你将它与 let 绑定为一个纯值.只需使用 <- 绑定:

listener <- eventListener logClick

最后,参数类型eventListener期望的是一个函数Event -> Effect Unit,但是你的logClick只是一个Effect Unit.只需给它一个 Event 参数。您不必实际使用它:

logClick :: Event -> Effect Unit
logClick _ = log "button clicked"

然后,这是整个工作部分:

logClick :: Event -> Effect Unit
logClick _ = log "button clicked"

main :: Effect Unit
main = do
  w <- window
  doc <- document w
  buttonMaybe <- getElementById "myButton" $ toNonElementParentNode doc

  myEventTarget <- case buttonMaybe of
    Nothing -> throw "element with id 'myButton' not found."
    Just myButtonElem -> pure $ toEventTarget myButtonElem

  listener <- eventListener logClick

  addEventListener click listener true myEventTarget

总之,虽然上面的技术在技术上可行,但可以通过在方便的地方组合函数而不是给出结果名称来写得更短更简洁:

main :: Effect Unit
main = do
  window >>= document <#> toNonElementParentNode
  >>= getElementById "myButton"
  >>= traverse_ \button -> do
    listener <- eventListener \_ -> log "button clicked"
    addEventListener click listener true (toEventTarget button)