Skip to content

Settings API 深度指南

本文汇总 Obsidian Settings API 的完整用法,从基础设置项到高级动态设置面板。

快速回顾

以下内容在其他教程中已详述,这里简要列出接口:

typescript
import { Plugin, PluginSettingTab, Setting } from 'obsidian';

export default class MyPlugin extends Plugin {
  settings: MyPluginSettings;

  async onload() {
    this.addSettingTab(new MySettingTab(this.app, this));
  }
}

详细入门参见 插件开发教程插件开发详解

基础设置类型

文本输入 → TextComponent

typescript
new Setting(containerEl)
  .setName('API Key')
  .setDesc('输入你的 API 密钥')
  .addText(text => text
    .setPlaceholder('sk-...')
    .setValue(this.plugin.settings.apiKey)
    .onChange(async (value) => {
      this.plugin.settings.apiKey = value;
      await this.plugin.saveSettings();
    }));

文本输入扩展属性:

  • text.inputEl.type = 'password' — 隐藏输入内容
  • .setDisabled(true) — 禁用编辑

开关 → ToggleComponent

typescript
new Setting(containerEl)
  .setName('启用功能')
  .addToggle(toggle => toggle
    .setValue(this.plugin.settings.enabled)
    .onChange(async (value) => {
      this.plugin.settings.enabled = value;
      await this.plugin.saveSettings();
    }));

下拉选择 → DropdownComponent

typescript
new Setting(containerEl)
  .setName('主题模式')
  .addDropdown(dropdown => dropdown
    .addOption('light', '浅色')
    .addOption('dark', '深色')
    .addOption('system', '跟随系统')
    .setValue(this.plugin.settings.theme)
    .onChange(async (value) => {
      this.plugin.settings.theme = value;
      await this.plugin.saveSettings();
    }));

滑块 → SliderComponent

typescript
new Setting(containerEl)
  .setName('字体大小')
  .addSlider(slider => slider
    .setLimits(12, 32, 1)   // min, max, step
    .setValue(this.plugin.settings.fontSize)
    .setDynamicTooltip()     // 拖动时显示值
    .onChange(async (value) => {
      this.plugin.settings.fontSize = value;
      await this.plugin.saveSettings();
    }));

文本域 → TextAreaComponent

typescript
new Setting(containerEl)
  .setName('自定义 CSS')
  .addTextArea(text => {
    text
      .setPlaceholder('输入 CSS 代码...')
      .setValue(this.plugin.settings.customCSS)
      .onChange(async (value) => {
        this.plugin.settings.customCSS = value;
        await this.plugin.saveSettings();
      });
    text.inputEl.rows = 6;
    text.inputEl.cols = 40;
  });

颜色选择器 → ColorComponent

typescript
new Setting(containerEl)
  .setName('强调色')
  .addColorPicker(color => color
    .setValue(this.plugin.settings.accentColor)
    .onChange(async (value) => {
      this.plugin.settings.accentColor = value;
      await this.plugin.saveSettings();
    }));

按钮 → ButtonComponent 和 ExtraButtonComponent

typescript
// 操作按钮
new Setting(containerEl)
  .setName('清除缓存')
  .addButton(button => button
    .setButtonText('清除')
    .setCta()              // 突出样式
    .onClick(() => {
      this.clearCache();
    }));

// 图标按钮(在 Setting 右侧)
new Setting(containerEl)
  .setName('API 地址')
  .addExtraButton(button => button
    .setIcon('reset')
    .setTooltip('重置为默认')
    .onClick(() => {
      // ...
    }));

信息提示 → addDesc / addMomentColor

typescript
new Setting(containerEl)
  .setName('已连接 ✅')
  .setDesc(new DocumentFragment()  // 支持 HTML
    .createEl('span', { text: '状态正常' })
    .createEl('br')
    .createEl('a', { href: 'https://example.com', text: '查看文档' })
  );

组合设置项

一个 Setting 可以包含多个组件:

typescript
new Setting(containerEl)
  .setName('每日笔记模板')
  .setDesc('选择模板并指定目标文件夹')
  .addText(text => text
    .setPlaceholder('文件夹路径')
    .setValue(this.plugin.settings.folder))
  .addDropdown(dropdown => dropdown
    .addOption('daily', '日记模板')
    .addOption('weekly', '周记模板')
    .setValue(this.plugin.settings.template));

条件显示 — 动态设置项

根据用户选择显示/隐藏关联设置:

typescript
class MySettingTab extends PluginSettingTab {
  display(): void {
    const { containerEl } = this;
    containerEl.empty();

    // 主开关
    new Setting(containerEl)
      .setName('启用高级模式')
      .addToggle(toggle => toggle
        .setValue(this.plugin.settings.advancedMode)
        .onChange(async (value) => {
          this.plugin.settings.advancedMode = value;
          await this.plugin.saveSettings();
          this.display();  // 重新渲染整个面板
        }));

    // 条件显示
    if (this.plugin.settings.advancedMode) {
      new Setting(containerEl)
        .setName('高级选项 A')
        .addText(text => text
          .setValue(this.plugin.settings.advancedA)
          .onChange(async (value) => {
            this.plugin.settings.advancedA = value;
            await this.plugin.saveSettings();
          }));
    }
  }
}

注意:调用 this.display() 重新渲染会导致焦点丢失。对于少量选项,可以用 .setDisabled() 或 CSS 控制显隐。

动态列表 — 添加/删除条目

