Bootstrap Elm 中的下拉菜单
Bootstrap Dropdown in Elm
我对 Elm(以及一般的前端开发)还很陌生,所以我希望我的问题不会太明显,但我想知道如何重用 UI 框架,例如 [=29] =] Elm 中的 3 个,包括 JS。
更准确地说,我今天的目标是或多或少地复制 the Bootstrap's Navbar documentation, whereby a dropdown button is contained within a navbar. So far, using Html and Html.Attributes 中的示例,我能够构建页面并正确设置样式,但实际的下拉行为不起作用:当我单击 caret 按钮,没有任何反应。我猜这是因为连接到下拉列表的 Javascript 没有被执行。
现在,我的问题是:
- 如何重用 Elm 代码中的下拉菜单等组件,包括它们的相关 JS?
- 在 Elm 中执行此操作的首选(更惯用)方式是什么?我见过像 circuithub's elm-bootstrap-dropdown 这样的包,据我所知,这是在 Elm 中对相同 JS 功能的(不)完全重写,所以我想知道:Elm 是从头开始重写所有内容的方法吗?我会对此感到非常惊讶...
谢谢大家
我认为没有一个非常明确的答案适合您,但这里有一些想法:
Elm 几乎可以做 Javascript 可以做的所有事情,当然也包括下拉菜单。但它以一种不同的方式实现,如果你想保持惯用,就不能重用 JS 代码。
您没有看到下拉菜单,因为
- 您还没有加载 bootstrap js;或
- BS js 加载正常,但在它想要锁定的 dom 元素出现之前(因为 Elm 在其视图方法中添加了它们)。在这种情况下,您可以使用一个 Tick 来触发一个新的动作,当它被接收到时(在下一个循环中)您可以使用一个端口来触发 bootstrap 再看一次。
- 将 JS 与 Elm 混合使用的真正问题是,如果 JS 重写了某些 DOM,它可能会扰乱 Elm 的差异算法,并让您遇到各种难以调试的问题。
如果您的下拉菜单在实践中不是太复杂,那么我建议查看 bootstraps JS 并查看它需要从 dom 附加/删除什么并尝试模拟它在榆树。也许您提到的图书馆已经在实践中完成了很多工作。
我目前在现实生活中的 Elm 项目中广泛使用 Bootstrap,并且效果很好。
我认为您不想通过在 Elm 中复制内容来将其集成 太多。根据我的经验,您将永远比当前 Bootstrap 版本落后一(或两)步。
虽然设置所有内容可能有点挑战,但一旦完成,它就会完美运行。为了让您继续,我正在 posting 我用来加载 Elm 应用程序的 index.html
文件。这是一个带有客户端路由的 单页 应用程序,因此我将 window.location.pathname
发送到应用程序中。它与使用 Bootstrap 无关。我包括它是因为我真的想 post 文件 "as-is" 或多或少。
基本上,在加载和启动 Elm 应用程序之前,我们只是简单地从内容分发网络将 Bootstrap CSS 和 JS 直接加载到浏览器中。
index.html
:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>My Awesome Application Title</title>
<!-- Bootstrap: Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Bootstrap: Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
<!-- Application styles -->
<!-- link rel="stylesheet" href="normalize.css" -->
<!-- link rel="stylesheet" href="skeleton.css" -->
<link rel="stylesheet" href="app.css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!-- Bootstrap: jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Bootstrap: Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<!-- Application: Javascript -->
<!-- script type="text/javascript" src="vendor.js"></script -->
<script type="text/javascript" src="native.js"></script>
<script type="text/javascript" src="app.js"></script>
<!-- Fire up the Elm application -->
<script type="text/javascript">
// Pass along the current pathname as "path" to the Elm application.
//
// This way the frontend router can decide what "page" to display.
//
var app = Elm.fullscreen(Elm.App, {path: window.location.pathname});
// Alternatively, embed the elm app in an element like this:
// var div = document.getElementById('myDiv');
// Elm.embed(Elm.Index, div);
</script>
</body>
</html>
一旦我们启动了 Elm 应用程序,它就是一种生成 Bootstrap 化 HTML 和 CSS 的简单方式,就像您在任何其他项目中使用 Bootstrap.
为了让您了解如何在此处实现导航栏,我摘自我在 Elm 中的导航栏代码:
-- Navigation bar ------------------------------------------------------------
--
-- TODO: Adapt to more responsive design. Stack navigation in mobile-friendly
-- layout and minimize user/instrument information.
--
-- Page link buttons
pageLinks : Context -> List Html
pageLinks (link, model, _) =
List.map (\p ->
li [ classList [ ("active", model.page == p) ] ]
[ link (pageToRoute p) (pageName p) ]) visiblePages
-- Dropdown menu with available options
dropdownSelectOption : Context -> Html
dropdownSelectOption (_, model, address) =
let
-- Option selection row (displayed in dropdown menu)
iRow i =
let
title_ = case i.macId of
Just macId -> macId -- primarily use macId if available
Nothing -> i.uuid -- otherwise, fallback on using the uuid
-- Determine if the option is selected and/or online/offline
isSelected = isActiveOption model i.uuid
in
li [ title title_ ]
[ a [ href "#", onClick address (SelectOption i.uuid) ]
[ text i.displayName,
span [ classList [("pull-right glyphicon glyphicon-remove-sign status-offline", i.status == Offline),
("pull-right glyphicon glyphicon-ok-sign status-online", i.status == Online),
("pull-right glyphicon glyphicon-question-sign status-unknown", i.status == Unknown)],
title (optionStatusToString i.status)
] [],
span [ classList [("pull-right glyphicon glyphicon-eye-open selected", isSelected)],
title (OptionSelectedTooltip |> t)
] []
]
]
-- Map rows on list of options
iSelectList = List.map iRow model.options
in
li [ class "dropdown", title (OptionSelectTooltip |> t) ]
[ a [ class "dropdown-toggle",
href "#",
attribute "data-toggle" "dropdown",
attribute "role" "button",
attribute "aria-haspopup" "true",
attribute "aria-expanded" "false" ]
[ OptionSelectionMenu |> tt,
span [ class "caret" ] []
],
ul [ class "dropdown-menu dropdown-menu-right" ]
(List.concat [
[ li [ class "dropdown-menu-label" ]
[ span [] [ OptionSelectLabel |> tt ] ],
li [ class "divider", attribute "role" "separator" ] [] ],
iSelectList])
]
-- The complete navigation bar
navigationBar : Context -> Html
navigationBar ctx =
ul [ class "nav nav-pills pull-right" ]
([ (pageLinks ctx),
[ (dropdownSelectOption ctx) ]
] |> List.concat)
很明显,如您所见,有很多功能我没有包含在这个示例中(出于 IP 原因),但它可以让您了解如何去做。 (例如 tt
函数转换为字符串,然后由 text
转换。它是一个支持不同语言的翻译模块)。
如果您只是将 Bootstrap 内部构件保留在 Elm 之外的 JS/CSS space 中,那么一切都非常简单。根据我的经验,它并没有像建议的那样弄乱 Elm 差异算法。
祝你好运! Elm 真的是一种很棒的语言和范例,一旦你全神贯注地编写前端代码。
我对 Elm(以及一般的前端开发)还很陌生,所以我希望我的问题不会太明显,但我想知道如何重用 UI 框架,例如 [=29] =] Elm 中的 3 个,包括 JS。
更准确地说,我今天的目标是或多或少地复制 the Bootstrap's Navbar documentation, whereby a dropdown button is contained within a navbar. So far, using Html and Html.Attributes 中的示例,我能够构建页面并正确设置样式,但实际的下拉行为不起作用:当我单击 caret 按钮,没有任何反应。我猜这是因为连接到下拉列表的 Javascript 没有被执行。
现在,我的问题是:
- 如何重用 Elm 代码中的下拉菜单等组件,包括它们的相关 JS?
- 在 Elm 中执行此操作的首选(更惯用)方式是什么?我见过像 circuithub's elm-bootstrap-dropdown 这样的包,据我所知,这是在 Elm 中对相同 JS 功能的(不)完全重写,所以我想知道:Elm 是从头开始重写所有内容的方法吗?我会对此感到非常惊讶...
谢谢大家
我认为没有一个非常明确的答案适合您,但这里有一些想法:
Elm 几乎可以做 Javascript 可以做的所有事情,当然也包括下拉菜单。但它以一种不同的方式实现,如果你想保持惯用,就不能重用 JS 代码。
您没有看到下拉菜单,因为
- 您还没有加载 bootstrap js;或
- BS js 加载正常,但在它想要锁定的 dom 元素出现之前(因为 Elm 在其视图方法中添加了它们)。在这种情况下,您可以使用一个 Tick 来触发一个新的动作,当它被接收到时(在下一个循环中)您可以使用一个端口来触发 bootstrap 再看一次。
- 将 JS 与 Elm 混合使用的真正问题是,如果 JS 重写了某些 DOM,它可能会扰乱 Elm 的差异算法,并让您遇到各种难以调试的问题。
如果您的下拉菜单在实践中不是太复杂,那么我建议查看 bootstraps JS 并查看它需要从 dom 附加/删除什么并尝试模拟它在榆树。也许您提到的图书馆已经在实践中完成了很多工作。
我目前在现实生活中的 Elm 项目中广泛使用 Bootstrap,并且效果很好。
我认为您不想通过在 Elm 中复制内容来将其集成 太多。根据我的经验,您将永远比当前 Bootstrap 版本落后一(或两)步。
虽然设置所有内容可能有点挑战,但一旦完成,它就会完美运行。为了让您继续,我正在 posting 我用来加载 Elm 应用程序的 index.html
文件。这是一个带有客户端路由的 单页 应用程序,因此我将 window.location.pathname
发送到应用程序中。它与使用 Bootstrap 无关。我包括它是因为我真的想 post 文件 "as-is" 或多或少。
基本上,在加载和启动 Elm 应用程序之前,我们只是简单地从内容分发网络将 Bootstrap CSS 和 JS 直接加载到浏览器中。
index.html
:
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>My Awesome Application Title</title>
<!-- Bootstrap: Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
<!-- Bootstrap: Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css" integrity="sha384-fLW2N01lMqjakBkx3l/M9EahuwpSfeNvV63J5ezn3uZzapT0u7EYsXMjQV+0En5r" crossorigin="anonymous">
<!-- Application styles -->
<!-- link rel="stylesheet" href="normalize.css" -->
<!-- link rel="stylesheet" href="skeleton.css" -->
<link rel="stylesheet" href="app.css">
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<!-- Bootstrap: jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Bootstrap: Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
<!-- Application: Javascript -->
<!-- script type="text/javascript" src="vendor.js"></script -->
<script type="text/javascript" src="native.js"></script>
<script type="text/javascript" src="app.js"></script>
<!-- Fire up the Elm application -->
<script type="text/javascript">
// Pass along the current pathname as "path" to the Elm application.
//
// This way the frontend router can decide what "page" to display.
//
var app = Elm.fullscreen(Elm.App, {path: window.location.pathname});
// Alternatively, embed the elm app in an element like this:
// var div = document.getElementById('myDiv');
// Elm.embed(Elm.Index, div);
</script>
</body>
</html>
一旦我们启动了 Elm 应用程序,它就是一种生成 Bootstrap 化 HTML 和 CSS 的简单方式,就像您在任何其他项目中使用 Bootstrap.
为了让您了解如何在此处实现导航栏,我摘自我在 Elm 中的导航栏代码:
-- Navigation bar ------------------------------------------------------------
--
-- TODO: Adapt to more responsive design. Stack navigation in mobile-friendly
-- layout and minimize user/instrument information.
--
-- Page link buttons
pageLinks : Context -> List Html
pageLinks (link, model, _) =
List.map (\p ->
li [ classList [ ("active", model.page == p) ] ]
[ link (pageToRoute p) (pageName p) ]) visiblePages
-- Dropdown menu with available options
dropdownSelectOption : Context -> Html
dropdownSelectOption (_, model, address) =
let
-- Option selection row (displayed in dropdown menu)
iRow i =
let
title_ = case i.macId of
Just macId -> macId -- primarily use macId if available
Nothing -> i.uuid -- otherwise, fallback on using the uuid
-- Determine if the option is selected and/or online/offline
isSelected = isActiveOption model i.uuid
in
li [ title title_ ]
[ a [ href "#", onClick address (SelectOption i.uuid) ]
[ text i.displayName,
span [ classList [("pull-right glyphicon glyphicon-remove-sign status-offline", i.status == Offline),
("pull-right glyphicon glyphicon-ok-sign status-online", i.status == Online),
("pull-right glyphicon glyphicon-question-sign status-unknown", i.status == Unknown)],
title (optionStatusToString i.status)
] [],
span [ classList [("pull-right glyphicon glyphicon-eye-open selected", isSelected)],
title (OptionSelectedTooltip |> t)
] []
]
]
-- Map rows on list of options
iSelectList = List.map iRow model.options
in
li [ class "dropdown", title (OptionSelectTooltip |> t) ]
[ a [ class "dropdown-toggle",
href "#",
attribute "data-toggle" "dropdown",
attribute "role" "button",
attribute "aria-haspopup" "true",
attribute "aria-expanded" "false" ]
[ OptionSelectionMenu |> tt,
span [ class "caret" ] []
],
ul [ class "dropdown-menu dropdown-menu-right" ]
(List.concat [
[ li [ class "dropdown-menu-label" ]
[ span [] [ OptionSelectLabel |> tt ] ],
li [ class "divider", attribute "role" "separator" ] [] ],
iSelectList])
]
-- The complete navigation bar
navigationBar : Context -> Html
navigationBar ctx =
ul [ class "nav nav-pills pull-right" ]
([ (pageLinks ctx),
[ (dropdownSelectOption ctx) ]
] |> List.concat)
很明显,如您所见,有很多功能我没有包含在这个示例中(出于 IP 原因),但它可以让您了解如何去做。 (例如 tt
函数转换为字符串,然后由 text
转换。它是一个支持不同语言的翻译模块)。
如果您只是将 Bootstrap 内部构件保留在 Elm 之外的 JS/CSS space 中,那么一切都非常简单。根据我的经验,它并没有像建议的那样弄乱 Elm 差异算法。
祝你好运! Elm 真的是一种很棒的语言和范例,一旦你全神贯注地编写前端代码。