- node-red的基礎(chǔ)使用不講了,百度有較多資料,跟著官網(wǎng)也可以寫個(gè)簡(jiǎn)單的自定義組件
- 這里主要講的是如何將復(fù)雜的組件輸出成一個(gè) 獨(dú)立的html頁面并于vue框架結(jié)合形成一個(gè)友好的頻繁交互頁面
- 第一:創(chuàng)建一個(gè)”config“類型的配置項(xiàng),從而創(chuàng)建一個(gè)websocket長(zhǎng)連接,進(jìn)行頻繁的數(shù)據(jù)交換
- 第二:創(chuàng)建一個(gè)html文件,引入vue,寫一個(gè)漂亮一些的可視化頁面
- 第三:創(chuàng)建一個(gè)組件,提供一些node服務(wù),并關(guān)聯(lián)上你寫的websocket服務(wù),啟動(dòng)你的html頁面
配置socket
選擇配置
流程
產(chǎn)生url
創(chuàng)建的菜單 my-com
image.png
image.png
image.png
- ui文件夾是組件加入后需要公開的文件
- mycom 是自定義組件
- socket 是長(zhǎng)鏈接配置
- 下面上代碼
- mycom.html
<!-- 注冊(cè) -->
<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', // 標(biāo)簽
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服務(wù)</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
<!-- 注冊(cè)節(jié)點(diǎn) -->
<script type="text/javascript">
RED.nodes.registerType('my-socket', {
category: 'config', // 節(jié)點(diǎn)類型:配置,設(shè)置類
defaults: {
name: { value: "my-socket" },
port: { value: '1881', required: true }
},
label: function () {
return this.name;
}
});
</script>
<!-- 展示內(nèi)容 -->
<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') {
// 持續(xù)檢測(cè)
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('已啟動(dòng)')
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">開始檢測(cè)</button>
<button v-show="loading" @click="handlerStopCheck">停止檢測(cè)</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, // 檢測(cè)按鈕
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可以自由擴(kuò)展發(fā)揮,項(xiàng)目化也是可以的,node-red作為配置以及服務(wù)器使用
- vue.js 是vue 3 官網(wǎng)下載的
- 寫的畢竟粗糙
- 發(fā)布之后的打開url:http://127.0.0.1:1880/ui.html?id=
{socket.port} 查看