面向实战:使用 Custom Elements 构建 Admin 模板系统

前言

Admin 模板系统通常用于构建企业级后台管理系统,其特点是数据量大,页面复杂,功能繁多。由于不同企业的管理需求不同,因此也需要定制化的管理系统。使用 Custom Elements 技术,可以非常便捷地开发出一套可复用的模板系统,本文将详细介绍如何使用 Custom Elements 构建一个 Admin 模板系统。

什么是 Custom Elements

Custom Elements 是 Web Components 规范中的一部分,它允许我们创建属于我们自己的 HTML 组件。我们可以使用自定义的标签名创建组件,然后在页面中通过该标签来创建组件实例,Custom Elements 提供了一套 API,让我们可以进行组件的生命周期控制、属性监听与处理、Shadow DOM 的操作等。

Admin 模板系统设计思路

了解了 Custom Elements 技术的基本原理,我们开始思考如何使用它来构建一个 Admin 模板系统。根据 Admin 模板系统的需求,我们将其分为顶部菜单、侧边栏、主题选择、面包屑、内容区域等部分,每一个部分都可以使用 Custom Elements 实现。

  • 顶部菜单:由多个导航链接组成;
  • 侧边栏:根据不同的菜单选项,显示不同的子菜单;
  • 主题选择:提供不同的主题可供选择;
  • 面包屑:根据用户操作路径,显示当前页面所在位置;
  • 内容区域:根据不同的菜单选项,显示不同的组件界面。

根据这些需求,我们可以将 Admin 模板系统抽象为一个由以上部分组成的组件,其中每个组件都是一个 Custom Elements。

使用 Custom Elements 实现 Admin 模板系统

1. 创建 Custom Elements

我们创建一个名为 AdminTemplate 的 Custom Elements,并且定义其 template 和 styles:

class AdminTemplate extends HTMLElement {
  constructor() {
    super();

    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        /* 样式 */
      </style>
      <nav class="top-nav">
        <!-- 顶部菜单 -->
      </nav>
      <div class="main">
        <aside class="sidebar">
          <!-- 侧边栏 -->
        </aside>
        <main class="content">
          <div class="theme-switch">
            <!-- 主题选择 -->
          </div>
          <nav class="breadcrumbs">
            <!-- 面包屑 -->
          </nav>
          <div class="main-content">
            <!-- 内容区域 -->
          </div>
        </main>
      </div>
    `;

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));
  }

  // 组件生命周期方法
  connectedCallback() { /* ... */ }
  disconnectedCallback() { /* ... */ }
  adoptedCallback() { /* ... */ }
  attributeChangedCallback() { /* ... */ }
}

customElements.define('admin-template', AdminTemplate);

2. 创建子组件

我们将在 AdminTemplate 中创建以下子组件:Menu、SubMenu、ThemeSwticher、Breadcrumbs、Content,它们均为 Custom Elements,所以我们需要再定义它们的类。

以 Menu 组件为例,我们定义其 template 和 styles:

class Menu extends HTMLElement {
  constructor() {
    super();

    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        /* 样式 */
      </style>
      <ul>
        <!-- 菜单项 -->
      </ul>
    `;

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));
  }

  // 组件生命周期方法
  connectedCallback() { /* ... */ }
  disconnectedCallback() { /* ... */ }
  adoptedCallback() { /* ... */ }
  attributeChangedCallback() { /* ... */ }
}

customElements.define('admin-menu', Menu);

同样的方式,我们完成 SubMenu、ThemeSwticher、Breadcrumbs、Content 组件的定义。

3. 实现 AdminTemplate 组件

我们在 AdminTemplate 类中,通过 querySelector 方法获取到其内部子组件,并实现相应的逻辑。

