{"id":241,"date":"2025-03-05T13:52:00","date_gmt":"2025-03-05T05:52:00","guid":{"rendered":"https:\/\/mitongxue.cn\/?p=241"},"modified":"2026-06-05T13:53:34","modified_gmt":"2026-06-05T05:53:34","slug":"%e5%b0%81%e8%a3%85websocket","status":"publish","type":"post","link":"https:\/\/mitongxue.cn\/index.php\/2025\/03\/05\/%e5%b0%81%e8%a3%85websocket\/","title":{"rendered":"\u5c01\u88c5websocket"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>npm install socket.io-client<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">\u4f7f\u7528socket.io-client<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>import { io, type Socket } from \"socket.io-client\";\nimport { ref } from \"vue\";\n\ninterface WbeSocketOptions { \n  autoConnect?: boolean;\n  reconnectionAttempts?: number;\n  reconnectionDelay?: number;\n}\n\ntype WebSocketStatus = \"connecting\" | \"connected\" | \"disconnected\" | \"error\";\ntype EventCallback&lt;T=any> = (data: T) => void;\n\n\nexport default function useWebSocket(\n  url: string,\n  options: WbeSocketOptions = {}\n) { \n  const { \n    autoConnect = true,\n    reconnectionAttempts = 5,\n    reconnectionDelay = 3000\n  } = options;\n\n  \/\/ \u54cd\u5e94\u5f0f\u72b6\u6001\n  const socket = ref&lt;Socket | null>(null);\n  const connectionStatus = ref&lt;WebSocketStatus>(\"disconnected\");\n  const lastError = ref&lt;Error | null>(null);\n  const eventCallbacks = new Map&lt;string, EventCallback>();\n\n  \/\/ \u521d\u59cb\u5316Socket.IO\n  const initSocket = () => {\n    socket.value = io(url, { autoConnect, reconnectionAttempts, reconnectionDelay });\n\n    socket.value.on(\"connect\", () => {\n      connectionStatus.value = \"connected\";\n      lastError.value = null;\n    });\n\n    socket.value.on(\"disconnect\", () => {\n      connectionStatus.value = \"disconnected\";\n    });\n\n    socket.value.on(\"error\", (error: Error) => {\n      connectionStatus.value = \"error\";\n      lastError.value = error;\n    });\n\n    \/\/ \u901a\u7528\u7684\u6d88\u606f\u5904\u7406\n    socket.value.onAny((eventName: string, data: any) => {\n      const callback = eventCallbacks.get(eventName);\n      if (callback) {\n        callback(data);\n      }\n    })\n  };\n\n  \/\/ \u8ba2\u9605\u4e8b\u4ef6\n  const subscribe = &lt;T>(eventName:string, callback:EventCallback&lt;T>) => { \n    eventCallbacks.set(eventName, callback);\n  }\n\n  \/\/ \u53d6\u6d88\u8ba2\u9605\n  const unsubscribe = (eventName: string) => { \n    eventCallbacks.delete(eventName);\n  }\n\n  \/\/ \u624b\u52a8\u8fde\u63a5\n  const connect = () => { \n    if (!socket.value) { \n      initSocket();\n    }\n    socket.value?.connect();\n  }\n\n  const disconnect = () => {\n    socket.value?.disconnect();\n    eventCallbacks.clear();\n  }\n\n  if(autoConnect) { \n    initSocket();\n  }\n\n  return {\n    socket,\n    connectionStatus,\n    lastError,\n    subscribe,\n    unsubscribe,\n    connect,\n    disconnect\n  }\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">\u4f7f\u7528<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>&lt;template>\n  &lt;div class=\"screen-block\">\n    &lt;Title>\u9500\u552e\u7edf\u8ba1&lt;\/Title>\n    &lt;div style=\"width: 100%; height: 90%\">\n      &lt;v-chart :option=\"option\" \/>\n    &lt;\/div>\n  &lt;\/div>\n&lt;\/template>\n\n&lt;script setup lang=\"ts\">\nimport { onMounted, ref } from \"vue\";\nimport Title from \"..\/Title.vue\";\nimport * as echarts from \"echarts\";\nimport useWebSocket from \"@\/composables\/useWebSocket\";\n\nconst { subscribe } = useWebSocket('http:\/\/localhost:3000', {\n  autoConnect: true,\n})\n\nconst option = ref({})\n\n\nconst initOption = () => { \n  option.value = {\n    tooltip: {\n      trigger: \"axis\",\n      axisPointer: {\n        type: \"line\",\n        z: 0,\n        lineStyle: {\n          color: \"#2d3443\",\n        },\n      },\n    },\n    \/\/x\u8f74\n    xAxis: {\n      splitLine: { show: false }, \/\/ \u662f\u5426\u663e\u793a\u7f51\u683c\u7ebf\n      axisLine: { show: true }, \/\/ \u662f\u5426\u663e\u793a\u8f74\u7ebf\n      type: \"value\", \/\/ \u4f5c\u4e3a\u6570\u636e\u5c55\u793a\n    },\n    \/\/y\u8f74\n    yAxis: {\n      type: \"category\",\n      data: &#91;],\n      inverse: true, \/\/ y\u8f74\u53cd\u5411\n      axisLine: { show: true }, \/\/ \u662f\u5426\u663e\u793a\u8f74\u7ebf\n      axisTick: { show: false }, \/\/ \u662f\u5426\u663e\u793a\u523b\u5ea6\n      axisLabel: {\n        color: \"#fff\",\n      },\n    },\n    grid: {\n      top: \"3%\",\n      right: \"4%\",\n      bottom: \"3%\",\n      left: \"3%\",\n      containLabel: true,\n    },\n    series: &#91;\n      {\n        type: \"bar\",\n        label: {\n          show: true,\n          position: \"right\",\n        },\n        data: &#91;],\n        barWidth: 22,\n        roundCap: true,\n        showBackground: true,\n        backgroundStyle: {\n          color: \"rgba(220, 220, 220, 0.3)\",\n        },\n        itemStyle: {\n          borderWidth: 0,\n          borderRadius: &#91;0, 10, 10, 0],\n          color: new echarts.graphic.LinearGradient(0, 0, 1, 0, &#91;\n            {\n              offset: 0,\n              color: \"#00fffb\",\n            },\n            {\n              offset: 1,\n              color: \"#0061ce\",\n            },\n          ]),\n        },\n      },\n    ],\n  };\n} \n\nonMounted(() => {\n  initOption()\n})\n\nconst updateOption = (data: Array&lt;{name:string, value:number}>) => { \n  const categories = data.map((item) => item.name)\n  const values = data.map((item) => item.value)\n\n  option.value = {\n    yAxis: {\n      data: categories,\n    },\n    series: &#91;\n      {\n        data: values,\n      },\n    ],\n  }\n}\n\nsubscribe('salesData', updateOption)\n&lt;\/script>\n\n&lt;style lang=\"scss\" scoped>\n.screen-block {\n  width: 100%;\n  height: 100%;\n}\n&lt;\/style>\n<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>\u4f7f\u7528socket.io-client \u4f7f\u7528<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[16,13,11],"tags":[],"class_list":["post-241","post","type-post","status-publish","format-standard","hentry","category-js","category-vue","category-front"],"featured_image_urls":{"full":"","thumbnail":"","medium":"","medium_large":"","large":"","1536x1536":"","2048x2048":""},"author_info":{"info":["\u9648 \u67d0\u4eba"]},"category_info":"<a href=\"https:\/\/mitongxue.cn\/index.php\/category\/front\/js\/\" rel=\"category tag\">JS<\/a> <a href=\"https:\/\/mitongxue.cn\/index.php\/category\/front\/vue\/\" rel=\"category tag\">Vue<\/a> <a href=\"https:\/\/mitongxue.cn\/index.php\/category\/front\/\" rel=\"category tag\">\u524d\u7aef<\/a>","tag_info":"\u524d\u7aef","comment_count":"0","_links":{"self":[{"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/posts\/241","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/comments?post=241"}],"version-history":[{"count":2,"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/posts\/241\/revisions"}],"predecessor-version":[{"id":243,"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/posts\/241\/revisions\/243"}],"wp:attachment":[{"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/media?parent=241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/categories?post=241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mitongxue.cn\/index.php\/wp-json\/wp\/v2\/tags?post=241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}