【问题标题】:How to highlight active link with Snap?如何使用 Snap 突出显示活动链接?
【发布时间】:2012-08-04 23:16:54
【问题描述】:

有人可以举个例子,用Snap 突出显示网站菜单上的“活动”链接吗?或者至少告诉我你会怎么做——因为我不知道。

在其他网络框架中,我通常将一个名为 active 的上下文变量设置为活动页面应该是什么,然后我的 html 会简单地检查它:

<ul> 
   {% ifequal active "home" %}
   <li class="active">
   {% else %}
   <li>
   {% endifqual %}
   <a href="/">Home</a>
   </li>

   {% ifequal active "about" %}
   <li class="active">
   {% else %}
   <li>
   {% endifequal %}
   <a href="/about">About Us</a>
   </li>

 </ul>

抢劫中有拼接,但我不确定您将如何使用它们来确定当前 url 是什么或设置上下文变量。

我的解决方案

感谢@mightybyte 和@Adam Bergmark,我确定了以下几点:

Haskell 代码:

menuenuEntrySplice :: MonadSnap m => HeistT m Template
menuEntrySplice = do
               requestPath <- lift $ withRequest (return . rqURI)
               node <- getParamNode
               let setActive n = if getAttribute "href" node == Just (decodeUtf8 requestPath)
                                    then setAttribute "class" "active" n
                                    else n


               let aNode = Element "a" [("href", fromMaybe "/" $ getAttribute "href" node)] $ [TextNode (nodeText node)]
               let liNode = setActive $ Element "li" [] [aNode]

               return [liNode]


app :: SnapletInit App App
app = makeSnaplet "app" "An snaplet example application." Nothing $ do
    ....
    addSplices [ ("menuEntry", liftHeist menuEntrySplice) ]
    return $ App h s a

现在它在 HTML 中使用:

<ul class="nav">
      <menuEntry href="/">Home</menuEntry>
          <menuEntry href="/contact">Contact</menuEntry>
</ul>

产生:

<ul class="nav">
     <li class="active"> <a href="/">Home</a> </li>
     <li> <a href="/contact">Contact</a> </li>
</ul>

【问题讨论】:

  • body和你的lis一个id然后做#page-home #nav-home, #page-about #nav-about怎么样?
  • 谢谢,但我宁愿在代码中保留逻辑,而不是 css/html :-)(是的,我确实意识到我的解决方案是在 html 中使用逻辑 - 但我没有说它是最好的:-)

标签: haskell haskell-snap-framework


【解决方案1】:

在 snapframework.com 站点中,我们使用 javascript 来实现。在site.js 的末尾,您会发现这段代码将相应的类添加到相应的链接中。

if ($.url.segment(0)) {
  $('.nav li.'+$.url.segment(0)).addClass('active');
} else {
  $('.nav .home').addClass('active');
}

如果您想使用 Heist 执行此操作,那么您需要使用与您上面的模板所使用的有点不同的范例。 Heist 的全部意义(借助 Haskell 强大的静态类型系统)是在视图和业务逻辑之间提供尽可能强的分离,因此您不能直接在模板中使用循环或条件等 Haskell 构造。答案是创建完全符合您要求的新标签(通过拼接实现)。在您的模板中,您将像这样使用它:

<ul>
  <menuLink href="/">Home</menuLink>
  <menuLink href="/about">About Us</menuLink>
</ul>

首先,请注意这是多么清洁。在您的方法中,您必须为每个链接重复相同的代码。在这里,我们能够保持模板 DRY 并且读起来非常好。

要实现 menuLink 标记,您需要一个如下所示的拼接拼接:

import Control.Monad.Trans.Class (lift) -- transformers 
import Data.Text.Encoding (decodeUtf8)
import Text.XmlHtml (getAttribute, setAttribute, elementTag)

menuLinkSplice :: MonadSnap m => HeistT m Template
menuLinkSplice = do
    requestPath <- lift $ withRequest (return . rqURI)
    node <- getParamNode
    let addActive n = if getAttribute "href" n == Just (decodeUtf8 requestPath)
                           then setAttribute "class" "active" n
                           else n
    return [addActive (node { elementTag = "a" })]

然后,要将它们放在一起,您需要将该拼接绑定到 menuLink 标记。在 Snap 应用程序中,您将这样做:

addSplices [ ("menuLink", liftHeist menuLinkSplice) ]

您还可能会发现我的博文 Looping and Control Flow in Heist 很有帮助(以及我的其他一些带有“抢劫”标签的博文)。

【讨论】:

  • 很好的答案!正是我想要的。对不起,愚蠢的问题,但在let addActive node =...addActive 是什么?
  • 我怎样才能让拼接输出&lt;li&gt;&lt;a href="..."&gt;Blah&lt;/a&gt;&lt;/li&gt; 而不仅仅是a 标签?我真的没有走正确的路:return [addActive (node (node {elementTag ="li" {elementTag="a"} ... ???
  • addActive 只是他在本地定义的一个函数,格式问题。
  • @AdamBergmark 啊啊啊!谢谢!节点变量名称相同真的让我很困惑。
  • 如果您错过了我的 IRC 评论,请检查 hackage.haskell.org/packages/archive/xmlhtml/0.2.0.2/doc/html/… 中的 Node 定义以嵌套元素。
【解决方案2】:

据我所知,Heist 甚至要求您将这种逻辑放入 Haskell 而不是 Heist。例如,参见docs for Text.Templating.Heist 中的这个示例:

link :: Text -> Text -> X.Node
link target text = X.Element "a" [("href", target)] [X.TextNode text]

loginLink :: X.Node
loginLink = link "/login" "Login"

logoutLink :: Text -> X.Node
logoutLink user = link "/logout" (T.append "Logout " user)

loginLogoutSplice :: Splice MyAppMonad
loginLogoutSplice = do
    user <- lift getUser
    return [maybe loginLink logoutLink user]

这里不是将 Bool 传递给模板,并让模板执行 if/then 逻辑,而是在 Haskell 级别执行所有逻辑。这是我能给出的最好答案。我不熟悉抢劫;我知道您可以提供拼接参数,但我不清楚如何完成您的特定任务。

【讨论】:

  • 谢谢,但我完全不明白如何使用它。更重要的是,Snap 为您生成的初始项目的功能与 Snap 文档或其示例完全不同,我不知道该放在哪里。令人沮丧... :-(
  • 是的,抢劫文件似乎缺乏很多。在 freenode irc 上尝试#snapframework。
猜你喜欢
  • 1970-01-01
  • 2022-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-05
  • 1970-01-01
  • 2016-11-19
  • 2016-11-27
相关资源
最近更新 更多