Purescript中的getElementById

5

我对Purescript非常陌生,所以这可能是个幼稚的问题。

我想编写一个Purescript函数,该函数从浏览器上的HTML输入元素读取输入,并将一些输出写入另一个HTML输入元素。

在普通的Javascript中,它很简单:document.getElementById('output').value = myFun(document.getElementById('input'));。如何只用Purescript实现这个功能呢?

2个回答

6

编辑:

我注意到我的回答不符合要求 - 我只是设置了一个元素值。如果我有更多时间,我可能会添加从元素值读取的代码段,但是你应该能够从已提供的提示中猜出如何实现它:-)


一般来说,在使用PureScript时,您需要使用一些高级框架来操作DOM,例如:halogen、react-basic、concur、spork、elmish、flare、hedwig、flame(当然我可能漏掉了一些其他的 - 对此感到抱歉)。

但是,如果您真的想手动改变DOM,请不要感到惊讶,因为这并不像命令式JavaScript那样愉快。这是有意的 - PureScript有将效果与纯函数分离的能力,我们必须在每个步骤中使用Effect。另一方面,这赋予了我们一种独特的能力,可以理解代码并确保副作用可能发生的位置以及我们程序的哪些部分是纯粹的。

所以让我们使用低级别的purescript-web-html。这个库非常底层,但是在DOM API周围提供严格的类型,因此就像我说的那样,它需要相当多的手动值传递:

module Main where

import Prelude

import Data.Maybe (Maybe(..))
import Effect (Effect)
import Web.DOM.Document (toNonElementParentNode)
import Web.DOM.Element (setAttribute)
import Web.DOM.NonElementParentNode (getElementById)
import Web.HTML (window)
import Web.HTML.HTMLDocument (toDocument)
import Web.HTML.Window (document)

main :: Effect Unit
main = do
  w ← window
  d ← document w
  maybeElement ← getElementById "test-input" $ toNonElementParentNode $ toDocument  d
  case maybeElement of
    Nothing → pure unit
    Just elem → do
      setAttribute "value" "new-value" elem

使用无中间变量的点儿式风格可以将其缩短一些:

main :: Effect Unit
main = window >>= document >>= toDocument >>> toNonElementParentNode >>> getElementById "test-input" >>= case _ of
  Nothing → pure unit
  Just elem → setAttribute "value" "new-value" elem

直��作 DOM �能�是开始�建较大项目或开始使用这个真正精彩的语言的最佳方�。�一方�,这有时�能会很有用😉

谢谢您的回答,我会尝试一下。顺便问一句,您有没有推荐的遵循函数式编程范式的Purescript框架?我看了一下Halogen,但它似乎对我来说非常面向对象,其“组件”抽象保持状态并提供渲染和响应查询方法。 - Random dude
我是 react-basic 的快乐用户(它是在 React 之上的微小、有见解的层,因此采用了组件化的方法)。我还使用我们内部的 spork_(“_Elm 架构”)框架的分支,所以我只能推荐这两个 :-) ,适应于 canvas 渲染层。 - paluh
关于面向对象的方法,我认为在UI组件建模的背景下,某种形式的面向对象并不是本质上不好的。请注意,在这些框架中没有“子类型/继承”或类似的建模,因此我认为组件更像是状态机。基于清晰的转换图的状态机模型是一种非常有用和清晰的应用程序模块化方法,我认为 :-) - paluh

0
我使用了Purescript的Foreign Function Interface (FFI)功能,如下所示。
定义您的Purescript模块,并导入您想要使用的外部函数。这里我们已经导入了两个函数。
-- Main.purs
foreign import getElementById :: String -> Effect String
foreign import setElementById :: String -> String -> Effect Unit 

现在创建一个相同名称但扩展名为.js的Javascript文件。我们将从这里导出JS函数以供Purescript使用。

// Main.js
"use strict";

exports.getElementById = function(id) {
    return document.getElementById(id).value;
};

exports.setElementById = function(id) {
    return function(value) {
    document.getElementById(id).value = value;
    };
};

现在我们可以在Purescript文件中调用getElementByIdsetElementById函数。

1
我发现你提供的FFI函数和类型存在一些问题。 getElementById 不是纯函数,因为它依赖于文档的当前状态,而不仅仅是输入的字符串。文档中可能缺少该元素,给定元素可以是 HTML input 之外的其他元素(value 属性可能丢失)。value 可以在调用之间更改,因此对此函数的后续调用返回不同的结果,违反了引用透明属性。setElementById 应该被包装在一个JS端的 Effect 表示的 function() 中。 - paluh
1
你能否改进上面的答案或者加一些警告说明这段代码有些不正确?这个答案在stackoverflow上被显示为第一个回答,可能会让人们感到困惑。 - paluh
该方法没有正确处理元素不存在的情况。例如,getElementById 应该返回 Effect (Maybe String) 或类似的内容。 - chtenb
@paluh如果您知道更正确的答案,请提供。试图学习PureScript的人们正在尽其所能利用有限的PureScript文档和在线示例。一个可行的示例比批评某人合理尝试回答要好得多。 - devdanke
@davdanke,你可以在下面找到我的答案。我需要扩展它并提供更多的例子吗? - paluh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接