【问题标题】:Trouble translating JavaScript to ReScript将 JavaScript 转换为 ReScript 时遇到问题
【发布时间】:2022-01-25 18:38:44
【问题描述】:

我想用 ReScript 实现一个交互式滑块,所以我想把这个 JavaScript 翻译成 ReScript(礼貌:https://www.w3schools.com/howto/howto_js_rangeslider.asp):

var slider = document.getElementById("myRange");
var output = document.getElementById("demo");
output.innerHTML = slider.value; // Display the default slider value

// Update the current slider value (each time you drag the slider handle)
slider.oninput = function() {
  output.innerHTML = this.value;
}

目标 HTML (slider.html) 在哪里:

<!DOCTYPE html>
<html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
.slidecontainer {
    width: 100%;

}

.slider {
    -webkit-appearance: none;
    width: 100%;
    height: 25px;
    background: #d3d3d3;
    outline: none;
    opacity: 0.7;
    -webkit-transition: .2s;
    transition: opacity .2s;

}

.slider:hover {
    opacity: 1;
}

.slider::-webkit-slider-thumb {
    -webkit-appearance: none;
    appearance: none;
    width: 25px;
    height: 25px;
    background: #04AA6D;
    cursor: pointer;

}

.slider::-moz-range-thumb {
    width: 25px;
    height: 25px;
    background: #04AA6D;
    cursor: pointer;

}
        </style>
    </head>
    <body>
        <div class="slidecontainer">
            <input type="range" min="1" max="100" value="50" class="slider" id="myRange">
            <p>Value: <span id="demo"></span></p>
        </div>

        <script src="./bundled.bs.js"></script>
    </body>
</html>

其中bundled.bs.js 是将编译后的.bs.js 代码与Browerify 捆绑在一起的结果。

到目前为止,我使用rescript-webapi 编写了以下代码:

open Webapi.Dom
open Belt.Option

@val external document: Document.t = "document"

let slider = getExn(Document.getElementById("myRange", document))
let output = getExn(Document.getElementById("demo", document))

Element.setInnerText(output, getExn(Element.getAttribute("value", slider)))

Element.addEventListener("value", _ => 
    Element.setInnerHTML(output, getExn(Element.getAttribute("value", slider))), slider)

但是,这并没有按预期工作;我可以看到滑块并滑动它,但输入标签的值没有更新:

我的 ReScript 翻译缺少什么?

+更新:

@glennsl 为我提供了以下代码:

open Webapi.Dom
open Belt

let slider = document->Document.getElementById("myRange")->Option.getExn
let output = document->Document.getElementById("demo")->Option.getExn

output->Element.setInnerText(slider->Element.getAttribute("value")->Option.getExn)

slider->Element.addEventListener("input", _ => {
  let value = slider->Element.getAttribute("value")->Option.getExn
  output->Element.setInnerHTML(value)
})

我可以看到具有正确初始值50Value: 但是,即使我重新定位滑块,值也不会更新:

如上所述,我将这段代码(称为slider.res)编译成slider.bs.js,并与browserify slider.bs.js -o bundled.bs.js捆绑在一起。

【问题讨论】:

    标签: slider rescript


    【解决方案1】:

    没有名为value 的事件。您要翻译的 JavaScript 代码使用的是 input (oninput)。

    您还混合了“数据优先”和“数据最后”。 rescript-webapi 使用“数据优先”,而 bs-webapirescript-webapi 的分支)使用“数据最后”。您可能基于来自bs-webapi 的示例代码。

    无论如何,这应该适用于rescript-webapi

    open Webapi.Dom
    open Belt
    
    let slider = document->Document.getElementById("myRange")->Option.getExn
    let output = document->Document.getElementById("demo")->Option.getExn
    
    output->Element.setInnerText(slider->Element.getAttribute("value")->Option.getExn)
    
    slider->Element.addEventListener("input", _ => {
      let value = slider->Element.getAttribute("value")->Option.getExn
      output->Element.setInnerHTML(value)
    })
    

    【讨论】:

    • 这里的后续问题:“数据优先”和“数据最后”分别是如何定义的?
    • 另外,上面的代码似乎没有在滑动滑块时更新demo的值。 :( 我在最新的 Safari 上,并用 browserify 包装了 .bs.js 代码。
    • 如果没有完整的minimal reproducible example,很难提供任何进一步的帮助。
    • “数据优先”或“t-first”表示函数将其操作的主值或“对象”作为第一个参数。 “data last”或“t-last”表示它是最后一个参数。 “data last”过去更为常见,因为 ReScript 基于一种更自然、更方便的柯里化语言。但由于各种原因,也许最重要的是与 JavsScript 更好的互操作性,-&gt; 运算符和“数据优先”概念被引入(以一种非常糟糕的方式,甚至在几年后也会导致这些问题,但那是另一回事了) .
    • 我已经用更多细节更新了这个问题。感谢您指出。
    【解决方案2】:

    呃,主要问题有两个:

    1. 正如@glennsl 指出的那样,事件名称是错误的。应该是"input",而不是"value"

    2. 我误认为this.value 指的是thisvalue 属性,即slider。实际上,这是将slider 视为一个HTML 输入元素,并引用它的输入值

    由于我们不能直接将Dom.Element.t 转换为Dom.HtmlInputElement.t,我们首先将其转换为Dom.Node.t,然后再转换为Dom.HtmlInputElement.t。因此,基于@glennsl 的代码,代码是:

    open Webapi.Dom
    open Belt
    
    let slider = document->Document.getElementById("myRange")->Option.getExn
    let output = document->Document.getElementById("demo")->Option.getExn
    
    output->Element.setInnerText(slider->Element.getAttribute("value")->Option.getExn)
    
    slider->Element.addEventListener("input", _ => {
      let value = slider->Element.asNode->HtmlInputElement.ofNode->Option.getExn->HtmlInputElement.value
      output->Element.setInnerHTML(value)
    })
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-28
      • 1970-01-01
      • 2018-01-08
      • 2018-11-23
      • 2013-10-14
      • 1970-01-01
      • 1970-01-01
      • 2017-12-01
      相关资源
      最近更新 更多