如何使用$ mdTheming将主题应用于自定义元素

时间:2015-11-13 11:40:51

标签: angularjs angular-material

我一直试图找出一种方法来使用$mdTheming库提供的angular-material服务来应用通过$mdThemingProvider配置的主题。

简单来说:

考虑一个元素

<div class="md-primary" theme></div>

在这种情况下,theme 指令必须 注入 主色配置到主题。

通过angular-material代码

后,我尝试使用的方法如下
  

只是为了看看他们是如何做到的

export function ThemeDirective($mdTheming) {
 'ngInject';

 let directive = {
   restrict: 'A',
   link: (scope, element) => {
    $mdTheming(element);
   }
 };

  return directive
}

以上代码似乎没有做任何事情。我确定我忽视了一些事情。需要帮助。

1 个答案:

答案 0 :(得分:0)

这可能有助于您的研究......您可以使用它来将主题应用于您的指令。我从链接https://material.angularjs.org/latest/Theming/05_under_the_hood

开始

当您进一步查看角度代码时,您将找到常量$ MD_THEME_CSS。这基本上是一个css文件,其中包含每个指令的所有样式 - 但它使用内插的标记进行格式化:


    ...
    md-input-container.md-THEME_NAME-theme .md-input {
        color: {{foreground-1}};
        border-color: {{foreground-4}};
        text-shadow: {{foreground-shadow}};
    }

    md-input-container.md-THEME_NAME-theme .md-input::-webkit-input-placeholder,md-input-container.md-THEME_NAME-theme .md-input::-moz-placeholder,md-input-container.md-THEME_NAME-theme .md-input:-moz-placeholder,md-input-container.md-THEME_NAME-theme .md-input:-ms-input-placeholder {
        color: {{foreground-3}};
    }
    ...

这些用颜色值替换的标签显示在mdThemingProvider ...

的文档中

    /* Some Example Valid Theming Expressions
     * =======================================
     * Intention group expansion: (valid for primary, accent, warn, background)
     * {{primary-100}} - grab shade 100 from the primary palette
     * {{primary-100-0.7}} - grab shade 100, apply opacity of 0.7
     * {{primary-100-contrast}} - grab shade 100's contrast color
     * {{primary-hue-1}} - grab the shade assigned to hue-1 from the primary palette
     * {{primary-hue-1-0.7}} - apply 0.7 opacity to primary-hue-1
     * {{primary-color}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured shades set for each hue
     * {{primary-color-0.7}} - Apply 0.7 opacity to each of the above rules
     * {{primary-contrast}} - Generates .md-hue-1, .md-hue-2, .md-hue-3 with configured contrast (ie. text) color shades set for each hue
     * {{primary-contrast-0.7}} - Apply 0.7 opacity to each of the above rules
     *
     * Foreground expansion: Applies rgba to black/white foreground text
     * {{foreground-1}} - used for primary text
     * {{foreground-2}} - used for secondary text/divider
     * {{foreground-3}} - used for disabled text
     * {{foreground-4}} - used for dividers
     */

然后,在定义了所有主题之后,通过generateAllThemes()在运行时格式化此字符串。这会将这些样式注入&lt; head&gt;元素 - 通过在chrome中检查页面可以看到: enter image description here

现在我从未在个人面前做过这个,所以我不知道这里的标准,也找不到记录。但是我假设您可以调用GenerateTheme()以某种方式生成您自己的样式以在您的html中使用...或者可能只是借用一些已经为核心代码生成的类。

然而,我使用自己的服务而不是他们的服务做了类似的事情。

这里有可能开始我过去使用过的解决方案......我在我的.config中定义了主题之后编写了一个简单的提供程序来保存我的主题调色板( )。然后我写了一个服务,将主题颜色代码连接到实际的rgb颜色。希望它不是太苛刻。

