wzh

wzh

我想有那么一段时光,可以在面朝大海的房车里煮上一杯咖啡,看看曾写过的代码

JTBC5 自定义组件介绍

本文发布于:2024-01-27

这不是一篇原理分析的文章,它更像是一篇使用说明书。JTBC5 (以下简称 j5) 自定义组件是使用 Web Components 的方式来实现组件化,j5 为了使组件的使用、编写上更加方便、自动化,增加了一些附加的功能。本文分两部分介绍,第一部分说一下什么是 Web Components(web 自定义组件),以及如何使用;第二部分说一下 j5 的自定义组件是怎么实现自动加载的以及如何实现的。

一、自定义 web 组件(Web Components)。

1、什么是 Web Components

        Web Components 是一组 web 原生 API 的统称,允许您创建可重用的自定义元素 (custom elements)并且在您的 web 应用中使用它们。参见 https://developer.mozilla.org/zh-CN/docs/Web/Web_Components 。Web Components 大部分技术规范兼容现代浏览器,因此它是一套原生的 web 组件规范。

2、Web Components 的使用

        下面看一个常规的使用方法,示例代码如下

        1)一个完全自定义的元素

/main.js
//代码来源 https://mdn.github.io/web-components-examples/edit-word/
//做了部分修改
customElements.define('edit-word',
  class extends HTMLElement {
    constructor() {
      // 必须首先调用 super 方法
      super();

      // 创建一个 shadow root
      const shadowRoot = this.attachShadow({mode: 'open'});

      // 创建一个 html 模板
      let shadowRootHTML = `
        <style>:host {display: inline-block; --text-font-size: 12px;} span{display: inline-block;}</style>
        <form style="display: none;"><input required="required"></form>
        <span><slot></slot></span>
      `;
      // 将创建的模板附加到 shadow dom
      shadowRoot.innerHTML = shadowRootHTML;

      // 添加功能

      let span = shadowRoot.querySelector('span');
      let form = shadowRoot.querySelector('form');
      let input = shadowRoot.querySelector('input');
      this.addEventListener('click', () => {
        span.style.display = 'none';
        form.style.display = 'inline-block';
        input.focus();
        input.setSelectionRange(0, input.value.length)
      });

      form.addEventListener('submit', e => {
        updateDisplay();
        e.preventDefault();
      });

      input.addEventListener('blur', updateDisplay);

      function updateDisplay() {
        span.style.display = 'inline-block';
        form.style.display = 'none';
        span.textContent = input.value;
        input.style.width = span.clientWidth + 'px';
      }
    }
  }
);
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>edit-word demo</title>
    <script src="main.js" defer></script>
  </head>
  <body>
    <h1><code>edit-word</code> demo</h1>
    <p>我叫 <edit-word>张三</edit-word></p>
  </body>
</html>

语法:

        customElements.define(name, constructor, options);
                a、name:  自定义元素名,例如上面的 “edit-word”,在 html 中可以直接使用如 <edit-word > 张三 </edit-word>
                b、constructor:自定义元素构造器。对应上面的 匿名类 “class extends HTMLElement”, 当然也可以是具名类,类也可以放到别一个文件中,然后通过 import 引入,就像下面的 “WordCount” WordCount 这是一个类的引用。
                c、options:(可选项)控制元素如何定义。目前有一个选项支持:
                      extends. 指定继承的已创建的元素。被用于创建自定义元素。如
                      customElements.define ('word-count', WordCount, { extends: 'p'}); 表示这个自定义元素继承自 p 标签

        2)第二个是继承自基本的 HTML 元素的自定义标签

        这个和上面结构基本一样,不同的地方一个是多出 options 选项来指定继承的基本标签元素;再一个是自定义元素够造器,也就是用来定义自定义元素功能的类(上面的 constructor 参数),这个类需要继承的不是 HTMLElement 而是和 options 中指定的要扩展的标签的类。如 p 标签 对应的是 HTMLParagraphElement。

        使用时,需要先写出基本的元素标签,并通过 is 属性指定 custom element 的名称。例如<p is="word-count">, 或者 document.createElement("p", { is: "word-count" })

        例子就不在累述了,可以参见 https://developer.mozilla.org/zh-CN/docs/Web/Web_Components/Using_custom_elements

二、JTBC5 的自定义组件

        j5 的自定义组件更加的自动化。只要把编写好的自定义标签的功能(对应上面 customElements.define 中的 constructor 参数)的类文件,按照 j5 的存储路径规范存储后 j5 就会按需加载,也就是说不用按上面 “常规用法” 中先定义、然后通过 script 标签引入,最后才能使用。参 jian:https://help.jtbc.cn/php/5.0/#structure/component.xml

1、自定义标签类的存储路径规范

        1)j5 核心组件目录,一般存放 j5 官方组件。为了方便管理不建议自己编写的组件放到这个目录。\Public\common\assets\js\components\jtbc\
         此目录下组件是按照文件夹分别存放。如图

 如 jtbcAnchor 文件夹下 jtbcAnchor.js  现实了对 a 标签的扩展。注意命名都是以小驼峰式命名。如图

        如何在中使用呢?只需在模板文件中直接写标签 <a is=“jtbc-anchor” href="网址"></a>(因为这是继承的基本 html 元素 a, 所以使用时先写基本标签 a , 再通过 is 属性指定自定义元素名), 元素名是把小驼峰式命名改为用 “-” 连接成的标签名。因为,custom element 的名称不能是单个单词,且其中必须要有短横线

        2)非 j5 官方的自定义组件可以放到 \Public\common\assets\js\components\ 自定义文件夹 \,比如 my 文件夹(这个名字可以自己取,名字全小写)。组件同样是以小驼峰命名的文件夹单独存放。组件的类文件名与其文件夹同名。如图

        如何引用: <my-edit-field></my-edit-field> 同样是把小驼峰式命名改为用短横线连接,转为标签名。如图

       3)模块下的自定义组件。存放到对应模块下,如新闻模块 \Public\news\common\assets\js\components\ 。
           模块下自定义组件组织相对自由,因为不像上面两个组件比较多,需要有条理一些。
                    a、可以把包含组件的直接放到 components 文件夹下。引用方式 <web-news-scroll></web-news-scroll>
                    b、也可以像上面那样用不同的文件夹来分类存储组件的文件夹。引用方式 <web-news-detail-scroll></web-news-detail-scroll>、<web-news-list-scroll></<web-news-list-scroll>
   如图

        c、上面的规律就是
              web 代表要去模块下面加载
              news 代表需要搜索的模块名

        下面代表的是组件名:这里的组件名可以不用小驼峰。用小驼峰的组件名,每一层需要一个文件夹。如上面的 detailScroll、ListScroll。如图

2、为什么 j5 的组件不用引入就能自动加载,这要看一段源码,当然以理解它也不会妨碍你很好的用 j5 ,编写自己的自定义组件。

        j5 的自动加载的实现文件位于 /Public/common/assets/js/components/components.js 中。如图

        看到第 44 行中的  customElements.define (tag, component.default, options); 了吗?是不是和一开始介绍的常规用法自定义组件的语法一样 ---
customElements.define(name, constructor, options);。

        有了自动加载,我们就只需实现自定义组件的行为类,然后按照上面介绍的 3 种路径存放方式存放,自定义组件就可以按需加载了。它让我们专注于组件功能逻辑,省去了不必要的重复工作。

        感谢阅读,希望这篇文章能给你带来帮助!

  

 

wzh

wzh

我想有那么一段时光,可以在面朝大海的房车里煮上一杯咖啡,看看曾写过的代码

联络

  • EMail: qihui658[at]qq.com

标签

链接