如何使用 AngularJS + Angular UI Router 制作自动动态面包屑 [英] How to make Automated Dynamic Breadcrumbs with AngularJS + Angular UI Router

查看:32
本文介绍了如何使用 AngularJS + Angular UI Router 制作自动动态面包屑的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Web 应用程序的一个关键组件是面包屑/导航.使用 Angular UI Router,将面包屑元数据与各个状态一起放置是有意义的,而不是放在您的控制器中.为每个需要的控制器手动创建面包屑对象是一项简单的任务,但也是一项非常麻烦的任务.

One key component to web applications is breadcrumbs/navigation. With Angular UI Router, it would make sense to put the breadcrumb metadata with the individual states, rather than in your controllers. Manually creating the breadcrumbs object for each controller where it's needed is a straight-forward task, but it's also a very messy one.

我见过一些使用 Angular 实现自动面包屑导航的解决方案,但老实说,它们相当原始.某些状态,如对话框或侧面板不应该更新面包屑,但使用当前的 angular 插件,无法表达.

I have seen some solutions for automated Breadcrumbs with Angular, but to be honest, they are rather primitive. Some states, like dialog boxes or side panels should not update the breadcrumbs, but with current addons to angular, there is no way to express that.

另一个问题是面包屑的标题不是静态的.例如,如果您转到用户详细信息"页面,面包屑标题可能应该是用户的全名,而不是通用的用户详细信息".

Another problem is that titles of breadcrumbs are not static. For example, if you go to a User Detail page, the breadcrumb title should probably be the user's Full Name, and not a generic "User Detail".

最后一个需要解决的问题是为父链接使用所有正确的状态参数值.例如,如果您正在查看公司的用户详细信息页面,显然您想知道父状态需要 :companyId.

The last problem that needs to be solved is using all of the correct state parameter values for parent links. For example, if you're looking at a User detail page from a Company, obviously you'll want to know that the parent state requires a :companyId.

是否有任何 angular 插件提供这种级别的面包屑支持?如果没有,最好的方法是什么?我不想弄乱我的控制器 - 我会有很多控制器 - 我想让它尽可能自动化和轻松.

Are there any addons to angular that provide this level of breadcrumbs support? If not, what is the best way to go about it? I don't want to clutter up my controllers - I will have a lot of them - and I want to make it as automated and painless as possible.

谢谢!

推荐答案

我不久前自己解决了这个问题,因为没有可用的东西.我决定不使用 data 对象,因为我们实际上不希望我们的面包屑标题被孩子们继承.有时会出现模态对话框和右侧面板,它们在技术上是子视图",但它们不应该影响面包屑.通过使用 breadcrumb 对象,我们可以避免自动继承.

I did solve this myself awhile back, because nothing was available. I decided to not use the data object, because we don't actually want our breadcrumb titles to be inherited by children. Sometimes there are modal dialogs and right panels that slide in that are technically "children views", but they shouldn't affect the breadcrumb. By using a breadcrumb object instead, we can avoid the automatic inheritance.

对于实际的 title 属性,我使用了 $interpolate.我们可以将我们的面包屑数据与解析范围结合起来,而不必在不同的地方进行解析.在我遇到的所有情况下,我只是想使用解析范围,所以这非常有效.

For the actual title property, I am using $interpolate. We can combine our breadcrumb data with the resolve scope without having to do resolves in a different place. In all of the cases I had, I just wanted to use the resolve scope anyway, so this works very well.

我的解决方案也处理 i18n.

My solution also handles i18n too.

$stateProvider
    .state('courses', {
        url: '/courses',
        template: Templates.viewsContainer(),
        controller: function(Translation) {
            Translation.load('courses');
        },
        breadcrumb: {
            title: 'COURSES.TITLE'
        }
    })
    .state('courses.list', {
        url: "/list",
        templateUrl: 'app/courses/courses.list.html',
        resolve: {
            coursesData: function(Model) {
                return Model.getAll('/courses');
            }
        },
        controller: 'CoursesController'
    })
    // this child is just a slide-out view to add/edit the selected course.
    // It should not add to the breadcrumb - it's technically the same screen.
    .state('courses.list.edit', {
        url: "/:courseId/edit",
        templateUrl: 'app/courses/courses.list.edit.html',
        resolve: {
            course: function(Model, $stateParams) {
                return Model.getOne("/courses", $stateParams.courseId);
            }
        },
        controller: 'CourseFormController'
    })
    // this is a brand new screen, so it should change the breadcrumb
    .state('courses.detail', {
        url: '/:courseId',
        templateUrl: 'app/courses/courses.detail.html',
        controller: 'CourseDetailController',
        resolve: {
            course: function(Model, $stateParams) {
                return Model.getOne('/courses', $stateParams.courseId);
            }
        },
        breadcrumb: {
            title: '{{course.name}}'
        }
    })
    // lots more screens.

