【问题标题】:How to Provide Breadcrumbs for Page with dynamic Parameters?如何为具有动态参数的页面提供面包屑?
【发布时间】:2023-03-24 23:03:02
【问题描述】:

我找到了一个用于生成面包屑的 Grails 框架here。它确实根据 breadcrumbs.xml 文件中的静态定义生成面包屑,其中定义了面包屑的层次结构:

     <map>
        <nav id="homeCrumb" matchController="samplePages" matchAction="homeBreadCrumbPage">
            <!-- levels navigation -->
            <nav id="itemsLevel1Crumb" matchController="samplePages" matchAction="level1BreadCrumbPage">
                <nav id="itemsLevel2Crumb" matchController="samplePages" matchAction="level2BreadCrumbPage">
                    <nav id="itemsLevel3Crumb" matchController="samplePages" matchAction="level3BreadCrumbPage">
                        <nav id="showItemCrumb" matchController="samplePages" matchAction="itemDetailsBreadCrumbPage"/>
                    </nav>
                </nav>
            </nav>
            <nav id="simple1Crumb" matchController="samplePages" matchAction="simpleBreadCrumb"/>
            <nav id="simple2Crumb" matchController="samplePages" matchAction="simpleBreadCrumbWithAttr"/>
            <!-- levels navigation -->
        </nav>
    </map>

此文件由 taglib 评估和打印:

class BreadCrumbTagLib {

    static def log = LogFactory.getLog("grails.app.breadCrumbTag")

    def breadCrumb = { attrs , body ->

            def manager = BreadCrumbManager.getInstance()
            def uri = request.getRequestURI() 
            def context = request.getContextPath() 

            def controller = params.controller
            def action = params.action

            def attrTitle =  attrs.title
            def attrLink = attrs.link

            // if controller and action are missing from params try to get them from request url
            if (!controller && !action && uri && context && uri.indexOf(context) != -1) {
                def uriParams = uri.substring(uri.indexOf(context) + (context.length() + 1), uri.length())
                def uriArray = uriParams.split('/')

                if (uriArray.size() >= 2 ) {
                    controller = uriArray[0]
                    action = uriArray[1]                       
                }
            }

            def crumbs = manager.getBreadCrumbs(controller, action)

            if (crumbs) {
                out << '<div class="breadcrumb"><ul>'
                def size = crumbs.size()
                crumbs.eachWithIndex { crumb, index ->
                    out << '<li>'

                    // override title and link of breadcrumb on current page (i.e. last bread crumb in hierarchy)
                    // if name, link attributes are supplied
                    if (index == size - 1) {
                        if (attrTitle)
                            crumb.title = attrTitle
                        if (attrLink)
                            crumb.link = attrLink
                    }
                    // set title to undefined if not found, associated 
                    // renderer if present can overwrite it
                    if (!crumb.title)
                        crumb.title = "undefined"
                    if (crumb.title && crumb.title.size() > 40)
                        crumb.title = crumb.title.substring(0, 40) + "..."

                    if (crumb.viewController && crumb.viewAction) {
                        def content = g.include(controller:crumb.viewController, action:crumb.viewAction, breadcrumb:crumb, params:params)
                        out << content
                    } else if (crumb.viewTemplate) {
                        def content = g.include(view:crumb.viewTemplate, breadcrumb:crumb, params: params)
                        out << content
                    } else if (crumb.linkToController && crumb.linkToAction && (size - 1 > index)){
                        out << "<a href=\"${g.createLink (controller: crumb.linkToController, action: crumb.linkToAction)}\">${crumb.title}</a>"
                    // if crumb has a link and its not the last vread crumb then show link else
                    // just show the text
                    } else if (crumb.link && (size - 1 > index)){
                        out << "<a href=\"${crumb.link}\">${crumb.title}</a>"
                    } else {
                        out << "${crumb.title}"
                    }
                    out << "</li>"
                    // do not print for last bread crumb
                    if (size - 1 > index)
                        out << "<li>&raquo;</li>"
                }
                out << "</ul></div>"
            }
    }
}  

问题:当我的结构需要一些无法修复的参数时。

示例:我在导航的第三级可以说

A1 / A2 / A3

在我的情况下,A2 应该打开一个类似user/show/1234 的页面,其中 1234 是要显示的用户 ID。问题是我无法在 breadcrumbs.xml 文件中添加 1234 硬编码,因为此 id 会根据您要显示的用户而变化。

当中间面包屑链接需要动态参数时,我该如何处理?

【问题讨论】:

  • 该插件不是为该用例设计的。它专为面包屑的静态映射而设计。您需要 fork 插件并使其具有此功能,或使用其他方式创建面包屑。
  • 你能画出怎么做吗?
  • 好吧,你需要为标签提供一个新属性,这将是你想要用来获取值的实例(例如,id 值)然后出现使用配置 xml 中的一些新属性,您可以存储一个模式,您将在标签库中评估以将参数添加到正在生成的 href 的 URL。我建议您查看一些内置 Grails 标记的源代码,看看是否可以从那里获得有关如何执行此操作的任何想法(特别是链接标记)。
  • 您能否在更详细的答案中提供它。至少在哪里设置面包屑正在获取的参数?
  • 您的想法的问题是您只能对面包屑中的最后一个标签执行此操作。但是,您需要之前访问过的标签的标签属性。生成链接。您不需要当前面包屑的链接。你会如何解决这个问题?

