如何告诉 elm 外部 DOM 变化

Posted

技术标签:

【中文标题】如何告诉 elm 外部 DOM 变化【英文标题】:how to tell elm about external DOM changes 【发布时间】:2017-03-25 11:23:36 【问题描述】:

我正在使用 elm 0.17.1 并尝试与 select2 javascript 库(版本 4.0.3)进行互操作,这是我的 Main.elm:

port module Main exposing (..)

import html exposing (Html,select,option,div,text,br)
import Html.App as App
import Html.Attributes exposing (id,value,width)
-- MODEL

type alias Model =
  
     country : String
  


-- UPDATE

type Msg =
      Select String

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    Select str -> (Model str,Cmd.none)


-- VIEW

view : Model -> Html Msg
view model =
  div[]
  [
    select [id "myselect"]
    [
     option [value "US"] [text "United States"],
     option [value "UK"] [text "United Kingdom"]
    ],
    text model.country
  ]

-- SUBSCRIPTIONS

port selection : (String -> msg) -> Sub msg

subscriptions : Model -> Sub Msg
subscriptions _=
  selection Select


port issueselect2 : String -> Cmd msg

-- INIT

init : (Model, Cmd Msg)
init =
  (country="",issueselect2 "myselect")

main : Program Never
main = App.program init=init,view=view,update=update,subscriptions=subscriptions

和 javascript 方面:

$(document).ready(function()
     
        var app=Elm.Main.fullscreen();
        app.ports.issueselect2.subscribe(function(id)
        
           $('#'+id).select2().on('change',function(e)
           
              app.ports.selection.send(e.target.value);
           );
        )
     )

现在,当我选择一个国家/地区时,我的 chromium 控制台中出现未捕获类型错误,提示 domNode.replaceData 不是函数(实际上是未定义的)。

问题是 select2 向 DOM 添加了一个跨度,而 Elm 不知道它,检查 domNode 发现 Elm 在应该更新文本时尝试更新 span

我想我需要效果,但我不知道如何在我的特定用例中使用它们。

如何解决我的问题?

为了记录我正在使用 jquery 3,我将我的 elm 程序编译到 main.js 中,然后按以下顺序加载 js 文件:jquery.min.js、select2.min.js、main.js 然后是上面的js代码。

我无法使用 elm-reactor 进行调试,因为它似乎只适用于 elm 代码而不是 js 代码。

【问题讨论】:

我认为,即使不是不可能,也很难让它发挥作用。 Elm 的虚拟 DOM 假设真实的 DOM 总是同步的。 Select2 打破了这一点。也许最好只管理 Elm 中选择列表的数据:在模型中保留选择的国家和选项列表。使用 ap 端口将选项发送到 JavaScript,在 javascript-land 中渲染 <select><option>s,进行 select2 改造,然后将选定的选项发送回 Elm。 【参考方案1】:

为了解决这个问题,我创建了this example 来展示将任何第三方 JavaScript 技术集成到您的 Elm 应用中的所有核心理念。

规则如下:

让 Elm 拥有国家 不要改变由 Elm 生成的 DOM 查看 你不需要$(document).ready(),如果 Elm 应用程序控制 初始化逻辑 使用端口初始化和控制第三方代码

示例中的兴趣点:

index.js — JavaScript 中的端口订阅设置和 select2 引导代码

App.elm — 拥有 select2 的配置并订阅更改

视图为所有 jQuery 魔法提供了一个容器:

view : Model -> Html Msg
view model =
    div []
        [ text (toString model)
        , div [ id "select2-container" ] [] -- The container, where select2 will live
        ]

非常欢迎任何反馈,如果你能告诉我缺少什么,我愿意改进这个答案。

【讨论】:

以上是关于如何告诉 elm 外部 DOM 变化的主要内容,如果未能解决你的问题,请参考以下文章

使用 Elm.Browser.Dom 按类名获取元素

防止我的 Elm 应用程序在第 3 方更改 DOM 时崩溃

观察 Vue 中的异步外部 DOM 变化

如何在没有事件的情况下选择DOM外部的元素?

JQuery如何监听一个DIV宽高的变化?

如何在 Elm 中创建 HTML 数据属性?