如何为带有动态参数的页面提供面包屑?

How to Provide Breadcrumbs for Page with dynamic Parameters?

我找到了一个用于生成面包屑的 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>

此文件由标签库评估和打印:

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 会根据您要显示的用户而变化。

中间面包屑 link 需要动态参数时如何处理?

您的面包屑导航似乎采用 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。如果您改用会话范围的服务,则对面包屑代码进行单元测试会更容易。

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

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>
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>