PureScript で DOM を操作
PureScript の下記ライブラリを使って簡単な DOM 操作を試してみました。
ソースは http://github.com/fits/try_samples/tree/master/blog/20160125/
はじめに
PureScript を使って実装するものと同等の処理を JavaScript で書いてみました。 id で指定した DOM ノードの textContent を変更するだけの簡単な処理です。
sample.js
var Sample = { updateContent: (id, content) => { var node = document.getElementById(id); if (node) { node.textContent = content; } } };
下記の HTML で実行してみます。 (PureScript の方は updateContent
の呼び出し部分が少し異なります)
index.html
<!DOCTYPE html> <html> <body> <h2 id="d"></h2> <script src="sample.js"></script> <script> Sample.updateContent('d', 'sample javascript'); </script> </body> </html>
実行結果
Web ブラウザで表示した結果は以下の通りです。
purescript-dom の場合
pulp init
でプロジェクトを作成し、pulp dep install
で purescript-dom
をインストールします。
なお、pulp と gulp を事前にインストール (npm install
) しておきます。
purescript-dom インストール
> pulp init ・・・ > pulp dep install purescript-dom --save
src/Main.purs を編集し updateContent
関数を実装します。
以下のように型まわりに注意が必要です。
- (a) document 関数は Eff (dom :: DOM | eff) HTMLDocument を返す
- (b) getElementById 関数の引数は ElementId と NonElementParentNode
- (c) getElementById 関数は Eff (dom :: DOM | eff) (Nullable Element) を返す
- (d) setTextContent 関数の引数は String と Node
(a) の結果の HTMLDocument を getElementById の引数へそのまま使えなかったので htmlDocumentToNonElementParentNode
関数で変換しています。
(c) の結果の Nullable はそのままだと使い難いので toMaybe
関数で Maybe 化し、Element も setTextContent
の引数に使えなかったので elementToNode
関数で変換しています。
src/Main.purs
module Main where import Prelude import Control.Monad.Eff import Data.Maybe import Data.Nullable (toMaybe) import DOM import DOM.HTML.Types import DOM.Node.Types import DOM.HTML (window) import DOM.HTML.Window (document) import DOM.Node.NonElementParentNode (getElementById) import DOM.Node.Node (setTextContent) updateContent :: forall eff. String -> String -> Eff (dom :: DOM | eff) Unit updateContent id content = do win <- window doc <- document win node <- getElementById (ElementId id) $ htmlDocumentToNonElementParentNode doc case (toMaybe node) of Just x -> setTextContent content (elementToNode x) _ -> return unit
今回は、gulp を使って pulp browserify
を実行するように以下のような gulpfile.js を用意しました。
Sample.updateContent
で関数を実行できるように --standalone
を指定しています。
gulpfile.js
var gulp = require('gulp'); var child_process = require('child_process'); var pulpCmd = (process.platform == 'win32')? 'pulp.cmd': 'pulp'; var destFile = 'sample.js' gulp.task('pulp_package', () => { // pulp browserify の実行 var res = child_process.spawnSync(pulpCmd, ['browserify', '--standalone', 'Sample', '-t', destFile]); // 実行結果の出力 [res.stdin, res.stdout, res.stderr].forEach( x => { if (x) { console.log(x.toString()); } }); }); gulp.task('default', ['pulp_package']);
gulp
コマンドを実行すると sample.js が生成されます。
ビルド例 (gulp で pulp browserify を実行)
> gulp
下記の HTML で実行してみます。
ここで、Sample.updateContent
はカリー化されており function(id) { return function(content) { return function __do() { ・・・ } } }
となっている点に注意。
index.html
<!DOCTYPE html> <html> <body> <h2 id="d"></h2> <script src="sample.js"></script> <script> Sample.updateContent('d')('sample purescript-dom')(); </script> </body> </html>
実行結果
purescript-simple-dom の場合
同じ様にして purescript-simple-dom
をインストールします。
purescript-simple-dom インストール
> pulp init ・・・ > pulp dep install purescript-simple-dom --save
src/Main.purs を編集し updateContent
関数を実装します。
purescript-dom と比べると余計な型変換が不要なのでシンプルです。
src/Main.purs
module Main where import Prelude import Control.Monad.Eff import DOM import Data.Maybe import Data.DOM.Simple.Window (document, globalWindow) import Data.DOM.Simple.Element (getElementById, setTextContent) updateContent :: forall eff. String -> String -> Eff (dom :: DOM | eff) Unit updateContent id content = do doc <- document globalWindow node <- getElementById id doc case node of Just x -> setTextContent content x _ -> return unit
purescript-dom と同じ様に gulp で sample.js を生成しました。(gulpfile.js は同じ内容です)
HTML は以下の通りです。
index.html
<!DOCTYPE html> <html> <body> <h2 id="d"></h2> <script src="sample.js"></script> <script> Sample.updateContent('d')('sample purescript-simple-dom')(); </script> </body> </html>