&#13;
&#13;
(function() {
  var app = angular.module('MyApp', ['ngMaterial', 'ngMessages'])

  // The provider... I store the color palette here since a service isn't available during .config();
  .provider('colorPalette', function colorPaletteProvider() {
    var _PALETTE = {};

    this.SetPalette = function(value) {
      _PALETTE = value
    }

    this.$get = [
      function() {
        return _PALETTE;
      }
    ];
  })

  .config(function($mdThemingProvider, colorPaletteProvider) {
    var xoMap = $mdThemingProvider.extendPalette('purple', {
      '500': '833A96'
    });
    $mdThemingProvider.definePalette('XO-Main', xoMap);

    // add a couple of themes
    $mdThemingProvider.theme('default')
      .primaryPalette('XO-Main')
      .accentPalette('pink', {
        "default": "500",
        "hue-1": "50"
      })
      .backgroundPalette('grey');

    $mdThemingProvider.theme('order')
      .primaryPalette('XO-Main')
      .accentPalette('light-blue', {
        "default": "500",
        "hue-1": "50"
      });

    // save the palette so i can see it later
    colorPaletteProvider.SetPalette($mdThemingProvider._PALETTES);
  })

  .run(function($interpolate, themeColorsService) {
    // inject some styles into the head
    var orderTheme = themeColorsService.GetColors("order");
    var myStyle = $interpolate(".nav-icon-order {color: {{accent.default.bg}};}")(orderTheme);
    console.debug(myStyle);
    themeColorsService.AddStyle(myStyle);
    themeColorsService.AddStyle($interpolate("md-toolbar.hpbx-toolbar-accent-order, .panel-heading.hpbx-toolbar-accent-order { border-bottom: 5px solid {{accent.default.bg}};}")(orderTheme));

  });

  // The controller
  app.controller("AppCtrl", function($scope, themeColorsService) {
    $scope.themeColors = themeColorsService.GetColors("default");
  });
})();

// example directive where the theme is passed in
angular.module('MyApp').directive('theme', function (themeColorsService) {
        return {
            restrict: "A",
            transclude: true,
            template: "<div ng-style='{color: themeColors.primary.default.bg}' ng-transclude></div>",
            scope: {
                themeName: "="
            },
            controller: function ($scope, $element, $attrs) {
                $scope.themeColors = themeColorsService.GetColors("default");
            }
        }
    });

// The service
angular.module('MyApp').service("themeColorsService", function(colorPalette, $mdTheming) {
  this.themes = {};

  // tie the color codes together with the palettes
  this.GetColors = function(theme) {
    var returnVal = {};
    if (!this.themes.hasOwnProperty(theme)) {
      theme = $mdTheming.THEMES[theme];

      _.keys(theme.colors).forEach(function(key) {
        returnVal[key] = {};
        var palette = theme.colors[key].name;
        if (!_.isUndefined(palette)) {
          _.keys(theme.colors[key].hues).forEach(function(hue) {
            var c = theme.colors[key].hues[hue];
            var p = colorPalette[palette][c];

            returnVal[key][hue] = {};
            returnVal[key][hue].bg = getRGB(p.value);
            returnVal[key][hue].fg = getRGB(p.contrast);
          });
        }
      });

      this.themes[theme] = _.cloneDeep(returnVal);
    }

    return this.themes[theme];
  };

  var getRGB = function(value) {
    var returnVal = "";

    if (value.length == 4) {
      returnVal = "rgba(" + value[0] + "," + value[1] + "," + value[2] + "," + value[3] + ")";
    } else if (value.length == 3) {
      returnVal = "rgb(" + value[0] + "," + value[1] + "," + value[2] + ")";
    }

    return returnVal;
  };

  // insert a style into the head element
  this.AddStyle = function(styleContent) {
    var head = document.head;
    var firstChild = head ? head.firstElementChild : null;

    var style = document.createElement('style');
    style.setAttribute('xo-theme-style', '');
    style.appendChild(document.createTextNode(styleContent));
    head.insertBefore(style, firstChild);
  };
});
&#13;
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-messages.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-route.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-aria.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.6/angular-material.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/1.0.6/angular-material.css" rel="stylesheet" />

<html ng-app="MyApp">

<body>
  <div ng-controller="AppCtrl">
    <div>I'm unstyled</div>
    
    <!-- style using ng-style -->
    <div ng-style="{color: themeColors.primary.default.bg}">I'm styled with ngStyle</div>
    
    <!-- use your injected css style -->
    <div class="nav-icon-order">I'm using an injected css class</div>
    
    <!-- send it to a directive the way you listed in your example -->
    <div theme>This is a styled directive</div>
    
    <!-- show the themeColors object -->
    <pre>themeColors:{{themeColors | json}}</pre>
  </div>
</body>

</html>
&#13;
&#13;
&#13;