Javascript 使用Fable获取文件输入内容

Javascript 使用Fable获取文件输入内容,javascript,html,f#,fable-f#,Javascript,Html,F#,Fable F#,我见过使用HTML5文件API从JavaScript中输入的文件读取内容 这是我的视图方法,在一个小型寓言拱门应用程序中: let view model = div [ attribute "class" "files-form" ] [ form [ attribute "enctype" "multipart/form-data" attribute "action" "/feed"

我见过使用HTML5文件API从JavaScript中输入的文件读取内容

这是我的
视图
方法,在一个小型
寓言拱门
应用程序中:

let view model =
    div [
        attribute "class" "files-form"
    ] [
        form [
            attribute "enctype" "multipart/form-data"
            attribute "action" "/feed"
            attribute "method" "post"
        ] [
            label [ attribute "for" "x_train" ] [ text "Training Features" ]
            input [
                attribute "id" "x_train"
                attribute "type" "file"
                onInput (fun e -> SetTrainingFeaturesFile (unbox e?target?value)) 
            ]
        ]
        model |> sprintf "%A" |> text
    ]
  • 有没有一种简单的方法可以直接从F#捕获文件内容
  • 实现这一点所需的最小互操作寓言代码量是多少
我找不到不编写普通JavaScript的方法,主要是因为我无法从Fable导入/实例化
FileReader
。如果有人能做到这一点,那么解决方案可能会有所改进

读取文件是异步的。这意味着视图应该生成延迟的模型更新。因为这只能在模型更新函数中完成,所以我必须在其中转发一个JavaScript文件句柄

纯JavaScript只是一种导出攻击

// file interops.js, can I get rid of this?
export var getReader = function() { return new FileReader(); }
在视图中

// view code
input [
    attribute "id" "x_train"
    attribute "type" "file"
    onInput (fun e -> FromFile (SetField, e?target?files?(0)))
]
因此,该消息实际上是一条“带有文件内容的延迟消息”。以下是操作和更新代码:

type Action =
    | SetField of string
    | FromFile of (string -> Action) * obj

let update model action =
    match action with
    | SetField content ->
        { model with Field = content}, []
    | FromFile (setAction, file) ->
        let delayedAction h =
            let getReader = importMember "../src/interops.js"
            let reader = getReader()
            reader?onload <- (fun () ->  h <| setAction !!reader?result)
            reader?readAsText file |> ignore
        model, delayedAction |> toActionList
类型动作=
|字符串集合字段
|FromFile of(字符串->动作)*obj
让我们更新模型操作=
配合行动
|设置域内容->
{Field=content的模型},[]
|FromFile(setAction,file)->
让我们推迟行动h=
让getReader=importMember“./src/interops.js”
let reader=getReader()
读卡器?仅加载h忽略
模型,delayedAction |>toActionList

FromFile
是一个复杂的操作,因为我想用它来设置多个字段。如果您只需要一个,您可以使它成为obj的

在最新版本的Fable中,我们现在可以访问
Browser.Dom.FileReader
,并避免使用互操作

可以这样写:

input 
    [ 
        Class "input"
        Type "file"
        OnInput (fun ev -> 
            let file = ev.target?files?(0)

            let reader = Browser.Dom.FileReader.Create()

            reader.onload <- fun evt ->
                dispatch (SaveFileContent evt.target?result)

            reader.onerror <- fun evt ->
                dispatch ErrorReadingFile

            reader.readAsText(file)
        ) 
    ]
输入
[ 
类“输入”
键入“文件”
OnInput(有趣的ev->
让file=ev.target?文件?(0)
让reader=Browser.Dom.FileReader.Create()
reader.onload
分派(SaveFileContent evt.target?结果)
reader.onerror
分派错误读取文件
reader.readAsText(文件)
) 
]

以下是我对马克西姆答案的看法,使用Fable.Elmish.React v3.0.1。我不熟悉这个?运算符,但我可以使用:?>一个来强制转换某些类型

input [
          Class "input"
          Type "file"
          OnInput (fun ev ->
            let file = (ev.target :?> Browser.Types.HTMLInputElement).files.Item(0)
            let reader = Browser.Dom.FileReader.Create()
            reader.onload <- fun evt ->
              (*
                Negotiate/assume the onload target is a FileReader
                Result is a string containg file contents:
                https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText
              *)
              dispatch (Set (string (evt.target :?> Browser.Types.FileReader).result))

            reader.onerror <- fun evt ->
              dispatch (Set "Error")
            
            reader.readAsText(file))]
输入[
类“输入”
键入“文件”
OnInput(有趣的ev->
let file=(ev.target:?>Browser.Types.HTMLInputElement.files.Item(0)
让reader=Browser.Dom.FileReader.Create()
reader.onload
(*
协商/假设onload目标是文件读取器
结果是一个包含文件内容的字符串:
https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsText
*)
分派(设置(字符串(evt.target:?>Browser.Types.FileReader.result))
reader.onerror
调度(设置“错误”)
reader.readAsText(文件))]

感谢@MangelMaxime在寓言频道中提供的所有建议。:-)