javascript 带有 Angular UI-Router 的动态主体类

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28204606/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 08:34:56  来源:igfitidea点击:

Dynamic body class with Angular UI-Router

javascriptangularjsangular-ui-router

提问by Fabrizio Fenoglio

I'm trying to find an elegant way to have a custom dynamically class of the body tagthat I can set easily from the ui-router configurationsand if none is set, I can use a default option or none.

我试图找到一种优雅的方式来拥有一个自定义动态类的body 标签,我可以很容易地设置它ui-router configurations,如果没有设置,我可以使用默认选项或无。

Example:

例子:

routes.js

路由.js

$stateProvider
      .state('login', {
           url: "/login",
           template: 'Login'
      })
      .state('register', {
           url: "/register",
           template: 'Register'
      }).
      .state('profile', {
           url: "/profile",
           template: 'Profile'
      });;

Simple markup HTML

简单的标记 HTML

<html>
   <body class=""> <!-- Dynamically class to change -->
      <div ui-view></div>
   </body>
</html>

Scenario:

设想:

1 - Visiting the stateloginI should have the classof the body equals to auth

1 - 访问state登录我应该有身体的等于auth

2 - Visiting the stateregisterat this point it will have the same authclass

2 - 此时访问state寄存器,它将具有相同的auth

3 - Visiting the stateprofilethe body will have the defaultclass or none

3 - 访问state个人资料,正文将具有默认类或

How do you achieve that?

你如何做到这一点?

回答by jmq

You can have a master AppController that controls this:

您可以拥有一个主 AppController 来控制它:

<html ng-app="app" ng-controller="AppController as appController">
...
<body class="{{ appController.bodyClasses }}">

Inside AppController:

在 AppController 内部:

var vm = this;
vm.bodyClasses = 'default';

// this'll be called on every state change in the app
$scope.$on('$stateChangeSuccess', function(event, toState, toParams, fromState, fromParams){
    if (angular.isDefined(toState.data.bodyClasses)) {
        vm.bodyClasses = toState.data.bodyClasses;
        return;
    }

    vm.bodyClasses = 'default';
});

Inside your route defs:

在您的路线定义中:

  .state('register', {
       url: "/register",
       template: 'Register',
       data: {
           bodyClasses: 'auth'
       }
  });

See UI Router documentationfor more on this data-attribute strategy.

有关此数据属性策略的更多信息,请参阅UI 路由器文档

回答by JeremyWeir

Here's a similar approach as @jmq's using state data, but implemented as a directive instead of a controller. (The nice thing about the directive is you can apply this to any arbitrary elements)

这是与@jmq 使用状态数据类似的方法,但作为指令而不是控制器实现。(该指令的好处是您可以将其应用于任何任意元素)

Example Markup

示例标记

<body ng-app="app" route-css-classnames>

Routes Config (routes.js)

路由配置 (routes.js)

$stateProvider
  .state('login', {
       url: "/login",
       template: 'Login',
       data : {
           cssClassnames : 'auth'
       }
  })
  .state('register', {
       url: "/register",
       template: 'Register',
       data : {
           cssClassnames : 'auth'
       }
  }).
  .state('profile', {
       url: "/profile",
       template: 'Profile'
  });

Directive (routeCssClassnames.js)

指令 (routeCssClassnames.js)

(function () {
    'use strict';

    angular.module('shared').directive('routeCssClassnames', routeCssClassnames);

    function routeCssClassnames($rootScope) {
        return {
            restrict: 'A',
            scope: {},
            link: function (scope, elem, attr, ctrl) {

                $rootScope.$on('$stateChangeSuccess', function (event, toState, toParams, fromState, fromParams) {
                    var fromClassnames = angular.isDefined(fromState.data) && angular.isDefined(fromState.data.cssClassnames) ? fromState.data.cssClassnames : null;
                    var toClassnames = angular.isDefined(toState.data) && angular.isDefined(toState.data.cssClassnames) ? toState.data.cssClassnames : null;

                    // don't do anything if they are the same
                    if (fromClassnames != toClassnames) {
                        if (fromClassnames) {
                            elem.removeClass(fromClassnames);
                        }

                        if (toClassnames) {
                            elem.addClass(toClassnames);
                        }
                    }
                });
            }
        }
    }
}());

回答by Eduardo La Hoz Miranda

You could also apply this on your body tag or wherever you need it.

您也可以将其应用到您的身体标签或任何您需要的地方。

ng-class="$state.current.name"

回答by cbaigorri

This is just a version of @JeremyWeir's directive using [email protected] transition hooks.

这只是使用 [email protected] 转换钩子的 @JeremyWeir 指令的一个版本。

import angular from 'angular';

class RouteCssClassNamesDirective {
  constructor($transitions) {
    this.$transitions = $transitions;
    this.restrict = 'A';
  }

  link(scope, element, attrs) {
    this.$transitions.onSuccess({}, (trans) => {
      const fromClassNames = angular.isDefined(trans.from().data) && angular.isDefined(trans.from().data.cssClassNames) ? trans.from().data.cssClassNames : null;
      const toClassNames = angular.isDefined(trans.to().data) && angular.isDefined(trans.to().data.cssClassNames) ? trans.to().data.cssClassNames : null;
      if (fromClassNames !== toClassNames) {
        if (fromClassNames) {
          element.removeClass(fromClassNames);
        }
        if (toClassNames) {
          element.addClass(toClassNames);
        }
      }
    });
  }

  static create() {
    return new RouteCssClassNamesDirective(...arguments);
  }

}

RouteCssClassNamesDirective.create.$inject = ['$transitions'];

export default angular.module('shared')
  .directive('routeCssClassNames', RouteCssClassNamesDirective.create);