2

在 Halogen 中玩一个简单的演示应用程序,其中包含一个输入字段中的值填充的动态列表,我意识到,在单击按钮后将焦点返回到输入是非常困难的。只有一种方法:定义 FFI 方法,该方法通过 DOM id 发现元素并调用焦点。Halogen 在创建时不会公开 DOM 引用。

通过 id 定位 DOM 是一种有限的方法,并且无法自行扩展。DOM id 是页面全局的。它们打破了抽象和孤立。组件不可组合!

缺少 DOM 引用不仅会影响焦点,还会影响选择。

我猜卤素不会很快解决这个问题,所以我正在寻找一种解决方法。如何使组件,中继焦点,可组合?

我认为某种分层 id 生成器会有所帮助。它为 DOM 元素生成并分配唯一的 id,同时将它们暴露给组件逻辑。

module Main where


import Prelude (Unit, bind, discard, map, unit, ($), (<>), show)

import Data.Array (snoc, length)
import Effect (Effect)
import Effect.Console (log)
import Effect.Aff (Aff)
import Data.Maybe (Maybe(..))
import Halogen (liftEffect)
import Halogen as H
import Halogen.Aff as HA
import Halogen.HTML as HH
import Halogen.VDom.Driver (runUI)
import Halogen.HTML.Properties as P
import Halogen.HTML.Events as E

main :: Effect Unit
main = HA.runHalogenAff do
  body <- HA.awaitBody
  runUI component unit body

type AppState = { names :: Array String
                , newName :: String
                }


data Action = Append | NewName String

component :: forall query input output. H.Component HH.HTML query input output Aff
component =
  H.mkComponent
  { initialState
  , render
  , eval: H.mkEval $ H.defaultEval { handleAction = handleAction }
  }
  where
    initialState _ = { names: ["Bill"]
                     , newName: ""
                     }
    render state =
      HH.div_
        [ HH.div_
          [ HH.input
            [ P.value state.newName
            , P.id_ "newNameField"
            , P.type_ P.InputText
            , P.autofocus true
            , E.onValueChange \s -> Just $ NewName s
            ]
          , HH.button [E.onClick \_ -> Just Append] [ HH.text "add" ]
          ]
        , HH.div_ (map (\n -> HH.div_ [HH.text n]) state.names)
        ]

    handleAction ev = do
      st <- H.get
      case ev of
        Append -> do
          case st.newName of
            "" -> liftEffect $ log "Empty new name"
            _  -> H.put st { newName = "", names = snoc st.names st.newName }
        NewName s -> do
          liftEffect $ log ("Update new name: [" <> s <> "]")
          H.put st { newName = s }

4

1 回答 1

0

您可以使用 命名元素RefLabel,请参阅https://pursuit.purescript.org/packages/purescript-halogen/5.0.0/docs/Halogen.HTML.Properties#v:ref

然后您可以查询这些元素,请参阅https://pursuit.purescript.org/packages/purescript-halogen/5.0.0/docs/Halogen.Query#v:getHTMLElementRef

与元素 id 不同,卤素 RefLabel 是组件本地的。

于 2020-10-07T23:45:28.450 回答