3、第一个自定义组件:创建基础Widget项目结构、理解widget-config.json、widgets-bundle.js的作用

好,咱们正式开始动手了。

前面两章我们把ThingsBoard的组件体系、开发环境都捋了一遍。说实话,理论讲再多,不如亲手写一个组件来得实在。这一章,我们就来创建第一个自定义组件。

我会带着你一步步搭起项目结构,然后重点讲清楚两个核心文件——widget-config.jsonwidgets-bundle.js。这两个文件,说白了就是组件的「身份证」和「户口本」。搞懂了它们,后面写任何组件都顺风顺水。

3.1 创建基础Widget项目结构

我个人习惯,每个自定义组件都放在一个独立的文件夹里。这样管理起来清爽,后期维护也方便。

先看看一个最简的组件项目长什么样:

my-first-widget/
├── widget-config.json
├── widget.js
└── widget.css

嗯,就三个文件。别嫌少,麻雀虽小五脏俱全。

  • widget-config.json:组件的配置文件。告诉ThingsBoard「我叫什么、长什么样、需要什么数据」。
  • widget.js:组件的核心逻辑。渲染、更新、销毁,全在这里。
  • widget.css:样式文件。让组件看起来顺眼。

我在项目中遇到过不少新手,一上来就把所有代码塞进一个文件里。结果后面改需求时,找配置找半天,找样式又找半天。所以从一开始就分好文件,这是个好习惯。

小提示: 如果你的组件逻辑比较复杂,可以把widget.js拆成多个模块。但初期,一个文件足够了。

3.2 理解widget-config.json

这个文件,是ThingsBoard认识你组件的第一步。它定义了组件的基本信息、数据源要求、以及可配置的参数。

来看一个最简的配置:

{
    "alias": "my_first_widget",
    "name": "我的第一个组件",
    "description": "这是一个演示用的基础组件",
    "type": "latest",
    "sizeX": 6,
    "sizeY": 4,
    "resources": [
        {
            "url": "widget.js"
        },
        {
            "url": "widget.css"
        }
    ],
    "settingsSchema": {},
    "dataKeySettingsSchema": {},
    "defaultConfig": "{}"
}

咱们拆开来看每个字段的作用:

字段名 说明 我的经验
alias 组件的唯一标识。只能用字母、数字、下划线。 我习惯用项目名做前缀,避免和别人冲突。
name 显示在组件库里的名字。中文英文都行。 建议用中文,团队成员一看就懂。
type 组件类型。常用的是latest(最新值)和timeseries(时序数据)。 展示单个设备状态用latest,展示历史趋势用timeseries
sizeX/sizeY 组件在仪表盘上的默认尺寸。单位是网格。 别设太大,用户拖进来再调也不迟。
resources 组件依赖的JS和CSS文件列表。 顺序很重要,先引CSS再引JS。
settingsSchema 组件设置面板的JSON Schema。留空表示没有设置项。 初期可以空着,后面再慢慢加。
defaultConfig 默认配置,JSON字符串格式。 至少给个空对象{},避免报错。
注意: alias一旦确定,尽量不要修改。因为仪表盘上已经引用的组件实例,是通过alias来关联配置的。改了就找不到了。

你可能会问:「为什么要有settingsSchemadefaultConfig两个东西?」

嗯,这个问题我当初也困惑过。简单说:settingsSchema定义的是「用户能调什么」,而defaultConfig定义的是「初始值是什么」。一个管界面,一个管数据。

3.3 理解widgets-bundle.js的作用

好,现在组件有了。但ThingsBoard怎么知道「哦,我有个新组件可以用了」?

这就轮到widgets-bundle.js出场了。

你可以把它理解成一个「组件清单」。它把所有组件的配置打包在一起,告诉ThingsBoard:「看,这些组件都是我提供的,你注册一下吧。」

一个典型的bundle文件长这样:

self.onInit = function() {
    self.registerWidget('my_first_widget', {
        widgetConfig: {
            alias: 'my_first_widget',
            name: '我的第一个组件',
            // ... 其他配置
        },
        widget: function(ctx) {
            // 组件的渲染逻辑
        }
    });
};

等等,这里有个关键点——self.onInit。这个函数在bundle加载时自动执行。你需要在里面调用self.registerWidget来注册每个组件。

我记得第一次写bundle时,忘了加self.onInit,结果组件怎么都加载不出来。查了半天文档才发现这个坑。所以,千万别漏了

实际项目中,bundle文件通常放在widget-bundles目录下:

my-widget-bundle/
├── widget-bundles/
│   └── my-bundle.js
├── my-first-widget/
│   ├── widget-config.json
│   ├── widget.js
│   └── widget.css
└── my-second-widget/
    ├── widget-config.json
    ├── widget.js
    └── widget.css

这样组织的好处是:一个bundle可以包含多个组件。你想想看,如果你有十几个组件,每个都单独注册,那管理起来多麻烦。用一个bundle统一管理,清爽多了。

核心要点:
  • widget-config.json是组件的「身份证」——描述组件自身信息。
  • widgets-bundle.js是组件的「户口本」——告诉系统有哪些组件可用。
  • 一个bundle可以注册多个组件,方便统一管理。

3.4 实战:把组件跑起来

光说不练假把式。我们来走一遍完整的流程。

第一步: 在ThingsBoard的「自定义组件」页面,上传你的bundle文件。

第二步: 系统会自动解析bundle里的所有组件配置。如果widget-config.json有语法错误,这里就会报错。

第三步: 进入仪表盘编辑模式,在组件库的「自定义」分类下,就能找到你的组件了。

我曾经遇到过一个情况:组件上传成功了,但在仪表盘里死活找不到。后来发现是alias写了个中文,系统不认。所以记住,alias只能用英文和数字。

调试技巧: 如果组件加载失败,打开浏览器控制台(F12),看网络请求。bundle文件有没有加载成功?widget.js有没有报404?这些信息能帮你快速定位问题。

3.5 本章小结

这一章我们做了三件事:

  1. 创建了组件的基础项目结构——三个文件,各司其职。
  2. 吃透了widget-config.json——组件的身份证,告诉系统「我是谁」。
  3. 理解了widgets-bundle.js——组件的户口本,告诉系统「我有哪些组件」。

下一章,我们会真正开始写组件的渲染逻辑。到时候,你会看到数据是怎么从ThingsBoard流到你的组件里的。嗯,那才是真正好玩的部分。

公众号:蓝海资料掘金营,微信deep3321