【问题标题】:scalajs removeEventListener not working if using a scala function如果使用 scala 函数,scalajs removeEventListener 不起作用
【发布时间】:2019-07-22 15:11:09
【问题描述】:

这段代码没有按预期工作(keydown函数在按键时仍然执行):

import org.scalajs.dom.raw.Event
import org.scalajs.dom.{console, document}
import scala.scalajs.js

def keydown(e: Event) { console.log(e) }
document.addEventListener("keydown", keydown)
document.removeEventListener("keydown", keydown)

这个修改后的代码确实按预期工作:

def keydown_(e: Event) { console.log(e) }
val keydown: js.Function1[Event, Unit] = (e: Event) => keydown_ _
document.addEventListener("keydown", keydown)
document.removeEventListener("keydown", keydown)

为什么会这样? 是否可以删除这个额外的样板代码行?

【问题讨论】:

    标签: scala.js


    【解决方案1】:

    Scala Functions 和 JS Functions 是不同的类型,您需要从一种转换为另一种。这是为您隐式完成的,但每次调用转换时,此转换都会创建一个新的 JS Function 实例。

    所以多次调用转换,即使是隐式调用,每次都会得到不同的 JS Function 实例。即使这些实例包装了相同的 Scala 函数,浏览器也不知道这一点。为了removeEventListener,您需要向它提供与您传递给addEventListener 完全相同的JS 函数引用,这就是为什么您的val 示例有效但def 无效。

    【讨论】:

    • 好的,谢谢。那么实现这一目标的更紧凑的方法是什么?我目前正在使用这个:val keydown: js.Function1[Event, Unit] = (e: Event) => { console.log(e) },但与更紧凑(不工作)的形式 def keydown(e: Event) { console.log(e) } 相比,它看起来很难看。
    • @DavidPortabella 您可以创建一个像case class Callback[Ev](fn: js.Function1[Ev, Unit]) 这样的包装器来帮助进行类型推断,并像val cb = Callback[Event](ev => console.log(ev)) 一样使用它,当您需要JS 函数时只需参考cb.fn。您可能需要稍微调整该代码以获得所需的类型推断,我还没有运行它。您还可以使用 ScalaJS DOM 库之一为您处理这些事情。
    • 上面的代码已经使用了github.com/scala-js/scala-js-dom库。你的意思是另一个scalajs DOM库吗?哪一个?我没有找到任何其他人(可以处理这个)。
    • @DavidPortabella scala-js-dom 只是浏览器 DOM 的一个外观,它必须镜像原生的低级 DOM API。我的意思是更高级别的响应式 UI 库,例如 slinky.devoutwatch.github.io 或我自己的 github.com/raquo/Laminar——使用这些库,您通常不需要强制地微观管理事件处理程序——它们提供了不同的、更具声明性的抽象。如果您是整个领域的新手,还可以考虑查看 React.js 文档作为入门 - 它不是 Scala,但他们有很多涵盖现代 UI 开发方法的优秀文档。
    猜你喜欢
    • 1970-01-01
    • 2018-03-24
    • 1970-01-01
    • 2017-09-23
    • 2014-07-28
    • 2014-09-02
    • 2015-11-06
    相关资源
    最近更新 更多