我不想将面包屑与指令联系起来,因为我认为可能有多种方法可以在我的应用程序中直观地显示面包屑.所以,我把它放到了一个服务中:

I didn't want to tie the breadcrumbs to a directive, because I thought there might be multiple ways of showing the breadcrumb visually in my application. So, I put it into a service:

.factory("Breadcrumbs", function($state, $translate, $interpolate) {
    var list = [], title;

    function getProperty(object, path) {
        function index(obj, i) {
            return obj[i];
        }

        return path.split('.').reduce(index, object);
    }

    function addBreadcrumb(title, state) {
        list.push({
            title: title,
            state: state
        });
    }

    function generateBreadcrumbs(state) {
        if(angular.isDefined(state.parent)) {
            generateBreadcrumbs(state.parent);
        }

        if(angular.isDefined(state.breadcrumb)) {
            if(angular.isDefined(state.breadcrumb.title)) {
                addBreadcrumb($interpolate(state.breadcrumb.title)(state.locals.globals), state.name);
            }
        }
    }

    function appendTitle(translation, index) {
        var title = translation;

        if(index < list.length - 1) {
            title += ' > ';
        }

        return title;
    }

    function generateTitle() {
        title = '';

        angular.forEach(list, function(breadcrumb, index) {
            $translate(breadcrumb.title).then(
                function(translation) {
                    title += appendTitle(translation, index);
                }, function(translation) {
                    title += appendTitle(translation, index);
                }
            );
        });
    }

    return {
        generate: function() {
            list = [];

            generateBreadcrumbs($state.$current);
            generateTitle();
        },

        title: function() {
            return title;
        },

        list: function() {
            return list;
        }
    };
})

实际的面包屑指令变得非常简单:

The actual breadcrumb directive then becomes very simple:

.directive("breadcrumbs", function() {
    return {
        restrict: 'E',
        replace: true,
        priority: 100,
        templateUrl: 'common/directives/breadcrumbs/breadcrumbs.html'
    };
});

和模板:

<h2 translate-cloak>
    <ul class="breadcrumbs">
        <li ng-repeat="breadcrumb in Breadcrumbs.list()">
            <a ng-if="breadcrumb.state && !$last" ui-sref="{{breadcrumb.state}}">{{breadcrumb.title | translate}}</a>
            <span class="active" ng-show="$last">{{breadcrumb.title | translate}}</span>
            <span ng-hide="$last" class="divider"></span>
        </li>
    </ul>
</h2>

从这里的屏幕截图,您可以看到它在两个导航中都完美运行:

From the screenshot here, you can see it works perfectly in both the navigation:

以及 html </code> 标签:<em class="showen"></em></p> <p class="en">As well as the html <code><title></code> tag:</p> <p class="cn"></p> <p class="cn">对 Angular UI 团队的 PS:请立即添加类似的内容!<em class="showen"></em></p> <p class="en">PS to Angular UI Team: Please add something like this out of the box!</p> <p>这篇关于如何使用 AngularJS + Angular UI Router 制作自动动态面包屑的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!</p> </div> <div class="arc-body-main-more"> <span onclick="unlockarc('2524043');">查看全文</span> </div> </div> <div> </div> <div class="wwads-cn wwads-horizontal" data-id="166" style="max-width:100%;border: 4px solid #666;"></div> </div> </article> <div id="arc-ad-2" class="mb-1"> <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5038752844014834" crossorigin="anonymous"></script> <ins class="adsbygoogle" style="display:block" data-ad-format="autorelaxed" data-ad-client="ca-pub-5038752844014834" data-ad-slot="3921941283"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> <div class="widget bgwhite radius-1 mb-1 shadow widget-rel"> <h5>相关文章</h5> <ul> <li> <a target="_blank" title="如何使用 AngularJS + Angular UI Router 制作自动动态面包屑" href="/2531206.html"> 如何使用 AngularJS + Angular UI Router 制作自动动态面包屑; </a> </li> <li> <a target="_blank" title="如何使自动动态面包屑用AngularJS +角UI路由器" href="/198496.html"> 如何使自动动态面包屑用AngularJS +角UI路由器; </a> </li> <li> <a target="_blank" title="简单动态面包屑" href="/1741506.html"> 简单动态面包屑; </a> </li> <li> <a target="_blank" title="Angular 中的面包屑" href="/2525223.html"> Angular 中的面包屑; </a> </li> <li> <a target="_blank" title="jQuery-动态面包屑" href="/1481477.html"> jQuery-动态面包屑; </a> </li> <li> <a target="_blank" title="显示Prime面包屑动态" href="/578682.html"> 显示Prime面包屑动态; </a> </li> <li> <a target="_blank" title="Material-UI面包屑与react-router集成" href="/2296664.html"> Material-UI面包屑与react-router集成; </a> </li> <li> <a target="_blank" title="我如何动态创建面包屑" href="/1266244.html"> 我如何动态创建面包屑; </a> </li> <li> <a target="_blank" title="在MVC中动态面包屑" href="/1354193.html"> 在MVC中动态面包屑; </a> </li> <li> <a target="_blank" title="角面包屑" href="/2177515.html"> 角面包屑; </a> </li> <li> <a target="_blank" title="修剪面包屑" href="/866003.html"> 修剪面包屑; </a> </li> <li> <a target="_blank" title="流星面包屑" href="/2143236.html"> 流星面包屑; </a> </li> <li> <a target="_blank" title="带有链接的 Laravel 动态面包屑" href="/2686668.html"> 带有链接的 Laravel 动态面包屑; </a> </li> <li> <a target="_blank" title="带有链接的Laravel动态面包屑" href="/1539946.html"> 带有链接的Laravel动态面包屑; </a> </li> <li> <a target="_blank" title="如何处理面包屑?" href="/2202788.html"> 如何处理面包屑?; </a> </li> <li> <a target="_blank" title="面包屑在ExtJS" href="/746336.html"> 面包屑在ExtJS; </a> </li> <li> <a target="_blank" title="在角面包屑" href="/194039.html"> 在角面包屑; </a> </li> <li> <a target="_blank" title="SharePoint 2013面包屑" href="/1375471.html"> SharePoint 2013面包屑; </a> </li> <li> <a target="_blank" title="SharePoint细化-面包屑" href="/1340562.html"> SharePoint细化-面包屑; </a> </li> <li> <a target="_blank" title="如何创建 react-router v4 面包屑?" href="/2368641.html"> 如何创建 react-router v4 面包屑?; </a> </li> <li> <a target="_blank" title="具有兄弟状态、UI-Router 和 ncyBreadcrumb 的深度嵌套面包屑" href="/2532502.html"> 具有兄弟状态、UI-Router 和 ncyBreadcrumb 的深度嵌套面包屑; </a> </li> <li> <a target="_blank" title="使用反应路由器的动态面包屑" href="/2364885.html"> 使用反应路由器的动态面包屑; </a> </li> <li> <a target="_blank" title="面包屑使用CSS和javascript" href="/1383302.html"> 面包屑使用CSS和javascript; </a> </li> <li> <a target="_blank" title="zend framework 2动态面包屑-传递参数" href="/1673263.html"> zend framework 2动态面包屑-传递参数; </a> </li> <li> <a target="_blank" title="有没有办法在Angular 6中创建动态面包屑" href="/2177188.html"> 有没有办法在Angular 6中创建动态面包屑; </a> </li> </ul> </div> <div class="mb-1"> <script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-5038752844014834" crossorigin="anonymous"></script> <ins class="adsbygoogle" style="display:block" data-ad-format="autorelaxed" data-ad-client="ca-pub-5038752844014834" data-ad-slot="3921941283"></ins> <script> (adsbygoogle = window.adsbygoogle || []).push({}); </script> </div> </div> <div class="side"> <div class="widget widget-side bgwhite mb-1 shadow"> <h5>前端开发最新文章</h5> <ul> <li> <a target="_blank" title="为什么Chrome(在Electron内部)突然重定向到chrome-error:// chromewebdata?" href="/1996151.html"> 为什么Chrome(在Electron内部)突然重定向到chrome-error:// chromewebdata?; </a> </li> <li> <a target="_blank" title="错误102(net :: ERR_CONNECTION_REFUSED):服务器拒绝连接" href="/749568.html"> 错误102(net :: ERR_CONNECTION_REFUSED):服务器拒绝连接; </a> </li> <li> <a target="_blank" title="如何解决'重定向已被CORS策略阻止:没有'Access-Control-Allow-Origin'标题'?" href="/1009885.html"> 如何解决'重定向已被CORS策略阻止:没有'Access-Control-Allow-Origin'标题'?; </a> </li> <li> <a target="_blank" title="如何处理“Uncaught(in promise)DOMException:play()失败,因为用户没有首先与文档交互。”在桌面上使用Chrome 66?" href="/884909.html"> 如何处理“Uncaught(in promise)DOMException:play()失败,因为用户没有首先与文档交互。”在桌面上使用Chrome 66?; </a> </li> <li> <a target="_blank" title="警告:添加非被动事件侦听器到滚动阻塞'touchstart'事件" href="/818517.html"> 警告:添加非被动事件侦听器到滚动阻塞'touchstart'事件; </a> </li> <li> <a target="_blank" title="如何在浏览器中播放.TS文件(视频/ MP2T媒体类型)?" href="/343346.html"> 如何在浏览器中播放.TS文件(视频/ MP2T媒体类型)?; </a> </li> <li> <a target="_blank" title="此请求已被阻止;内容必须通过HTTPS提供" href="/886417.html"> 此请求已被阻止;内容必须通过HTTPS提供; </a> </li> <li> <a target="_blank" title="资源解释为样式表,但转换为MIME类型text / html(似乎与web服务器无关)" href="/562873.html"> 资源解释为样式表,但转换为MIME类型text / html(似乎与web服务器无关); </a> </li> <li> <a target="_blank" title="通过HTTPS加载页面但请求不安全的XMLHttpRequest端点" href="/885901.html"> 通过HTTPS加载页面但请求不安全的XMLHttpRequest端点; </a> </li> <li> <a target="_blank" title="拒绝从执行脚本'*',因为它的MIME类型(“应用/ JSON')不是可执行文件,并严格MIME类型检查被启用。" href="/47347.html"> 拒绝从执行脚本'*',因为它的MIME类型(“应用/ JSON')不是可执行文件,并严格MIME类型检查被启用。; </a> </li> </ul> </div> <div class="widget widget-side bgwhite mb-1 shadow"> <h5> 热门教程 </h5> <ul> <li> <a target="_blank" title="Java教程" href="/OnLineTutorial/java/index.html"> Java教程 </a> </li> <li> <a target="_blank" title="Apache ANT 教程" href="/OnLineTutorial/ant/index.html"> Apache ANT 教程 </a> </li> <li> <a target="_blank" title="Kali Linux教程" href="/OnLineTutorial/kali_linux/index.html"> Kali Linux教程 </a> </li> <li> <a target="_blank" title="JavaScript教程" href="/OnLineTutorial/javascript/index.html"> JavaScript教程 </a> </li> <li> <a target="_blank" title="JavaFx教程" href="/OnLineTutorial/javafx/index.html"> JavaFx教程 </a> </li> <li> <a target="_blank" title="MFC 教程" href="/OnLineTutorial/mfc/index.html"> MFC 教程 </a> </li> <li> <a target="_blank" title="Apache HTTP客户端教程" href="/OnLineTutorial/apache_httpclient/index.html"> Apache HTTP客户端教程 </a> </li> <li> <a target="_blank" title="Microsoft Visio 教程" href="/OnLineTutorial/microsoft_visio/index.html"> Microsoft Visio 教程 </a> </li> </ul> </div> <div class="widget widget-side bgwhite mb-1 shadow"> <h5> 热门工具 </h5> <ul> <li> <a target="_blank" title="Java 在线工具" href="/Onlinetools/details/4"> Java 在线工具 </a> </li> <li> <a target="_blank" title="C(GCC) 在线工具" href="/Onlinetools/details/6"> C(GCC) 在线工具 </a> </li> <li> <a target="_blank" title="PHP 在线工具" href="/Onlinetools/details/8"> PHP 在线工具 </a> </li> <li> <a target="_blank" title="C# 在线工具" href="/Onlinetools/details/1"> C# 在线工具 </a> </li> <li> <a target="_blank" title="Python 在线工具" href="/Onlinetools/details/5"> Python 在线工具 </a> </li> <li> <a target="_blank" title="MySQL 在线工具" href="/Onlinetools/Dbdetails/33"> MySQL 在线工具 </a> </li> <li> <a target="_blank" title="VB.NET 在线工具" href="/Onlinetools/details/2"> VB.NET 在线工具 </a> </li> <li> <a target="_blank" title="Lua 在线工具" href="/Onlinetools/details/14"> Lua 在线工具 </a> </li> <li> <a target="_blank" title="Oracle 在线工具" href="/Onlinetools/Dbdetails/35"> Oracle 在线工具 </a> </li> <li> <a target="_blank" title="C++(GCC) 在线工具" href="/Onlinetools/details/7"> C++(GCC) 在线工具 </a> </li> <li> <a target="_blank" title="Go 在线工具" href="/Onlinetools/details/20"> Go 在线工具 </a> </li> <li> <a target="_blank" title="Fortran 在线工具" href="/Onlinetools/details/45"> Fortran 在线工具 </a> </li> </ul> </div> </div> </div> <script type="text/javascript">var eskeys = '如何,使用,angularjs,angular,ui,router,制作,自动,动态,面包屑'; var cat = 'cc';';//qianduan</script> </div> <div id="pop" onclick="pophide();"> <div id="pop_body" onclick="event.stopPropagation();"> <h6 class="flex flex101"> 登录 <span onclick="pophide();">关闭</span> </h6> <div class="pd-1"> <div class="wxtip center"> <span>扫码关注<em>1秒</em>登录</span> </div> <div class="center"> <img id="qr" src="https://huajiakeji.com/Content/Images/qrydx.jpg" alt="" style="width:150px;height:150px;" /> </div> <div style="margin-top:10px;display:flex;justify-content: center;"> <input type="text" placeholder="输入验证码" id="txtcode" autocomplete="off" /> <input id="btngo" type="button" onclick="chk()" value="GO" /> </div> <div class="center" style="margin: 4px; font-size: .8rem; color: #f60;"> 发送“验证码”获取 <em style="padding: 0 .5rem;">|</em> <span style="color: #01a05c;">15天全站免登陆</span> </div> <div id="chkinfo" class="tip"></div> </div> </div> </div> <script type="text/javascript" src="https://lib.sinaapp.com/js/jquery/1.9.1/jquery-1.9.1.min.js"></script> <script type="text/javascript" src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.min.js"></script> <script type="text/javascript" src="https://img01.yuandaxia.cn/Scripts/highlight.min.js"></script> <script type="text/javascript" src="https://img01.yuandaxia.cn/Scripts/base.js?v=0.22"></script> <script type="text/javascript" src="https://img01.yuandaxia.cn/Scripts/tui.js?v=0.11"></script> <footer class="footer"> <div class="container"> <div class="flink mb-1"> 友情链接: <a href="https://www.it1352.com/" target="_blank">IT屋</a> <a href="https://huajiakeji.com/" target="_blank">Chrome插件</a> <a href="https://www.cnplugins.com/" target="_blank">谷歌浏览器插件</a> </div> <section class="copyright-section"> <a href="https://www.it1352.com" title="IT屋-程序员软件开发技术分享社区">IT屋</a> ©2016-2022 <a href="http://www.beian.miit.gov.cn/" target="_blank">琼ICP备2021000895号-1</a> <a href="/sitemap.html" target="_blank" title="站点地图">站点地图</a> <a href="/Home/Tags" target="_blank" title="站点标签">站点标签</a> <a target="_blank" alt="sitemap" href="/sitemap.xml">SiteMap</a> <a href="/1155981.html" title="IT屋-免责申明"><免责申明></a> 本站内容来源互联网,如果侵犯您的权益请联系我们删除. </section> <!--统计代码--> <script type="text/javascript"> var _hmt = _hmt || []; (function() { var hm = document.createElement("script"); hm.src = "https://hm.baidu.com/hm.js?0c3a090f7b3c4ad458ac1296cb5cc779"; var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(hm, s); })(); </script> <script type="text/javascript"> (function () { var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </div> </footer> </body> </html>