标签: html grails groovy breadcrumbs


【解决方案1】:

再想一想,我意识到最好不要使用 HttpSession。如果您改用会话范围的服务,则对面包屑代码进行单元测试会更容易。

首先,创建一个会话范围的服务来维护用户的导航历史记录。

class NavigationHistoryService {
    static transactional = false
    static scope = "session"

    def history = [:]

    public List push(String controller, String action, Map params) {
        def crumb = [
            action: action, 
            params: params]

        history.controller = crumb

        return history
    }   

在您的控制器中注入服务并使用它来跟踪用户所在的位置。然后将历史记录添加为操作模型返回的内容的一部分:

class CompanyController {
    def navigationHistoryService

    def show() {
        navigationHistoryService.push('company', 'show', params)
        ...
        [crumbs: navigationHistoryService.history] 
    }
}

最后,使用 GSP 中的历史记录来呈现面包屑。

<ol class="breadcrumb">
    <li><g:link controller="company" action="${crumbs.company.action}" params="${crumbs.company.params}">SOMETHING</a></li>
</ol>

【讨论】:

  • 我喜欢这篇文章中的做法:adityakalia.wordpress.com/2011/01/10/… 带有 xml 文件。 XML 文件定义了碎屑的层次结构。您是否看到如何将其集成到您的方法中,或者您是否看到了更新其他方法的方法?
  • 层次结构是这样的吗:(company/show/ID) / (user/showall/ID) / (user/show/ID)?换句话说,是不是每个关卡都保留了controller和action,只有ID发生了变化?
  • 是的,你明白了。 id 旁边可能还有其他参数,但基本上就是这样。有什么想法吗?
  • 我更改了它以保持每个级别固定。它不像历史堆栈那样工作,它跟踪每个控制器的最后一个动作和参数。
  • 我仍然看不到它如何与我显示的链接中的现有代码集成在一起。我给你一个提议。我从这篇 50Reps 的帖子中获得了赏金。您详细描述了我必须如何更改和扩展现有代码:adityakalia.wordpress.com/2011/01/10/… 这听起来对您公平吗?
【解决方案2】:

您的面包屑似乎采用 CONTROLLER/ACTION/ID 格式。如果是这样,您需要的信息已经通过 webRequest 属性在您的 GSP 中可用。下面是一个使用 Twitter Bootstrap 面包屑的示例:

<ol class="breadcrumb">
  <li><a href="#">${webRequest.controllerName}</a></li>
  <li><a href="#">${webRequest.actionName}</a></li>
  <li class="active">${webRequest.id}</li>
</ol>

您仍然需要将 href 设置为有意义的内容。更强大的方法是这样的......

<g:set var="crumbs" value="${[webRequest.controllerName, webRequest.actionName, webRequest.id].findAll { it != null }}.collect { [label: it, active: false] }" />
<% crumbs.last().active = true %>
<ol class="breadcrumb">
    <g:each in="${crumbs}">
        <li class="${it.active ? 'active' : ''}"><a href="#">${it.label}</a></li>
    </g:each>
</ol>

不推荐通过 标记将 Groovy 代码嵌入 GSP,但可以在 TagLib 中完成类似的操作。这种方法可以处理长度为 1-3 部分的面包屑。它根据当前的 URI 进行调整。

【讨论】:

  • 是的,但是这种方法只适用于当前请求。我的问题是如何将链接设置为上一页的面包屑。这可能行不通?你怎么看?
  • 哦哦哦。 现在我明白你要做什么了。您可以在控制器操作方法中使用 HttpSession 来维护面包屑历史记录。例如:session.crumbs.add(WHATEVER) 然后你可以循环遍历 GSP 中的 session.crumbs 来渲染面包屑。
  • 您能否更新您的答案并更详细地解释一下?问题是当前 url 没有指示最后一个是什么,即使它们应该在层次结构中。问题是当您转到 A -> B -> A 时,您不想添加 A 两次。期待您的回复。谢谢!
  • 由于方法完全不同,我将创建一个新答案。我的错误可以永远留在这里。
  • 是的,你可以这样做。我期待着它。为你的努力投上一票。
【解决方案3】:
use simple by blade view
 <ul class="breadcrumb" style="padding-right: 20px">
                <li> <i class="fa fa-home"></i> <a class="active" href="{{url('/')}}">Home</a>
                    {{--<i class="fa fa-angle-right"></i>--}}
                </li> <?php $link = url('/') ; ?>
                @for($i = 1; $i <= count(Request::segments()); $i++)
                    <li>
                        @if($i < count(Request::segments()) & $i > 0)
                            <?php $link .= "/" . Request::segment($i); ?>
                                <a class="active" href="<?= $link ?>">{{Request::segment($i)}}</a>
                                {{--{!!'<i class="fa fa-angle-right"></i>'!!}--}}
                        @else {{Request::segment($i)}}
                        @endif
                    </li>
                @endfor
            </ul>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 2019-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多