You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Angular v5.x中如何动态获取Angular Material自定义主题列表?

Hey there! Let's figure out how to dynamically pull in all your custom Angular Material themes without hardcoding their names—perfect for populating that dropdown menu. Since you're working with Angular v5.x, I’ll focus on solutions that play nice with this specific version:

Solution 1: Extract Themes from Loaded Stylesheets

If your themes are applied via CSS classes (like theme-dark, theme-ocean), you can scan the app's loaded stylesheets on initialization to pick up these class names automatically.

Step 1: Add Theme Detection Logic to Your Component

In your root component (e.g., app.component.ts), add code to parse stylesheets and extract theme classes:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  availableThemes: string[] = [];
  selectedTheme: string = 'theme-light'; // Default theme

  ngOnInit() {
    this.extractThemesFromStyles();
    // Set initial theme if needed
    document.body.classList.add(this.selectedTheme);
  }

  private extractThemesFromStyles(): void {
    // Adjust this regex to match your theme class pattern
    const themeClassRegex = /theme-\w+/g;
    const allStylesheets = Array.from(document.styleSheets);

    allStylesheets.forEach(sheet => {
      try {
        const cssRules = Array.from(sheet.cssRules || sheet.rules);
        cssRules.forEach(rule => {
          if ('selectorText' in rule) {
            const matches = (rule as CSSStyleRule).selectorText.match(themeClassRegex);
            if (matches) {
              matches.forEach(match => {
                // Remove the leading dot from the CSS selector
                const className = match.replace('.', '');
                if (!this.availableThemes.includes(className)) {
                  this.availableThemes.push(className);
                }
              });
            }
          }
        });
      } catch (err) {
        // Skip cross-origin stylesheets (like external CDNs)
        console.warn(`Skipping inaccessible stylesheet: ${sheet.href}`);
      }
    });
  }

  switchTheme(themeName: string): void {
    // Remove existing theme classes
    document.body.classList.forEach(cls => {
      if (cls.startsWith('theme-')) document.body.classList.remove(cls);
    });
    // Apply new theme
    document.body.classList.add(themeName);
    this.selectedTheme = themeName;
  }
}

Step 2: Update Your Template for the Dropdown

Use the availableThemes array to populate your Material select:

<mat-select [(value)]="selectedTheme" (selectionChange)="switchTheme($event.value)">
  <mat-option *ngFor="let theme of availableThemes" [value]="theme">
    {{ theme.replace('theme-', '') | titlecase }}
  </mat-option>
</mat-select>
Solution 2: Generate a Theme List at Build Time (More Reliable)

For a more stable approach, generate a static list of themes during your build process. This avoids DOM parsing and works great if your themes are stored in a consistent directory.

Step 1: Create a Node Script to Generate Theme List

Make a file named generate-theme-list.js in your project root:

const fs = require('fs');
const path = require('path');

// Path to your theme files (adjust this to match your project structure)
const themesDir = path.join(__dirname, 'src/styles/themes');
// Output file that will hold your theme list
const outputFile = path.join(__dirname, 'src/app/theme-list.ts');

// Get all SCSS theme files
const themeFiles = fs.readdirSync(themesDir).filter(file => file.endsWith('.scss'));

// Extract theme names (remove .scss extension, add 'theme-' prefix if missing)
const themeNames = themeFiles.map(file => {
  const baseName = file.replace('.scss', '');
  return baseName.startsWith('theme-') ? baseName : `theme-${baseName}`;
});

// Write the theme list to a TypeScript file
const tsContent = `export const AVAILABLE_THEMES = ${JSON.stringify(themeNames)} as const;`;
fs.writeFileSync(outputFile, tsContent);

console.log('Successfully generated theme list!');

Step 2: Add Script to Your Build Workflow

Update your package.json to run this script before starting or building the app:

"scripts": {
  "prestart": "node generate-theme-list.js",
  "prebuild": "node generate-theme-list.js",
  // ... your other scripts
}

Step 3: Use the Generated Theme List in Your Component

Import the theme list and use it directly:

import { Component, OnInit } from '@angular/core';
import { AVAILABLE_THEMES } from './theme-list';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  availableThemes = AVAILABLE_THEMES;
  selectedTheme: typeof AVAILABLE_THEMES[number] = 'theme-light';

  ngOnInit() {
    document.body.classList.add(this.selectedTheme);
  }

  switchTheme(themeName: typeof AVAILABLE_THEMES[number]): void {
    document.body.classList.forEach(cls => {
      if (cls.startsWith('theme-')) document.body.classList.remove(cls);
    });
    document.body.classList.add(themeName);
    this.selectedTheme = themeName;
  }
}
Which Solution to Choose?
  • Solution 1 is great if you need to handle dynamically loaded themes (e.g., themes added after the app initializes).
  • Solution 2 is more reliable for static themes, as it avoids DOM parsing edge cases and gives you type safety in TypeScript.

内容的提问来源于stack exchange,提问作者Rick

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:32:45