在使用Node-Red的过程中,总有一些节点是无法满足需求,或者通用方法复用率高的想直接转化为节点的,这时就会用到自定义节点这个功能。
Node-Red
是一个基于Node
开发的框架工具,所以为她开发的节点都要遵从于Node
开发的模式。比如说,我们需要npm init
生成package.json
,需要npm publish
、npm install
等,但是又跟纯的Node Package
又有些许不同,因为是给Node-Red
开发的package
,所以在package.json
中需要加上Node-Red
的标识。自定义Node-Red的Node大致可以分为三部分,1.创建package.json
、2.创建js
、3.创建html
。
我这里的自定节点方法是:根据对象的属性名称以及属性值获取对象,所以首先创建文件夹node-red-get-value-by-prop
mkdir node-red-get-value-by-prop && cd node-red-get-value-by-prop
执行初始化
npm init
执行操作之后就得到了package.json
文件了
step 1 修改package.json
{
"name": "node-red-get-value-by-prop",
"version": "1.0.0",
"description": "node red tool get value by prop",
"main": "get-value-by-prop.js",
"node-red": {
"nodes": {
"get-value-by-prop": "get-value-by-prop.js"
}
},
"scripts": {
},
"author": "jonathan",
"license": "ISC"
}
看到这里可以发现不同点,就是添加了node-red
标识,以及节点名称和节点路径值等。
step 2 创建js
在同路径下创建package.json
中nodes
对象的js
文件,我们这里命名为get-value-by-prop.js
并且填写以下内容:
module.exports = function (RED) {
function _getValByProp(data, prop, propVal, r) {
r = r ? r : { status: false };
if (data && data.hasOwnProperty(prop) && data[prop] == propVal) {
r.status = true;
r.result = data;
return r;
}
for (var i in data) {
if (data && typeof data[i] == "object" && null !== data[i]) {
var r = _getValByProp(data[i], prop, propVal, r);
if (r.status) return r;
}
}
return r;
}
function getValByProp(config) {
RED.nodes.createNode(this, config);
var node = this;
this.prop = config.prop;
this.propVal = config.propVal;
node.on("input", function (msg) {
var data = msg.payload || {};
msg.payload = _getValByProp(data,this.prop,this.propVal);
node.send(msg);
});
}
RED.nodes.registerType("get-value-by-prop", getValByProp);
}
看到这里,首先Node由构造函数定义,可用于创建Node的新实例。 该函数在运行时注册,因此可以在Flow中部署相应类型的Node时调用它。
该函数被传递一个包含在Flow编辑器中设置的属性的对象。
它必须做的第一件事是调用 RED.nodes.createNode 函数来初始化所有Node共享的特征。 之后,自定义Node的代码就创建好了。
当然这里如果想让写法更高级一点可以改成es6的class,这样写类构造函数会更加优雅,比如你可以把代码修改成这样:
module.exports = function (RED) {
function _getValByProp(data, prop, propVal, r) {
r = r ? r : { status: false };
if (data && data.hasOwnProperty(prop) && data[prop] == propVal) {
r.status = true;
r.result = data;
return r;
}
for (var i in data) {
if (data && typeof data[i] == "object" && null !== data[i]) {
var r = _getValByProp(data[i], prop, propVal, r);
if (r.status) return r;
}
}
return r;
}
class getValByProp {
constructor(config) {
RED.nodes.createNode(this, config);
var node = this;
this.prop = config.prop;
this.propVal = config.propVal;
node.on("input", function (msg) {
var data = msg.payload || {};
msg.payload = _getValByProp(data, this.prop, this.propVal);
node.send(msg);
});
}
}
RED.nodes.registerType("get-value-by-prop", getValByProp);
}
接收消息
Node在输入事件上注册一个侦听器,以接收来自流中上游Node的消息。
this.on('输入', function(msg) {
// 用 'msg' 做点什么
});
发送消息
Node可以使用 send 函数将消息发送到流中的下游Node:
var msg = { payload:“hi”}
this.send(msg);
如果 msg 为空,则不发送任何消息。
step 3 创建html
自定义Node .html
文件定义了节点在编辑器中的显示方式。 它包含三个不同的部分,每个部分都包含在自己的标签中:
- 编辑器注册的自定义节点,诸如调色板类别、可编辑属性(默认值)和要使用的图标等内容位于常规的
javascript
脚本标记中。 - 编辑对话框内容的编辑模板在
text/x-red
类型的脚本中,其中data-template-name
设置为节点的类型。 - 编辑信息侧边栏选项卡中显示的帮助文本在
text/x-red
类型的脚本中,其中data-help-name
设置为节点的类型。
通过以上的介绍,我们就可以编辑html
了,在项目路径下创建名字为get-value-by-prop.html
的文件,并填写以下内容:
这里需要注意,input
的id
和label for
前缀固定为node-input
,后缀为defaults
对象中的值。data-template-name
、data-help-name
,以及RED.nodes.registerType
注册的方法名都要统一为上面js
注册的名称。
step 4 install Node
经过上述的操作我就基本完成了Node-Red的自定义节点。接下来就是安装自定义的节点。
- 找到自定义节点的路径,以我本地的为例,执行
pwd
,得到路径为
$ pwd
/Users/dev/Documents/workspace/node-red-package/node-red-get-value-by-prop
- 找到安装Node-Red的路径下执行
$ cnpm install ~/Documents/workspace/node-red-package/node-red-get-value-by-prop --no-save
执行成功后会得到以下输出
$ cnpm install ~/Documents/workspace/node-red-package/node-red-get-value-by-prop --no-save
✔ Installed 1 packages
✔ Linked 1 latest versions
✔ Run 0 scripts
✔ All packages installed (1 packages installed from local file, used 202ms(network 201ms), speed 0B/s, json 0(0B), tarball 0B, manifests cache hit 0, etag hit 0 / miss 0)
这时我们重启服务,在Node-Red的编辑界面就可以看到对应的自定义节点了。
step 5 测试自定义节点
-
见自定义模板拖到编辑中,编辑内添加测试数据
-
添加inject节点和debug节点
-
在inject节点添加数据
-
部署控制台输出
总结
这样一个完整的自定义节点例子就完成了,总结一下其实还是挺容易的,至少保持思路明确,主要步骤就是这些。当然这个例子很简单,如果要实现复杂的程序的话还是有难度的。