为了方便测试连接mqtt,自己写了个测试的页面,界面如下图:
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="#" />
<link href="https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.1/theme-chalk/index.css" rel="stylesheet" />
<link rel="stylesheet" href="//at.alicdn.com/t/font_2292707_b2m1g0ybo1.css">
<style>
html,
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
color: #fff;
font-size: 16px;
}
* {
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
#app {
height: 100%;
text-align: center;
overflow: hidden;
}
.el-container {
height: 100%;
}
.el-header,
.el-footer {
color: #000;
line-height: 60px;
background-color: #d7e2f1;
}
.el-aside {
height: 100%;
color: #333;
background-color: #D3DCE6;
}
.history-wrap {
height: calc(100% - 70px);
overflow: auto;
}
.history-link {
color: #444;
font-size: 14px;
line-height: 40px;
height: 40px;
cursor: pointer;
}
i.el-icon-close {
display: none;
}
.history-link:hover {
color: #51a5fa;
}
.history-link:hover i.el-icon-close {
display: inline-block;
}
.active {
color: #1b89f7;
}
.el-main {
height: 100%;
color: #333;
background-color: #E9EEF3;
}
.row {
margin-bottom: 20px;
}
.el-button {
width: 100px;
}
.el-icon--right {
margin-right: 10px;
}
.show-content {
height: calc(100% - 260px);
padding: 20px;
color: #fff;
background-color: #000;
text-align: left;
max-height: 339px;
}
[v-clock] {
display: none;
}
.text {
text-align: left;
}
.tip {
font-size: 12px;
color: #ccc;
}
.message-text {
overflow: auto;
height: 100%;
padding: 10px 0;
word-break: break-all;
color: #fff;
background-color: #000;
}
.iconfont {
font-size: 14px;
margin-right: 5px;
}
</style>
<title>mqtt-test</title>
</head>
<body>
<div id="app" v-clock>
<el-container>
<el-header>MQTT测试工具</el-header>
<el-container>
<el-aside width="200px">
<h3>历史记录</h3>
<div class="history-wrap">
<div @click="onClickHistory(index)" class="history-link" :class="{active: index==currentIndex}"
v-for="(item, index) in historyList" :key="index">{{item.ip}} <i
@click.stop="onDelete(index)" class="el-icon-close"></i> </div>
</div>
</el-aside>
<el-main>
<div class="row">
<el-row class="row" :gutter="20" type="flex" align="middle">
<el-col :span="6">
<el-row type="flex" align="middle">
<el-col :span="4">IP</el-col>
<el-col :span="20" :push="1">
<el-input v-model="ip" placeholder="请输入ip"></el-input>
</el-col>
</el-row>
</el-col>
<el-col :span="6">
<el-row type="flex" align="middle">
<el-col :span="4">端口</el-col>
<el-col :span="20" :push="1">
<el-input v-model="port" placeholder="请输入端口"></el-input>
</el-col>
</el-row>
</el-col>
<el-col :span="6">
<el-row type="flex" align="middle">
<el-col :span="4">路径</el-col>
<el-col :span="20" :push="1">
<el-input v-model="path" placeholder="请输入路径"></el-input>
</el-col>
</el-row>
</el-col>
<el-col :span="6">
<el-button :disabled="hasConnect" @click="onConnect" type="primary" size="medium"><i
class="iconfont icon-lianjie"></i>连接</el-button>
<el-button :disabled="!hasConnect" @click="onDisconnect" type="primary" size="medium"><i
class="iconfont icon-duankailianjie"></i>断开</el-button>
</el-col>
</el-row>
</div>
<div class="row">
<el-row :gutter="20" type="flex" align="middle">
<el-col :span="6">
<el-row type="flex" align="middle">
<el-col :span="6">订阅主题</el-col>
<el-col :span="18" :push="1">
<el-input v-model="sub" placeholder="请输入订阅主题"></el-input>
</el-col>
</el-row>
</el-col>
<el-col :span="6">
<el-button :disabled="!hasConnect" @click="onSub" prefix-icon="" type="primary"
size="medium"><i class="iconfont icon-dingyue"></i>订阅</el-button>
</el-col>
</el-row>
</div>
<div class="row">
<el-row :gutter="20" type="flex" align="middle">
<el-col :span="6">
<el-row type="flex" align="middle">
<el-col :span="6">发布主题</el-col>
<el-col :span="18" :push="1">
<el-input v-model="pub" placeholder="请输入发布订阅主题"></el-input>
</el-col>
</el-row>
</el-col>
<el-col :span="10" :push="1">
<el-row type="flex" align="middle">
<el-col :span="4">发布内容</el-col>
<el-col :span="20" :push="1">
<el-input v-model="content" type="textarea" rows="5" placeholder="请输入发布内容">
</el-input>
</el-col>
</el-row>
</el-col>
<el-col :span="6" :push="1">
<el-button :disabled="!hasConnect" @click="onPub" type="primary" size="medium"><i
class="iconfont icon-fabu"></i>发布</el-button>
<el-button :disabled="!hasConnect" @click="onClearMessage" type="primary" size="medium">
<i class="iconfont icon-qingchu"></i>清除</el-button>
</el-col>
</el-row>
</div>
<div class="show-content">
<el-row>
<el-col :span="12">
接受的消息:
</el-col>
<el-col :span="12">
发布的消息
</el-col>
</el-row>
<div class="message-text">
<div class="box">
<el-row>
<el-col :span="12">
<div class="sub-box">
<div class="text" v-for="(item,index) in subList" :key="index">
<span v-html="item"></span>
</div>
<div class="tip" v-if="subList.length == 0">暂未收到消息</div>
</div>
</el-col>
<el-col :span="12">
<div class="text" v-for="(item,index) in pubList" :key="index">
<span v-html="item"></span>
</div>
</el-col>
</el-row>
</div>
</div>
</div>
</el-main>
</el-container>
</el-container>
</div>
</body>
</html>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.0/axios.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/element-ui/2.14.1/index.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/mqtt/4.2.6/mqtt.js"></script>
<script>
const app = new Vue({
el: "#app",
data() {
return {
ip: 'xx.xx.xx.xx',
port: '9001',
path: '/mqtt',
sub: 'test',
pub: 'test',
content: 'hello',
pubList: [],
subList: [],
client: null,
hasConnect: false,
historyList: [],
currentIndex: -1
};
},
computed: {
num() {
return this.subList.length > 0 ? '12' : '0'
}
},
watch: {
subList(n, o) {
this.$nextTick(() => {
const ele = document.querySelector('.message-text')
ele.scrollTop = ele.scrollHeight;
});
},
historyList(n) {
console.log(n)
}
},
methods: {
initStatus() {
this.hasConnect = false;
this.client && this.client.end()
this.client = null;
},
onDelete(index) {
this.historyList.splice(index, 1)
this.setHistoryList(index - 1)
},
onClickHistory(index) {
this.currentIndex = index
if (this.historyList.length == 0) return;
const {
ip,
port,
path,
sub,
pub,
content
} = this.historyList[index]
this.ip = ip
this.port = port
this.path = path
this.sub = sub
this.pub = pub
this.content = content
this.initStatus()
},
successTip(message) {
this.$message({
type: 'success',
message
})
},
now() {
return moment().format('YYYY-MM-DD HH:mm:ss')
},
formatMessage(topic, message) {
return `<span style="color: #00A000;">| ${this.now()} | 主题名称: ${topic} |</span>
<br>
<span style="word-break: break-all;line-height:1.2;padding:5px;">${message}</span>
`
},
onSub() {
this.successTip(`订阅了主题${this.sub}`)
this.client && this.client.subscribe(this.sub)
this.updateHistoryList()
},
onPub() {
this.pubList.push(this.formatMessage(this.pub, this.content))
this.client && this.client.publish(this.pub, this.content);
this.updateHistoryList()
},
onDisconnect() {
this.initStatus()
},
onConnect() {
this.client = mqtt.connect(`ws://${this.ip}:${this.port}${this.path}`);
this.client.on('connect', this.onConnectMqtt)
this.client.on('error', this.onError)
this.client.on('message', this.onMessage)
this.client.on('close', this.onClose)
this.historyList.unshift({
ip: this.ip,
port: this.port,
path: this.path
})
this.setHistoryList()
},
updateHistoryList() {
this.historyList[this.currentIndex] = {
...this.historyList[this.currentIndex],
pub: this.pub,
sub: this.sub,
content: this.content
}
this.setHistoryList(this.currentIndex)
},
setHistoryList(index = 0) {
if (index < 0) index = 0;
localStorage.setItem('history', JSON.stringify(this.historyList))
this.currentIndex = index
},
onConnectMqtt(e) {
console.log(e)
this.hasConnect = true
this.successTip('连接成功')
},
onMessage(topic, payload) {
console.log(topic, payload.toString())
this.subList.push(this.formatMessage(topic, payload.toString()))
},
onClearMessage() {
this.subList = []
this.pubList = []
},
onClose() {
if (!this.hasConnect) return this.$message({
type: 'info',
message: '已断开连接'
})
this.hasConnect = false;
this.$message.error('连接不成功,连接关闭!')
this.client.end()
},
onError(err) {
console.error(err)
this.$message.error(`出现错误了错误信息是${JSON.stringify(err)}`)
this.client.end()
},
init() {
this.historyList = localStorage.getItem('history') ? JSON.parse(localStorage.getItem(
'history')) : []
this.onClickHistory(0)
}
},
mounted() {
this.init()
},
});
Vue.config.errorHandler = function (err, vm, info) {
console.log(`Error: ${err.toString()}\nInfo: ${info}`);
app.$message.error(err.message)
}
</script>
插件全部为外链接,可以直接新建html文件拷入,双击打开使用