问题
I have found the ghcjs documentation very limited. Here is this basic HTML document.
h1 { font-family: Helvetica; }
p {font-family: Helvetica; color: blue; }
<h1>
Hello World
</h1>
<p>
This is my test document.
</p>
Is ghcjs just a combinator, basically typing the HTML as an output string? Or does Haskell store a model of DOM somewhere?
My question is about all html tags and CSS, but maybe other tags have different features.
回答1:
You can use ghcjs
with the library ghcjs-dom
to work with the DOM
.
From the title of your question, "how to code <h1> tags with ghcjs"
, and some of your comments, it looks like you are looking for a simple ghcjs/ghcjs-dom example that includes a few HTML
tags. This program will generate your HTML
and respond to a click on the h1
element:
import GHCJS.DOM (runWebGUI, webViewGetDomDocument)
import GHCJS.DOM.Document (getBody, createElement)
import GHCJS.DOM.Element (click, setInnerHTML)
import GHCJS.DOM.HTMLHeadingElement (castToHTMLHeadingElement)
import GHCJS.DOM.HTMLParagraphElement (castToHTMLParagraphElement)
import GHCJS.DOM.Node (appendChild)
import GHCJS.DOM.EventM (on)
main = runWebGUI $ \win -> do
Just doc <- webViewGetDomDocument win
Just body <- getBody doc
Just h1 <- fmap castToHTMLHeadingElement <$> createElement doc (Just "h1")
appendChild body $ Just h1
setInnerHTML h1 (Just "Hello World")
on h1 click $ setInnerHTML h1 (Just "Clicked")
Just p <- fmap castToHTMLParagraphElement <$> createElement doc (Just "p")
appendChild body $ Just p
setInnerHTML p (Just "This is my test document.")
return ()
This project: https://github.com/dc25/stackOverflow__how-to-code-h1-tags-with-ghcjs contains the above code. Here is a link to a browser based demo: https://dc25.github.io/stackOverflow__how-to-code-h1-tags-with-ghcjs/ The page changes if you click the "Hello World" header.
The ghcjs
compiler output includes an index.html
page. Ghcjs will not overwrite that page if it already exists so you can safely edit it after it is created. This allows you to directly include your css
file.
Regarding documentation, this page: https://hackage.haskell.org/package/jsaddle-dom-0.4.0.1/docs/ contains useful links related to ghcjs-dom
functionality.
回答2:
First of all - as @Cubic already said - I think you are confused what GHCJS is.
GHCJS is a Compiler that lets you compile Haskell code to Javascript - rendering a simple page of html/css is not the task it was designed for. It is "Mit Kanonen auf Spatzen schießen" as we say in German - or shorter overkill.
So what would I use it for writing a front-end to a given haskell backend is really nice, you can share all your existing types and get all the maintainability and safety you have in the haskell eco-system.
But even if you don't have a haskell backend and you strife for novelty and good ideas - GHCJS might interest you, I myself am quite new to functional reactive programming, and having tried purescript(with pux) before now learning reflex/reflex-dom (my choice of front-end dsl) is a challenge for my brain and a delight - I know this paragraph is quite opinionated, but the abstractions presented in reflex seem right and seem to make clear some of the shortcomings of other functional reactive frameworks…
So how would one render the above in with the aforementioned libraries:
{-# LANGUAGE OverloadedStrings #-}
import Reflex
import Reflex.Dom
main :: IO ()
main = mainWidgetWithCss "h1 {font-family: Helvetica;} p {font-family: Helvetica; color: blue;}" $ do
el "h1" $ text "Hello World!"
el "p" $ text "This is my test document"
This is - as I said - overkill - you get a full run-time, a big chunk of js when some plain html/css would have sufficed. But for generating a complex UI in reusable components GHCJS might be the right choice.
The following is one of the more complex components I have yet written - it models a list of buttons that I can expand when clicking on the rightmost button, or shrink to the size of one of the other buttons (i use this for something like a "rate this X stars" but the stars can be arbitrary many).
listWidget :: MonadWidget t m => Int -> m (Event t Int)
listWidget n = leftmost <$> traverse button' [(-1)..(n+1)]
listWidget2 :: MonadWidget t m => m ()
listWidget2 = mdo
clicked <- switchPromptlyDyn <$> widgetHold (listWidget (-1))
(listWidget <$> clicked)
return ()
button' :: (MonadWidget t m, Show a) => a -> m (Event t a)
button' val = (fmap $ const val) <$> button (text . pack $ show val)
UPDATE:
The problem that plain Javascript has is scalability if you have a large amount of Javascript maintaining and changing code gets error prone and tedious because of the lacking type system and the dynamic nature. To remedy these problems there have come up a vast number of "compile-to-JS" languages - Haskell with GHCJS being one of them.
来源:https://stackoverflow.com/questions/42254610/how-to-code-h1-tags-with-ghcjs