class AdminTemplate extends HTMLElement {
  constructor() {
    super();

    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        /* 样式 */
      </style>
      <nav class="top-nav">
        <admin-menu></admin-menu>
      </nav>
      <div class="main">
        <aside class="sidebar">
          <admin-submenu></admin-submenu>
        </aside>
        <main class="content">
          <div class="theme-switch">
            <admin-them-switcher></admin-them-switcher>
          </div>
          <nav class="breadcrumbs">
            <admin-breadcrumbs></admin-breadcrumbs>
          </nav>
          <div class="main-content">
            <admin-content></admin-content>
          </div>
        </main>
      </div>
    `;

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));

    // 获取子组件
    this.menu = this.shadowRoot.querySelector('admin-menu');
    this.submenu = this.shadowRoot.querySelector('admin-submenu');
    this.themeSwitcher = this.shadowRoot.querySelector('admin-them-switcher');
    this.breadcrumbs = this.shadowRoot.querySelector('admin-breadcrumbs');
    this.content = this.shadowRoot.querySelector('admin-content');
  }

  // 组件生命周期方法
  connectedCallback() {
    // 初始化子组件
    this.menu.init();
    this.submenu.init();
    this.themeSwitcher.init();
    this.breadcrumbs.init();
    this.content.init();
  }

  disconnectedCallback() { /* ... */ }
  adoptedCallback() { /* ... */ }
  attributeChangedCallback() { /* ... */ }
}

customElements.define('admin-template', AdminTemplate);

4. 完成子组件实现

具体实现方法,我们以 Menu 组件为例:

  • Menu 组件需要监听父组件 AdminTemplate 的属性变化,根据传入的数据设置菜单项;
  • Menu 组件需要监听菜单项的点击事件,并相应地更新子组件的显示内容。
class Menu extends HTMLElement {
  constructor() {
    super();

    const template = document.createElement('template');
    template.innerHTML = `
      <style>
        /* 样式 */
      </style>
      <ul>
        <!-- 菜单项 -->
      </ul>
    `;

    this.attachShadow({ mode: 'open' });
    this.shadowRoot.appendChild(template.content.cloneNode(true));

    this.menuItems = []; // 菜单项
    this.currMenuItem = null; // 当前选中的菜单项
  }

  // 设置菜单项
  set menu(data) {
    this.menuItems = data; // 数据来源于 AdminTemplate 的属性传递
    this.render(); // 渲染菜单项
  }

  // 渲染菜单项
  render() {
    const ul = this.shadowRoot.querySelector('ul');
    ul.innerHTML = '';
    this.menuItems.forEach(item => {
      const li = document.createElement('li');
      li.innerText = item.label;
      li.setAttribute('data-key', item.key); // 设置标识
      li.addEventListener('click', e => {
        // 处理菜单点击事件
        this.handleClick(e.currentTarget.getAttribute('data-key'));
      });
      ul.appendChild(li);
    });
  }

  // 处理菜单点击事件
  handleClick(key) {
    this.currMenuItem = key;
    this.updateSubMenu(key); // 更新子菜单
    this.updateContent(key); // 更新内容区域
  }

  // 更新子菜单
  updateSubMenu(key) { /* ... */ }

  // 更新内容区域
  updateContent(key) { /* ... */ }

  // 初始化方法
  init() {
    // 获取菜单项
    fetch('/api/getMenu').then(data => {
      this.menu = data;
    });
  }

  // 组件生命周期方法
  connectedCallback() { /* ... */ }
  disconnectedCallback() { /* ... */ }
  adoptedCallback() { /* ... */ }
  attributeChangedCallback() { /* ... */ }
}

customElements.define('admin-menu', Menu);

SubMenu、ThemeSwitcher、Breadcrumbs、Content 组件的实现也可以参考上述例子。

总结

通过本文的介绍,我们了解了如何使用 Custom Elements 技术来构建一个完整的 Admin 模板系统。在实际应用中,开发者可以根据自身应用场景的需求,选择自定义组件和样式,实现可复用的模板系统,提升开发效率和用户体验。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65960b12eb4cecbf2d9ef73a


纠错反馈