- node-red的基础使用不讲了,百度有较多资料,跟着官网也可以写个简单的自定义组件
- 这里主要讲的是如何将复杂的组件输出成一个 独立的html页面并于vue框架结合形成一个友好的频繁交互页面
- 第一:创建一个”config“类型的配置项,从而创建一个websocket长连接,进行频繁的数据交换
- 第二:创建一个html文件,引入vue,写一个漂亮一些的可视化页面
- 第三:创建一个组件,提供一些node服务,并关联上你写的websocket服务,启动你的html页面
选择配置
流程
产生url 创建的菜单 my-com
image.png
image.png image.png
- ui文件夹是组件加入后需要公开的文件
- mycom 是自定义组件
- socket 是长链接配置
- 下面上代码
- mycom.html
<!-- 注册 -->
<script type="text/javascript">
RED.nodes.registerType('my-com', {
category: 'my', // 分类
color: '#a6bbcf', // 背景颜色
defaults: {
name: { value: "我的组件" },
socket: { value: '', type: "my-socket" }
},
inputs: 1, // 上游:输入 0 或者 1
outputs: 1, // 输出至下游 0 或者 more
icon: 'fa fa-anchor', // 标签
label: function () {
return this.name;
}
});
</script>
<!-- 配置窗口 -->
<script type="text/html" data-template-name="my-com">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name"/>
</div>
<div class="form-row">
<label for="node-input-socket"><i class="fa fa-globe"></i> <span>socket服务</span></label>
<input type="text" id="node-input-socket">
</div>
</script>
<!-- hover提示 -->
<script type="text/html" data-help-name="my-com">
<p>码代码的小公举</p>
</script>
- mycom.js
- socket.html
<!-- 注册节点 -->
<script type="text/javascript">
RED.nodes.registerType('my-socket', {
category: 'config', // 节点类型:配置,设置类
defaults: {
name: { value: "my-socket" },
port: { value: '1881', required: true }
},
label: function () {
return this.name;
}
});
</script>
<!-- 展示内容 -->
<script type="text/html" data-template-name="my-socket">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-config-input-name" placeholder="Name" />
</div>
<div class="form-row">
<label for="node-config-input-port"><i class="fa fa-tag"></i> Port</label>
<input type="text" id="node-config-input-port" placeholder="Port"/>
</div>
</script>
*socket.js
module.exports = function (RED) {
"use strict";
const webServer = require('ws').Server;
function mySocket(n) {
RED.nodes.createNode(this, n);
const node = this;
node.port = n.port;
node.statusText = 'init';
const wss = new webServer({ port: node.port }, () => {
node.statusText = 'start';
});
wss.on('connection', (ws) => {
console.log('connected')
node.statusText = 'connected';
node.ws = ws;
ws.send('connected');
ws.on('message', (data) => {
try {
const { code, nodeId } = JSON.parse(data.toString());
const node = RED.nodes.getNode(nodeId);
node.start = false;
let timmer;
if (code == 'test') {
// 持续检测
if (node.start) {
return;
}
node.start = true;
const loop = () => {
if (node.start) {
node.getWorks().then((res) => {
ws.send(JSON.stringify({ code: 'test', payload: res }))
})
timmer = setTimeout(loop, 100);
} else {
clearTimeout(timmer);
timmer = null;
}
}
loop();
} else if (code == 'stop') {
node.start = false;
ws.send(JSON.stringify({ code: 'stop', payload: 'stoped' }))
}
} catch (err) {
}
});
ws.on('close', () => {
node.statusText = '浏览器断开连接';
console.log('closed')
})
});
wss.on('close', () => {
node.statusText = 'closed';
console.log('closed')
})
wss.on('error', (error) => {
if (error.toString().indexOf('already') > -1 ) {
console.log('已启动')
return;
}
console.log(error)
node.statusText = 'error';
})
}
RED.nodes.registerType("my-socket", mySocket);
}
- ui.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>码代码的小公举</title>
<script src="./vue.js"></script>
<style>
* {
padding: 0;
margin: 0;
}
#app {
margin: 40px;
height: 200px;
line-height: 26px;
}
.items {
margin: 10px;
}
th,td {
width: 300px;
}
button {
width: 100%;
height: 40px;
background: #3872e0;
border-radius: 4px;
color: #fff;
border: 1px solid #3872e0;
font-size: 16px;
cursor: pointer;
}
</style>
</head>
<body>
<div id='app'>
<div class='box'>
<div style="padding: 0 10px; margin-bottom: 10px;">
<button v-show="!loading" @click="handlerCheck">开始检测</button>
<button v-show="loading" @click="handlerStopCheck">停止检测</button>
</div>
<div class="items">
<table border="1">
<tr>
<th>name</th>
<th>mac</th>
<th>family</th>
<th>netmask</th>
<th>address</th>
</tr>
<tr v-for="w of works" class="item">
<td>{{w.name}}</td>
<td>{{w.mac}}</td>
<td>{{w.family}}</td>
<td>{{w.netmask}}</td>
<td>{{w.address}}</td>
</tr>
</table>
</div>
</div>
</div>
<script>
const params = {};
try {
const arr = location.search.split('?')[1].split('&');
arr.forEach(i => {
const obj = i.split('=');
params[obj[0]] = obj[1];
})
} catch (err) {
}
const id = params.id;
const port = params.port;
console.log(id, port)
const { createApp } = Vue
const HelloVueApp = {
data() {
return {
loading: false, // 检测按钮
works: [],
}
},
mounted() {
const ws = new WebSocket(`ws://localhost:${port}`);
ws.addEventListener('open', (event) => {
console.log('WebSocket connected!');
this.connected = true; // 连接成功
});
ws.addEventListener('message', ({ data }) => {
try {
const { code, payload } = JSON.parse(data);
console.log(payload)
if (code == 'start') {
this.works = payload;
} else if (code == 'stop') {
// this.works = [];
}
} catch (err) { }
});
ws.addEventListener('close', (event) => {
console.log('WebSocket disconnected!');
this.connected = false;
});
this.ws = ws;
},
methods: {
handlerCheck() {
this.loading = true;
this.ws.send(JSON.stringify({ code: 'start', id }))
},
handlerStopCheck() {
this.loading = false;
this.ws.send(JSON.stringify({ code: 'stop', id }))
}
}
}
Vue.createApp(HelloVueApp).mount('#app')
</script>
</body>
</html>
- port是配置的所以需要传递过去给html
- id是获取node能力所需要的
- html可以自由扩展发挥,项目化也是可以的,node-red作为配置以及服务器使用
- vue.js 是vue 3 官网下载的
- 写的毕竟粗糙
- 发布之后的打开url:http://127.0.0.1:1880/ui.html?id={socket.port} 查看
网友评论