typescript
new Setting(containerEl)
  .setName('排除的文件夹')
  .setDesc('这些文件夹将被忽略')
  .addButton(button => button
    .setButtonText('添加')
    .setCta()
    .onClick(() => {
      this.plugin.settings.excludeFolders.push('');
      this.plugin.saveSettings();
      this.display();
    }));

this.plugin.settings.excludeFolders.forEach((folder, index) => {
  new Setting(containerEl)
    .addText(text => text
      .setValue(folder)
      .setPlaceholder('文件夹路径')
      .onChange(async (value) => {
        this.plugin.settings.excludeFolders[index] = value;
        await this.plugin.saveSettings();
      }))
    .addExtraButton(button => button
      .setIcon('trash')
      .setTooltip('删除')
      .onClick(async () => {
        this.plugin.settings.excludeFolders.splice(index, 1);
        await this.plugin.saveSettings();
        this.display();
      }));
});

设置迁移

当插件升级时,旧版本用户的数据结构可能不同:

typescript
// settings.ts
export interface MyPluginSettings {
  version: number;    // 用于版本追踪
  apiKey: string;
  // v2 新增
  endpoint?: string;
  // v1 旧字段(已重命名)
  template?: string;
}

export const DEFAULT_SETTINGS: MyPluginSettings = {
  version: 2,
  apiKey: '',
  endpoint: 'https://api.example.com',
};
typescript
// main.ts
async onload() {
  await this.loadSettings();

  // 从旧版本迁移
  if (this.settings.version < 2) {
    if (this.settings.template) {
      // 迁移旧字段
      this.settings.apiKey = this.settings.template;
      delete this.settings.template;
    }
    this.settings.version = 2;
    await this.saveSettings();
  }
}

迁移检查清单:

  • 每次设置结构变化时递增 version 字段
  • onload 中检查版本并按步骤迁移
  • 用可选属性 ? 标记新增字段,避免 undefined 错误
  • 迁移后立即调用 saveSettings()

Settings UI 模式

分组标题

typescript
// 方法 1:使用 Setting.setHeading()
new Setting(containerEl)
  .setName('API 配置')
  .setHeading();

// 方法 2:手动创建标题
containerEl.createEl('h2', { text: 'API 配置' });
containerEl.createEl('p', {
  text: '配置第三方 API 的连接参数',
  cls: 'setting-item-description'
});

带状态指示

typescript
new Setting(containerEl)
  .setName('连接状态')
  .setDesc(this.plugin.settings.isConnected
    ? '✅ 已成功连接到服务器'
    : '❌ 连接失败,请检查配置')
  .addButton(button => button
    .setButtonText('测试连接')
    .onClick(async () => {
      button.setButtonText('测试中...');
      button.setDisabled(true);
      try {
        await this.testConnection();
        new Notice('连接成功');
      } catch {
        new Notice('连接失败');
      }
      button.setButtonText('测试连接');
      button.setDisabled(false);
      this.display();  // 刷新状态文字
    }));

重置按钮

typescript
new Setting(containerEl)
  .setName('重置设置')
  .setDesc('将所有设置恢复为默认值')
  .addButton(button => button
    .setButtonText('重置')
    .setWarning()  // 红色警告样式
    .onClick(async () => {
      this.plugin.settings = { ...DEFAULT_SETTINGS };
      await this.plugin.saveSettings();
      this.display();
      new Notice('设置已重置');
    }));

Setting 装饰方法

Setting 类提供的链式方法:

方法说明
.setName(name)设置标题(支持字符串或 DocumentFragment)
.setDesc(desc)设置描述文字
.setClass(cls)添加 CSS 类名
.setTooltip(tooltip)添加悬停提示
.setDisabled(disabled)禁用整个设置项
.setHeading()将当前项渲染为分组标题
.addButton(cb)添加按钮
.addToggle(cb)添加开关
.addText(cb)添加文本输入
.addTextArea(cb)添加文本域
.addDropdown(cb)添加下拉框
.addSlider(cb)添加滑块
.addColorPicker(cb)添加颜色选择
.addExtraButton(cb)添加图标按钮
.addMomentColor(cb)添加瞬时颜色选择器
.then(cb)在渲染完成后执行回调

最佳实践

typescript
export class MySettingTab extends PluginSettingTab {
  plugin: MyPlugin;

  constructor(app: App, plugin: MyPlugin) {
    super(app, plugin);
    this.plugin = plugin;
  }

  display(): void {
    const { containerEl } = this;
    containerEl.empty();

    // ✅ 先清空再渲染,避免重复元素
    // ✅ 每次 onChange 都调用 saveSettings()
    // ✅ 复杂面板可拆分为多个私有方法
    this.addAPISection(containerEl);
    this.addDisplaySection(containerEl);
    this.addAdvancedSection(containerEl);
  }

  private addAPISection(el: HTMLElement): void {
    el.createEl('h2', { text: 'API 配置' });
    // ...
  }

  private addDisplaySection(el: HTMLElement): void {
    el.createEl('h2', { text: '显示设置' });
    // ...
  }

  private addAdvancedSection(el: HTMLElement): void {
    el.createEl('h2', { text: '高级设置' });
    // ...
  }
}

与插件教程的关系

你需要的场景参考文档
第一个设置面板怎么建插件开发教程
完整的高级面板实现插件开发进阶
国际化设置面板插件国际化
设置拖拽排序插件高级技巧