websocket快速操作工具
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

827 lines
27 KiB

2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8" />
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  7. <title>Document</title>
  8. <style>
  9. *,
  10. html,
  11. body {
  12. margin: 0;
  13. padding: 0;
  14. box-sizing: border-box;
  15. }
  16. li {
  17. list-style: none;
  18. }
  19. .container {
  20. display: flex;
  21. width: 100vw;
  22. align-items: center;
  23. box-sizing: border-box;
  24. justify-content: space-between;
  25. }
  26. .left_chat {
  27. border: solid 1px #000;
  28. height: 100vh;
  29. display: flex;
  30. box-sizing: border-box;
  31. flex-direction: column;
  32. padding: 24px;
  33. overflow: scroll;
  34. width: 500px;
  35. min-width: 500px;
  36. }
  37. .right_message {
  38. height: 100vh;
  39. box-sizing: border-box;
  40. flex: 1;
  41. }
  42. .btn {
  43. padding: 36px;
  44. font-size: 24px;
  45. margin-top: 24px;
  46. width: 100%;
  47. }
  48. .right_message {
  49. padding: 24px;
  50. border: solid 1px #000;
  51. display: flex;
  52. flex-direction: column;
  53. }
  54. .message_wrap {
  55. flex: 1;
  56. border: solid 1px #ddd;
  57. overflow: scroll;
  58. }
  59. .message {
  60. padding: 6px 8px;
  61. border-bottom: solid 1px #ddd;
  62. }
  63. .input_wrap {
  64. display: flex;
  65. align-items: center;
  66. /* margin-bottom: 20px; */
  67. }
  68. .input_wrap .ws_connnect {
  69. flex: 2;
  70. padding: 4px 0;
  71. margin-right: 20px;
  72. }
  73. .input_wrap .connect {
  74. flex: 1;
  75. }
  76. .order {
  77. display: grid;
  78. grid-template-columns: repeat(1, 1fr);
  79. column-gap: 20px;
  80. row-gap: 10px;
  81. margin-bottom: 20px;
  82. }
  83. .status {
  84. padding: 4px 0;
  85. border-bottom: solid 2px #ddd;
  86. margin-bottom: 10px;
  87. }
  88. .tabs {
  89. margin: 20px 0;
  90. }
  91. .tab-bar {
  92. display: flex;
  93. }
  94. .tab {
  95. padding: 10px 20px;
  96. border: 1px solid #ccc;
  97. border-bottom: none;
  98. cursor: pointer;
  99. }
  100. /* .active {
  101. border-bottom: 2px solid blue;
  102. } */
  103. .tab-panel {
  104. display: none;
  105. padding: 20px;
  106. border: 1px solid #ccc;
  107. }
  108. .active {
  109. display: block;
  110. }
  111. .common_order_input {
  112. display: flex;
  113. align-items: center;
  114. justify-content: space-evenly;
  115. padding: 0 20px;
  116. margin-bottom: 10px;
  117. }
  118. .common_order_input .single {
  119. display: flex;
  120. flex-direction: column;
  121. align-items: center;
  122. }
  123. .single .input {
  124. width: 100%;
  125. text-align: center;
  126. padding: 4px;
  127. }
  128. .common_btns {
  129. width: 100%;
  130. }
  131. .btn_c {
  132. width: 100%;
  133. padding: 4px 0;
  134. margin-bottom: 10px;
  135. }
  136. .report_c {
  137. border: solid 1px #ddd;
  138. padding: 10px;
  139. }
  140. .form_line {
  141. display: flex;
  142. align-items: center;
  143. width: 100%;
  144. margin-bottom: 10px;
  145. }
  146. .form_line .tit {
  147. margin-right: 6px;
  148. white-space: nowrap;
  149. }
  150. .form_line .info {
  151. width: 100%;
  152. text-align: center;
  153. padding: 4px 0;
  154. }
  155. .report_c .title {
  156. border-bottom: solid 1px #ddd;
  157. margin-bottom: 10px;
  158. }
  159. .mod-tab .tab_top {
  160. float: left;
  161. padding: 5px 20px;
  162. border-top: 1px solid #ccc;
  163. border-left: 1px solid #ccc;
  164. background-color: #ddd;
  165. }
  166. .header .tab_top:last-child {
  167. border-right: 1px solid #ccc;
  168. }
  169. .content {
  170. border: 1px solid #ccc;
  171. width: 100%;
  172. height: 100%;
  173. }
  174. .header::after {
  175. content: "";
  176. display: block;
  177. clear: both;
  178. }
  179. .mod-tab .header .active {
  180. background-color: #fff;
  181. }
  182. .mod-tab .content .panel {
  183. display: none;
  184. }
  185. .mod-tab .content .active {
  186. display: block;
  187. }
  188. .card_container {
  189. padding: 0 10px;
  190. }
  191. .card_container .title {
  192. margin-bottom: 10px;
  193. border-bottom: solid 1px #ddd;
  194. }
  195. .card_container .form {
  196. display: flex;
  197. margin-bottom: 10px;
  198. align-items: center;
  199. justify-content: space-between;
  200. }
  201. .card_container .form .label {
  202. white-space: nowrap;
  203. margin-right: 10px;
  204. }
  205. .card_container .form .input {
  206. flex: 1;
  207. padding: 4px 0;
  208. text-align: center;
  209. }
  210. .card_container .form .btn {
  211. padding: 0;
  212. margin: 0;
  213. width: 40px;
  214. margin-left: 10px;
  215. }
  216. .card_container .form .input_config {
  217. width: 60px;
  218. padding: 4px 0;
  219. text-align: center;
  220. }
  221. </style>
  222. </head>
  223. <body>
  224. <div class="container">
  225. <div class="left_chat">
  226. <div class="input_wrap">
  227. <input type="text" class="ws_connnect" id="ws_connnect_input" />
  228. <button class="connect" onclick="connectWs()">连接</button>
  229. </div>
  230. <p class="status" id="status">当前状态: 未连接</p>
  231. <div class="mod-tab">
  232. <div class="header">
  233. <button class="tab_top active button1">基本控制</button>
  234. <button class="tab_top button2">电机控制</button>
  235. <button class="tab_top button3">舵机控制</button>
  236. </div>
  237. <div class="content">
  238. <div class="panel active">
  239. <div class="report_c">
  240. <p class="title">上报解析</p>
  241. <div class="form_line">
  242. <p class="tit">ADDRESS:</p>
  243. <input
  244. type="text"
  245. class="info"
  246. disabled
  247. id="report_address"
  248. />
  249. </div>
  250. <div class="form_line">
  251. <p class="tit">VALUE:</p>
  252. <input type="text" class="info" disabled id="report_val" />
  253. </div>
  254. </div>
  255. <div class="report_c">
  256. <p class="title">回执解析</p>
  257. <div class="form_line">
  258. <p class="tit">ADDRESS:</p>
  259. <input
  260. type="text"
  261. class="info"
  262. disabled
  263. id="receipt_address"
  264. />
  265. </div>
  266. <div class="form_line">
  267. <p class="tit">VALUE:</p>
  268. <input type="text" class="info" disabled id="receipt_val" />
  269. </div>
  270. <div class="form_line">
  271. <p class="tit">结果:</p>
  272. <input
  273. type="text"
  274. class="info"
  275. value="无"
  276. disabled
  277. id="receipt_message"
  278. />
  279. </div>
  280. </div>
  281. <div class="tabs">
  282. <ul class="tab-bar">
  283. <li class="tab active">通用指令</li>
  284. <li class="tab">指令列表</li>
  285. </ul>
  286. <div class="tab-content">
  287. <div class="tab-panel active">
  288. <div class="common_order_input">
  289. <div class="single">
  290. <p>ID</p>
  291. <input type="text" class="input" id="common_id" />
  292. </div>
  293. <div
  294. class="single"
  295. style="margin-left: 10px; margin-right: 5px"
  296. >
  297. <p>BASE</p>
  298. <input type="text" class="input" id="common_base" />
  299. </div>
  300. <div
  301. class="single"
  302. style="margin-left: 5px; margin-right: 10px"
  303. >
  304. <p>OFFSET</p>
  305. <input type="text" class="input" id="common_off" />
  306. </div>
  307. <div class="single">
  308. <p>VALUE</p>
  309. <input type="text" class="input" id="common_value" />
  310. </div>
  311. </div>
  312. <div class="common_btns">
  313. <button class="btn_c" onclick="writeFun()"></button>
  314. <button class="btn_c" onclick="read()"></button>
  315. <button class="btn_c" onclick="autoReport()">
  316. 使能自动上报
  317. </button>
  318. <button class="btn_c" onclick="reportCycle()">
  319. 设置上报周期
  320. </button>
  321. </div>
  322. </div>
  323. <div class="tab-panel">
  324. <div class="order" id="order"></div>
  325. </div>
  326. </div>
  327. </div>
  328. </div>
  329. <div class="panel">
  330. <div
  331. class="common_order_input"
  332. style="border-bottom: solid 2px #ddd; padding-bottom: 10px"
  333. >
  334. <div class="single">
  335. <p>ID</p>
  336. <input type="text" class="input" />
  337. </div>
  338. <div
  339. class="single"
  340. style="margin-left: 10px; margin-right: 5px"
  341. >
  342. <p>BASE</p>
  343. <input type="text" class="input" />
  344. </div>
  345. <div
  346. class="single"
  347. style="margin-left: 5px; margin-right: 10px"
  348. >
  349. <p>OFFSET</p>
  350. <input type="text" class="input" />
  351. </div>
  352. </div>
  353. <div class="card_container">
  354. <h3 class="title">状态</h3>
  355. <div class="form">
  356. <p class="label">异常</p>
  357. <input type="text" class="input" />
  358. <button class="btn"></button>
  359. </div>
  360. <div class="form">
  361. <p class="label">状态</p>
  362. <input type="text" class="input" />
  363. <button class="btn"></button>
  364. </div>
  365. <div class="form">
  366. <p class="label">位置</p>
  367. <input type="text" class="input" />
  368. <button class="btn"></button>
  369. </div>
  370. </div>
  371. <div class="card_container">
  372. <h3 class="title">配置</h3>
  373. <div class="form">
  374. <p class="label">反复运动启始位置</p>
  375. <input type="text" class="input_config" />
  376. <button class="btn"></button>
  377. <button class="btn"></button>
  378. </div>
  379. <div class="form">
  380. <p class="label">反复运动终止位置</p>
  381. <input type="text" class="input_config" />
  382. <button class="btn"></button>
  383. <button class="btn"></button>
  384. </div>
  385. <div class="form">
  386. <p class="label">运行时速度配置</p>
  387. <input type="text" class="input_config" />
  388. <button class="btn"></button>
  389. <button class="btn"></button>
  390. </div>
  391. </div>
  392. <div class="card_container">
  393. <h3 class="title">动作</h3>
  394. <div class="form">
  395. <p class="label">舵机移动到角度</p>
  396. <input type="text" class="input" />
  397. <button class="btn"></button>
  398. </div>
  399. <div class="form">
  400. <p class="label">舵机停止</p>
  401. <input type="text" class="input" />
  402. <button class="btn"></button>
  403. </div>
  404. <div class="form">
  405. <p class="label">清除异常</p>
  406. <input type="text" class="input" />
  407. <button class="btn"></button>
  408. </div>
  409. <div class="form">
  410. <p class="label">反复运动</p>
  411. <input type="text" class="input" />
  412. <button class="btn"></button>
  413. </div>
  414. </div>
  415. </div>
  416. <div class="panel">
  417. <div
  418. class="common_order_input"
  419. style="border-bottom: solid 2px #ddd; padding-bottom: 10px"
  420. >
  421. <div class="single">
  422. <p>ID</p>
  423. <input type="text" class="input" />
  424. </div>
  425. <div
  426. class="single"
  427. style="margin-left: 10px; margin-right: 5px"
  428. >
  429. <p>BASE</p>
  430. <input type="text" class="input" />
  431. </div>
  432. <div
  433. class="single"
  434. style="margin-left: 5px; margin-right: 10px"
  435. >
  436. <p>OFFSET</p>
  437. <input type="text" class="input" />
  438. </div>
  439. </div>
  440. <div class="card_container">
  441. <h3 class="title">状态</h3>
  442. <div class="form">
  443. <p class="label">设备状态</p>
  444. <input type="text" class="input" />
  445. <button class="btn"></button>
  446. </div>
  447. <div class="form">
  448. <p class="label">异常状态</p>
  449. <input type="text" class="input" />
  450. <button class="btn"></button>
  451. </div>
  452. <div class="form">
  453. <p class="label">当前转速</p>
  454. <input type="text" class="input" />
  455. <button class="btn"></button>
  456. </div>
  457. <div class="form">
  458. <p class="label">当前位置</p>
  459. <input type="text" class="input" />
  460. <button class="btn"></button>
  461. </div>
  462. </div>
  463. <div class="card_container">
  464. <h3 class="title">配置</h3>
  465. <div class="form">
  466. <p class="label">加速度</p>
  467. <input type="text" class="input_config" />
  468. <button class="btn"></button>
  469. <button class="btn"></button>
  470. </div>
  471. <div class="form">
  472. <p class="label">减速度</p>
  473. <input type="text" class="input_config" />
  474. <button class="btn"></button>
  475. <button class="btn"></button>
  476. </div>
  477. <div class="form">
  478. <p class="label">速度</p>
  479. <input type="text" class="input_config" />
  480. <button class="btn"></button>
  481. <button class="btn"></button>
  482. </div>
  483. <div class="form">
  484. <p class="label">零点偏移</p>
  485. <input type="text" class="input_config" />
  486. <button class="btn"></button>
  487. <button class="btn"></button>
  488. </div>
  489. <div class="form">
  490. <p class="label">归零速度</p>
  491. <input type="text" class="input_config" />
  492. <button class="btn"></button>
  493. <button class="btn"></button>
  494. </div>
  495. <div class="form">
  496. <p class="label">归零减速度</p>
  497. <input type="text" class="input_config" />
  498. <button class="btn"></button>
  499. <button class="btn"></button>
  500. </div>
  501. <div class="form">
  502. <p class="label">归零最大位移</p>
  503. <input type="text" class="input_config" />
  504. <button class="btn"></button>
  505. <button class="btn"></button>
  506. </div>
  507. <div class="form">
  508. <p class="label">归零第一阶段移动距离</p>
  509. <input type="text" class="input_config" />
  510. <button class="btn"></button>
  511. <button class="btn"></button>
  512. </div>
  513. </div>
  514. <div class="card_container">
  515. <h3 class="title">动作</h3>
  516. <div class="form">
  517. <p class="label">速度模式控制</p>
  518. <input type="text" class="input" />
  519. <button class="btn"></button>
  520. </div>
  521. <div class="form">
  522. <p class="label">位置模式控制</p>
  523. <input type="text" class="input" />
  524. <button class="btn"></button>
  525. </div>
  526. <div class="form">
  527. <p class="label">位置模式相对位置</p>
  528. <input type="text" class="input" />
  529. <button class="btn"></button>
  530. </div>
  531. <div class="form">
  532. <p class="label">归零</p>
  533. <input type="text" class="input" />
  534. <button class="btn"></button>
  535. </div>
  536. <div class="form">
  537. <p class="label">零位校准</p>
  538. <input type="text" class="input" />
  539. <button class="btn"></button>
  540. </div>
  541. <div class="form">
  542. <p class="label">停止</p>
  543. <input type="text" class="input" />
  544. <button class="btn"></button>
  545. </div>
  546. <div class="form">
  547. <p class="label">清空异常</p>
  548. <input type="text" class="input" />
  549. <button class="btn"></button>
  550. </div>
  551. </div>
  552. </div>
  553. </div>
  554. </div>
  555. </div>
  556. <div class="right_message">
  557. <div class="message_wrap" id="message_wrap"></div>
  558. <div style="display: flex; align-items: center; margin-top: 10px">
  559. <textarea style="flex: 1" name="bio" rows="15" cols="40"></textarea>
  560. <div style="display: flex; flex-direction: column; height: 100%">
  561. <button style="flex: 1" onclick="sendMessage()">发送</button>
  562. <button style="flex: 1" onclick="clearTextArea()">清空</button>
  563. </div>
  564. </div>
  565. </div>
  566. </div>
  567. </body>
  568. <script src="./config.js"></script>
  569. <script>
  570. window.onload = () => {
  571. const commonI = document.querySelector("#common_id");
  572. const commonB = document.querySelector("#common_base");
  573. commonI.value = localStorage.getItem("id");
  574. commonB.value = localStorage.getItem("base");
  575. };
  576. var ws = null;
  577. const websocketInput = document.querySelector("#ws_connnect_input");
  578. websocketInput.value = websocketAddress;
  579. // 先向order下动态添加指令集合
  580. const order = document.querySelector("#order");
  581. for (let key in config) {
  582. const button = document.createElement("button");
  583. button.textContent = key;
  584. button.className = "order_btn";
  585. button.setAttribute("v", key);
  586. order?.appendChild(button);
  587. }
  588. order.addEventListener("click", (e) => {
  589. const item = e.target;
  590. if (item && item.getAttribute("v")) {
  591. const key = item.getAttribute("v");
  592. sendOrder(config[key]);
  593. }
  594. });
  595. const commonI = document.querySelector("#common_id");
  596. const commonB = document.querySelector("#common_base");
  597. commonI.addEventListener("input", (e) => {
  598. localStorage.setItem("id", e.target.value);
  599. });
  600. commonB.addEventListener("input", (e) => {
  601. localStorage.setItem("base", e.target.value);
  602. });
  603. const tabs = document.querySelector(".tabs");
  604. const tabBars = document.querySelectorAll(".tab-bar .tab");
  605. const tabPanels = document.querySelectorAll(".tab-content .tab-panel");
  606. for (let i = 0; i < tabBars.length; i++) {
  607. tabBars[i].onclick = function () {
  608. removeActive();
  609. this.classList.add("active");
  610. tabPanels[i].classList.add("active");
  611. };
  612. }
  613. function removeActive() {
  614. for (let i = 0; i < tabBars.length; i++) {
  615. tabBars[i].classList.remove("active");
  616. tabPanels[i].classList.remove("active");
  617. }
  618. }
  619. const clearMessage = () => {
  620. const messageWrap = document.querySelector("#message_wrap");
  621. messageWrap.innerHTML = "";
  622. };
  623. const clearTextArea = () => {
  624. const textArea = document.querySelector("textarea");
  625. textArea.value = "";
  626. clearMessage();
  627. };
  628. const sendMessage = () => {
  629. if (ws) {
  630. const textArea = document.querySelector("textarea");
  631. const messageVal = textArea.value;
  632. ws.send(messageVal);
  633. const messageWrap = document.querySelector("#message_wrap");
  634. const div = document.createElement("div");
  635. div.classList = ["message"];
  636. div.textContent = `Tx: ${messageVal}`;
  637. messageWrap.appendChild(div);
  638. messageWrap.scrollTop =
  639. messageWrap.scrollHeight - messageWrap.clientHeight;
  640. } else {
  641. }
  642. };
  643. const transValToName = (val) => {
  644. switch (val) {
  645. case 0x00:
  646. return "kSuccess";
  647. case 2:
  648. return "kRegNotFound";
  649. case 3:
  650. return "kRegNotWritable";
  651. case 4:
  652. return "kRegNotReadable";
  653. case 5:
  654. return "kIllegalValue";
  655. case 6:
  656. return "kDeviceBusy";
  657. case 7:
  658. return "kDeviceException";
  659. case 8:
  660. return "kChannelDeviceException";
  661. case 9:
  662. return "kParameterError";
  663. case 10:
  664. return "kOvertime";
  665. case 11:
  666. return "kOperationInvalid";
  667. case 12:
  668. return "kunsupportOperation";
  669. case 13:
  670. return "kIllegalOperation";
  671. case 14:
  672. return "kPermissionDenied";
  673. case 15:
  674. return "koutOfRange";
  675. case 16:
  676. return "kmotorNotRunToHome";
  677. case 17:
  678. return "kParameterOutOfLimit";
  679. }
  680. };
  681. const connectWs = () => {
  682. console.log(123);
  683. const input = document.querySelector("#ws_connnect_input");
  684. const status = document.querySelector("#status");
  685. const address = input.value;
  686. try {
  687. ws = new WebSocket(address);
  688. ws.onopen = function () {
  689. console.log("Connected to WebSocket server.");
  690. // 改变状态
  691. status.innerHTML = `当前状态: 已连接${address}`;
  692. };
  693. ws.onmessage = function (evt) {
  694. const messageWrap = document.querySelector("#message_wrap");
  695. const div = document.createElement("div");
  696. div.classList = ["message"];
  697. div.textContent = `Rx: ${evt.data}`;
  698. messageWrap.appendChild(div);
  699. messageWrap.scrollTop =
  700. messageWrap.scrollHeight - messageWrap.clientHeight;
  701. // 对消息进行处理
  702. try {
  703. const { message: messageBody } = JSON.parse(evt.data);
  704. const { type, ctrlPointAddr, ctrlPointVal } = messageBody;
  705. const receiptMessage = document.querySelector("#receipt_message");
  706. const receiptAddress = document.querySelector("#receipt_address");
  707. const receiptVal = document.querySelector("#receipt_val");
  708. const reportAddress = document.querySelector("#report_address");
  709. const reportVal = document.querySelector("#report_val");
  710. if (type == "receipt") {
  711. receiptMessage.value = "正确";
  712. receiptAddress.value = ctrlPointAddr;
  713. receiptVal.value = ctrlPointVal;
  714. }
  715. if (type == "error_receipt") {
  716. receiptMessage.value = "错误";
  717. receiptAddress.value = ctrlPointAddr;
  718. // 错误回执需要吧值和英文进行对应
  719. receiptVal.value = transValToName(ctrlPointVal);
  720. }
  721. if (type == "report") {
  722. reportAddress.value = ctrlPointAddr;
  723. reportVal.value = ctrlPointVal;
  724. }
  725. } catch (error) {
  726. console.log(error);
  727. }
  728. };
  729. ws.onclose = function () {
  730. status.innerHTML = `当前状态: 已关闭`;
  731. };
  732. } catch (error) {
  733. status.innerHTML = `当前状态: 连接错误`;
  734. }
  735. };
  736. const sendOrder = (msg) => {
  737. if (ws) {
  738. ws.send(msg);
  739. const messageWrap = document.querySelector("#message_wrap");
  740. const div = document.createElement("div");
  741. div.classList = ["message"];
  742. div.textContent = `Tx: ${msg}`;
  743. messageWrap.appendChild(div);
  744. messageWrap.scrollTop =
  745. messageWrap.scrollHeight - messageWrap.clientHeight;
  746. }
  747. };
  748. const getCommonOrderInput = (type) => {
  749. const id = document.querySelector("#common_id");
  750. const base = document.querySelector("#common_base");
  751. const off = document.querySelector("#common_off");
  752. const value = document.querySelector("#common_value");
  753. const { protocol, message } = commonMessage;
  754. return JSON.stringify({
  755. protocol,
  756. message: {
  757. ...message,
  758. targetId: parseInt(id.value),
  759. ctrlPointAddr: parseInt(base.value) + parseInt(off.value),
  760. ctrlPointVal: parseInt(value.value),
  761. type,
  762. },
  763. });
  764. };
  765. const writeFun = () => {
  766. const msg = getCommonOrderInput("write");
  767. sendOrder(msg);
  768. };
  769. const read = () => {
  770. const msg = getCommonOrderInput("read");
  771. sendOrder(msg);
  772. };
  773. const autoReport = () => {
  774. const msg = getCommonOrderInput("set_auto_report_enable_flag");
  775. sendOrder(msg);
  776. };
  777. const reportCycle = () => {
  778. const msg = getCommonOrderInput("set_auto_report_period");
  779. sendOrder(msg);
  780. };
  781. document.querySelectorAll(".tab_top").forEach(function (node) {
  782. node.addEventListener("click", function () {
  783. var index;
  784. this.parentElement
  785. .querySelectorAll(".tab_top")
  786. .forEach(function (e, inx) {
  787. //e.style.display='none' 跳转的时候隐藏按钮
  788. e.classList.remove("active");
  789. if (node === e) {
  790. index = inx;
  791. }
  792. });
  793. this.classList.add("active");
  794. this.parentElement.nextElementSibling
  795. .querySelectorAll(".panel")
  796. .forEach(function (panel) {
  797. panel.classList.remove("active");
  798. });
  799. this.parentElement.nextElementSibling
  800. .querySelectorAll(".panel")
  801. [index].classList.add("active");
  802. });
  803. });
  804. </script>
  805. </html>