【问题标题】:How to render purescript-halogen components into the <head> tag如何将 purescript-halogen 组件渲染到 <head> 标签中
【发布时间】:2017-02-22 17:09:18
【问题描述】:

如何将特定的 purescript-halogen 组件渲染到

标签中?

以下为 Halogen 1.0.0 编写的示例将样式表和段落呈现到 HTML 正文中:

module Main where

import Prelude
import Control.Monad.Eff      (Eff)
import Data.Maybe             (Maybe(Nothing))

import CSS                    as C
import Halogen                as H
import Halogen.Aff            as HA
import Halogen.HTML           as HH
import Halogen.HTML.CSS       as HS
import Halogen.Query.HalogenM as HQ
import Halogen.VDom.Driver    as HV

styles :: forall p i. HH.HTML p i
styles = HS.stylesheet $
    C.select C.body $ C.margin C.nil C.nil C.nil C.nil

content :: forall p i. HH.HTML p i
content = HH.p_ [ HH.text "Test" ]

main :: Eff (HA.HalogenEffects ()) Unit
main = HA.runHalogenAff $ HA.awaitBody >>= HV.runUI ui unit
  where
    ui = H.component { initialState : const unit
                     , render       : const render
                     , eval         : const $ HQ.halt "no query"
                     , receiver     : const Nothing
                     }

    render = HH.div_ [ styles, content ]

DOM 生成如下:

<html>
    <head>
        <title>Test</title>
        <script async="" type="text/javascript" src="main.js"></script>
    </head>
    <body>
        <div>
            <style type="text/css">
                body { margin: 0 0 0 0 }
            </style>
            <p>
                Test
            </p>
        </div>
    </body>
</html>

此示例有效,但根据specification,样式元素仅允许“在需要元数据内容的地方”,即

元素。所以我想在那里渲染样式表。我该如何做到这一点?

【问题讨论】:

  • 如果样式表完全是静态的,为什么还要用 Halogen 渲染呢?如果需要这种灵活性,可以在特定元素上呈现样式属性。但总的来说这个问题仍然很有趣......我正在考虑
  • 在 Purescript 中呈现静态样式表具有以下优点: 您可以使用 PureScript 的全部功能来组装样式表,并且不需要像 Sass 或 Less 之类的其他 CSS 预处理器。此外,您可以将代码模块化,以便将 Halogen 组件与其样式存储在一起。如果您需要媒体查询或 :hover 之类的伪类,则不能使用样式属性。

标签: purescript halogen


【解决方案1】:

注意awaitBody 函数——在等待它加载的同时,它选择了body 元素,在这种情况下这并不是你真正想要的。如果您想写信给head,那么您需要选择它并将其传递给runUI,以获得呈现样式表的组件。

您还需要运行两个单独的组件,一个用于head,一个用于body

module Main where

import Prelude

import Control.Monad.Aff.Console (CONSOLE)
import Control.Monad.Eff (Eff)

import Data.Const (Const)
import Data.Foldable (traverse_)
import Data.Maybe (Maybe(..))
import Data.Newtype (unwrap)

import Halogen as H
import Halogen.Aff as HA
import Halogen.HTML as HH
import Halogen.VDom.Driver (runUI)

bodyComponent :: forall m. H.Component HH.HTML (Const Void) Unit Void m
bodyComponent =
  H.component
    { initialState: const unit
    , render: const $ HH.div_ [ HH.text "A component" ]
    , eval: absurd <<< unwrap
    , receiver: const Nothing
    }

styleComponent :: forall m. H.Component HH.HTML (Const Void) Unit Void m
styleComponent =
  H.component
    { initialState: const unit
    , render: const $ HH.style_ [ HH.text "body { background: #222; color: #eee }"]
    , eval: absurd <<< unwrap
    , receiver: const Nothing
    }

main :: Eff (HA.HalogenEffects (console :: CONSOLE)) Unit
main = HA.runHalogenAff do
  HA.awaitLoad
  traverse_ (runUI styleComponent unit) =<< HA.selectElement "head"
  traverse_ (runUI bodyComponent unit) =<< HA.selectElement "body"

如果他们需要通信,那么您可以使用runUI 生成的HalogenIO 记录中的subscribedriver 函数来设置它们之间的通道。

我担心这样做,因为您应该通过一个空元素作为容器将呈现的目标...但是当使用卤素提供的 VDom 驱动程序时,它似乎表现得很好至少,&lt;head&gt; 内容不会被样式组件替换(它被附加到末尾)。虽然这基本上是未指定的行为,所以我不确定它是否一定适用于其他驱动程序。

【讨论】:

  • 我尝试了您的建议,但我无法使用 runUI 运行两个组件。只有第一个被渲染。然后我尝试使用runHalogenAff 运行两个卤素实例,并且成功了。我不需要两个组件/实例相互通信,所以这对我来说没问题。实例将它们的元素分别添加到head 元素和body 元素中,并且不替换它们的内容,因此正如您所猜测的那样重写没有问题。
  • 我已经编辑了我的答案以包含一个非常简单的工作示例。我不确定您可能遇到了什么问题,但使用 runUI 两次似乎对我来说很好!
  • 我的代码中的错误是 awaitLoad 实际上被调用了两次。你的例子工作正常。谢谢!
猜你喜欢
  • 2016-02-04
  • 2019-10-02
  • 2019-03-12
  • 1970-01-01
  • 2017-11-16
  • 2016-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多