如何为带有动态参数的页面提供面包屑?
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>»</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>
我找到了一个用于生成面包屑的 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>»</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>