当状态发生变化时,如何防止重新加载命名视图?AngularJS UI-路由器视图、路由器、如何防止、加载

2023-09-06 08:23:09 作者:羁绊

我在我的应用程序中使用了出色的 ui-router 模块.作为其中的一部分,我使用命名视图来管理应用程序中的动态子导航".

考虑以下几点:

$urlRouterProvider.otherwise('/person/list');$stateProvider.state('人', {网址:'/人',摘要:真实,}).state('person.list', {网址:'/列表',意见:{主要的@": {模板网址:person.list.html",控制器:'PersonListController'}}}).state('person.details', {网址:'/{id}',意见:{'主要的@': {templateUrl: "person.details.html",控制器:'PersonController'},'导航@':{templateUrl: "person.nav.html",控制器:'PersonNavController'}}});
三大 JS 框架的较量 Angular.js 与 React.js 与 Ember.js

当用户首次访问该应用时,他们会看到一个人员列表.当他们点击一个人时,他们会被带到详细信息页面.很基本的东西.如果有帮助,这里是标记...

<aside ui-view="nav"></aside><div ui-view="main"></div></div>

但是,PersonNavController 调用 REST 服务来获取人员列表,因此在查看人员时,用户可以导航同级元素.使用上述方法会导致模板和控制器重新渲染,从而在每次点击后导致延迟,尽管内容从未改变.

有没有办法让 'nav@' 视图保持加载状态,并且只刷新 'main@' 视图?

解决方案

我在这种情况下使用 ui-router 的方式是:将视图移到最小公分母上时间>.

换句话说:如果 ui-view="nav" 在所有细节之间共享并且对所有细节都相同(因为它应该只加载一次) - 它应该是 list 状态的一部分 (detail 状态的父级)

父状态定义会这样调整:

.state('person.list', {网址:'/列表',意见:{主要的@": {模板网址:person.list.html",控制器:'PersonListController'}//这里我们针对 person.list.html//及其 ui-view="nav"'nav@person.list': {templateUrl: "person.nav.html",控制器:'PersonNavController'}}

那么诀窍在哪里?在角度 ui-router 的力量下.我们可以,在每个状态定义期间,以当前视图为目标.现在,nav 视图是 list 状态定义的一部分 - 即它不会在细节切换期间重新加载(另请检查 这里了解更多说明)

我们只需要使用定义的命名约定,请参阅:

查看名称 - 相对名称与绝对名称

上述文档中引用的几行:

浏览量:{/////////////////////////////////相对定位////目标父状态 ui-view 的///////////////////////////////////在此状态的父状态联系人"中相对定位详细信息"视图.//<div ui-view='detail'/>在contacts.html中细节" : { },//相对定位在此状态的父状态联系人"中的未命名视图.//<div ui-view/>在contacts.html中":{},////////////////////////////////////////////////使用 '@' 的绝对定位////以该状态内的任何视图或祖先为目标//////////////////////////////////////////////////绝对针对此状态下的 'info' 视图,'contacts.detail'.//<div ui-view='信息'/>在contacts.detail.html中info@contacts.detail":{}//绝对针对处于联系人"状态的详细信息"视图.//<div ui-view='detail'/>在contacts.html中详细信息@联系人":{ }

I'm using the excellent ui-router module in my application. As part of this, I'm using named views to manage the 'dynamic sub-navigation' I have in the app.

Consider the following:

$urlRouterProvider.otherwise('/person/list');

$stateProvider
    .state('person', {
        url: '/person',
        abstract: true,
    })
    .state('person.list', {
        url: '/list',
        views: {
            "main@": {
                templateUrl: "person.list.html",
                controller: 'PersonListController'
            }
        }
    })
    .state('person.details', {
        url: '/{id}',
        views: {
            'main@': {
                templateUrl: "person.details.html",
                controller: 'PersonController'
            },
            'nav@': {
                templateUrl: "person.nav.html",
                controller: 'PersonNavController'
            }
        }
    });

When users first visit the app, they are presented with a list of people. When they click on a person, they are taken to the details page. Pretty basic stuff. Here's the markup if it helps...

<div>
    <aside ui-view="nav"></aside>
    <div ui-view="main"></div>
</div>

However, the PersonNavController calls a REST service to get a list of people, so when viewing a person, the user is able to navigate sibling elements. Using the method above causes the template and controller to re-render, thus causing a delay after every click, despite the content never changing.

Is there a way to keep the 'nav@' view loaded, and only refresh the 'main@' view?

解决方案

The way I am using ui-router in this scenarios is: move the views to the least common denominator.

Other words: In case that ui-view="nav" is shared among all the details and is the same for all of them (because it should be loaded only once) - it should be part of the list state (parent of the detail state)

the parent state defintion would be adjusted like this:

.state('person.list', {
    url: '/list',
    views: {
        "main@": {
            templateUrl: "person.list.html",
            controller: 'PersonListController'
        }
        // here we target the person.list.html
        // and its ui-view="nav"
        'nav@person.list': {
            templateUrl: "person.nav.html",
            controller: 'PersonNavController'
        }
    }

So where is the trick? In the power of the angular ui-router. We can, during each state defintion, target the current view. Now, the nav view is part of the list state definition - i.e. it will not be reloaded during the detail switching (also check here for more explanation)

We just have to use the defined naming conventions, see:

View Names - Relative vs. Absolute Names

Few cited lines from the mentioned documentation:

views: {
    ////////////////////////////////////
    // Relative Targeting             //
    // Targets parent state ui-view's //
    ////////////////////////////////////

    // Relatively targets the 'detail' view in this state's parent state, 'contacts'.
    // <div ui-view='detail'/> within contacts.html
    "detail" : { },            

    // Relatively targets the unnamed view in this state's parent state, 'contacts'.
    // <div ui-view/> within contacts.html
    "" : { }, 

    ///////////////////////////////////////////////////////
    // Absolute Targeting using '@'                      //
    // Targets any view within this state or an ancestor //
    ///////////////////////////////////////////////////////

    // Absolutely targets the 'info' view in this state, 'contacts.detail'.
    // <div ui-view='info'/> within contacts.detail.html
    "info@contacts.detail" : { }

    // Absolutely targets the 'detail' view in the 'contacts' state.
    // <div ui-view='detail'/> within contacts.html
    "detail@contacts" : { }