实现 markdown 代码解析和自动高亮

This commit is contained in:
RockYang 2023-03-23 15:11:02 +08:00
parent c700895d9c
commit a061881d4a
8 changed files with 245 additions and 31 deletions

View File

@ -11,5 +11,6 @@
* [x] OpenAI API 负载均衡,限制每个 API Key 每分钟之内调用次数不超过 15次防止被封 * [x] OpenAI API 负载均衡,限制每个 API Key 每分钟之内调用次数不超过 15次防止被封
* [ ] 角色设定,预设一些角色,比如程序员,产品经理,医生,作家,老师... * [ ] 角色设定,预设一些角色,比如程序员,产品经理,医生,作家,老师...
* [ ] markdown 语法解析 * [ ] markdown 语法解析
* [ ] 用户配置界面 * [ ] 用户配置界面,配置用户的使用习惯
* [ ] 嵌入 AI 绘画功能,支持根据描述词生成图片

View File

@ -98,7 +98,6 @@ func (s *Server) ConfigSetHandle(c *gin.Context) {
} }
// 保存配置文件 // 保存配置文件
logger.Infof("Config: %+v", s.Config)
err = types.SaveConfig(s.Config, s.ConfigPath) err = types.SaveConfig(s.Config, s.ConfigPath)
if err != nil { if err != nil {
c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "Failed to save config file"}) c.JSON(http.StatusOK, types.BizVo{Code: types.Failed, Message: "Failed to save config file"})

124
web/package-lock.json generated
View File

@ -13,7 +13,9 @@
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-plus": "^2.1.11", "element-plus": "^2.1.11",
"good-storage": "^1.1.1", "good-storage": "^1.1.1",
"highlight.js": "^11.7.0",
"json-bigint": "^1.0.0", "json-bigint": "^1.0.0",
"markdown-it": "^13.0.1",
"qs": "^6.11.1", "qs": "^6.11.1",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-router": "^4.0.15" "vue-router": "^4.0.15"
@ -3962,6 +3964,15 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/cli-highlight/node_modules/highlight.js": {
"version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
"dev": true,
"engines": {
"node": "*"
}
},
"node_modules/cli-highlight/node_modules/supports-color": { "node_modules/cli-highlight/node_modules/supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz",
@ -6228,12 +6239,11 @@
} }
}, },
"node_modules/highlight.js": { "node_modules/highlight.js": {
"version": "10.7.3", "version": "11.7.0",
"resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ==",
"dev": true,
"engines": { "engines": {
"node": "*" "node": ">=12.0.0"
} }
}, },
"node_modules/hosted-git-info": { "node_modules/hosted-git-info": {
@ -6901,6 +6911,14 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true "dev": true
}, },
"node_modules/linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"dependencies": {
"uc.micro": "^1.0.1"
}
},
"node_modules/loader-runner": { "node_modules/loader-runner": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz", "resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz",
@ -7250,12 +7268,48 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"dependencies": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"bin": {
"markdown-it": "bin/markdown-it.js"
}
},
"node_modules/markdown-it/node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"node_modules/markdown-it/node_modules/entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/mdn-data": { "node_modules/mdn-data": {
"version": "2.0.14", "version": "2.0.14",
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz", "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz",
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
"dev": true "dev": true
}, },
"node_modules/mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
},
"node_modules/media-typer": { "node_modules/media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz",
@ -10081,6 +10135,11 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"node_modules/unicode-canonical-property-names-ecmascript": { "node_modules/unicode-canonical-property-names-ecmascript": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
@ -14150,6 +14209,12 @@
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true "dev": true
}, },
"highlight.js": {
"version": "10.7.3",
"resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
"dev": true
},
"supports-color": { "supports-color": {
"version": "7.2.0", "version": "7.2.0",
"resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz", "resolved": "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz",
@ -15957,10 +16022,9 @@
"dev": true "dev": true
}, },
"highlight.js": { "highlight.js": {
"version": "10.7.3", "version": "11.7.0",
"resolved": "https://registry.npmmirror.com/highlight.js/-/highlight.js-10.7.3.tgz", "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.7.0.tgz",
"integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==", "integrity": "sha512-1rRqesRFhMO/PRF+G86evnyJkCgaZFOI+Z6kdj15TA18funfoqJXvgPCLSf0SWq3SRfg1j3HlDs8o4s3EGq1oQ=="
"dev": true
}, },
"hosted-git-info": { "hosted-git-info": {
"version": "2.8.9", "version": "2.8.9",
@ -16490,6 +16554,14 @@
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
"dev": true "dev": true
}, },
"linkify-it": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-4.0.1.tgz",
"integrity": "sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==",
"requires": {
"uc.micro": "^1.0.1"
}
},
"loader-runner": { "loader-runner": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz", "resolved": "https://registry.npmmirror.com/loader-runner/-/loader-runner-4.3.0.tgz",
@ -16775,12 +16847,41 @@
"semver": "^6.0.0" "semver": "^6.0.0"
} }
}, },
"markdown-it": {
"version": "13.0.1",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz",
"integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==",
"requires": {
"argparse": "^2.0.1",
"entities": "~3.0.1",
"linkify-it": "^4.0.1",
"mdurl": "^1.0.1",
"uc.micro": "^1.0.5"
},
"dependencies": {
"argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
},
"entities": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q=="
}
}
},
"mdn-data": { "mdn-data": {
"version": "2.0.14", "version": "2.0.14",
"resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz", "resolved": "https://registry.npmmirror.com/mdn-data/-/mdn-data-2.0.14.tgz",
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==", "integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
"dev": true "dev": true
}, },
"mdurl": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
"integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g=="
},
"media-typer": { "media-typer": {
"version": "0.3.0", "version": "0.3.0",
"resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz", "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz",
@ -18969,6 +19070,11 @@
"mime-types": "~2.1.24" "mime-types": "~2.1.24"
} }
}, },
"uc.micro": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
},
"unicode-canonical-property-names-ecmascript": { "unicode-canonical-property-names-ecmascript": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", "resolved": "https://registry.npmmirror.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",

View File

@ -13,7 +13,9 @@
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-plus": "^2.1.11", "element-plus": "^2.1.11",
"good-storage": "^1.1.1", "good-storage": "^1.1.1",
"highlight.js": "^11.7.0",
"json-bigint": "^1.0.0", "json-bigint": "^1.0.0",
"markdown-it": "^13.0.1",
"qs": "^6.11.1", "qs": "^6.11.1",
"vue": "^3.2.13", "vue": "^3.2.13",
"vue-router": "^4.0.15" "vue-router": "^4.0.15"

View File

@ -69,6 +69,10 @@ export default defineComponent({
font-size: var(--content-font-size); font-size: var(--content-font-size);
border-radius: 5px; border-radius: 5px;
p:last-child {
margin-bottom: 0
}
//.cursor { //.cursor {
// height 24px; // height 24px;
// border-left 1px solid black; // border-left 1px solid black;

View File

@ -5,6 +5,7 @@ import "element-plus/dist/index.css"
import App from './App.vue' import App from './App.vue'
import Chat from './views/Chat.vue' import Chat from './views/Chat.vue'
import NotFound from './views/404.vue' import NotFound from './views/404.vue'
import TestPage from './views/Test.vue'
import './utils/prototype' import './utils/prototype'
import "./assets/css/bootstrap.min.css" import "./assets/css/bootstrap.min.css"
import {Global} from "@/utils/storage"; import {Global} from "@/utils/storage";
@ -14,7 +15,12 @@ Global['Chat'] = Chat
const routes = [ const routes = [
{ {
name: 'home', path: '/', component: Chat, meta: { name: 'home', path: '/', component: Chat, meta: {
title: 'ChatGPT-Console' title: 'WeChat-GPT'
}
},
{
name: 'test', path: '/test', component: TestPage, meta: {
title: '测试页面'
} }
}, },
{ {

View File

@ -6,7 +6,7 @@
<el-button round>欢迎来到人工智能时代</el-button> <el-button round>欢迎来到人工智能时代</el-button>
</div> </div>
<div class="chat-box" :style="{height: chatBoxHeight+'px'}"> <div class="chat-box" id="chat-box" :style="{height: chatBoxHeight+'px'}">
<div v-for="chat in chatData" :key="chat.id"> <div v-for="chat in chatData" :key="chat.id">
<chat-prompt <chat-prompt
v-if="chat.type==='prompt'" v-if="chat.type==='prompt'"
@ -83,6 +83,8 @@ import {Tools, Lock} from '@element-plus/icons-vue'
import ConfigDialog from '@/components/ConfigDialog.vue' import ConfigDialog from '@/components/ConfigDialog.vue'
import {httpPost} from "@/utils/http"; import {httpPost} from "@/utils/http";
import {getSessionId, setSessionId} from "@/utils/storage"; import {getSessionId, setSessionId} from "@/utils/storage";
import hl from 'highlight.js'
import 'highlight.js/styles/a11y-dark.css'
export default defineComponent({ export default defineComponent({
name: "XChat", name: "XChat",
@ -92,15 +94,16 @@ export default defineComponent({
title: 'ChatGPT 控制台', title: 'ChatGPT 控制台',
logo: 'images/logo.png', logo: 'images/logo.png',
chatData: [], chatData: [],
inputValue: '', inputValue: '', //
chatBoxHeight: 0, chatBoxHeight: 0, //
showConnectDialog: false, showConnectDialog: false,
showLoginDialog: false, showLoginDialog: false,
token: '', token: '', // token
connectingMessageBox: null, lineBuffer: '', //
connectingMessageBox: null, //
socket: null, socket: null,
toolBoxHeight: 61 + 42, toolBoxHeight: 61 + 42, //
sending: false, sending: false,
loading: false loading: false
} }
@ -124,13 +127,55 @@ export default defineComponent({
// type: "reply", // type: "reply",
// id: randString(32), // id: randString(32),
// icon: 'images/gpt-icon.png', // icon: 'images/gpt-icon.png',
// content: "", // content: "使 WebSocket API WebSocket JavaScript \n" +
// "\n" +
// "```js\n" +
// "const socket = new WebSocket('ws://localhost:8080');\n" +
// "\n" +
// "// WebSocket \n" +
// "socket.addEventListener('open', (event) => {\n" +
// " console.log('WebSocket ');\n" +
// "\n" +
// " // \n" +
// " socket.send('Hello WebSocket!');\n" +
// "});\n" +
// "\n" +
// "// WebSocket \n" +
// "socket.addEventListener('message', (event) => {\n" +
// " console.log('' + event.data);\n" +
// "});\n" +
// "\n" +
// "// WebSocket \n" +
// "socket.addEventListener('close', (event) => {\n" +
// " console.log('WebSocket ');\n" +
// "});\n" +
// "\n" +
// "// WebSocket \n" +
// "socket.addEventListener('error', (event) => {\n" +
// " console.log('WebSocket ');\n" +
// "});\n" +
// "```\n" +
// "\n" +
// "使 WebSocket 便",
// }); // });
// } // }
//
// let md = require('markdown-it')();
// this.chatData[this.chatData.length - 1]["content"] = md.render(this.chatData[this.chatData.length - 1]["content"]);
//
// nextTick(() => {
// const lines = document.querySelectorAll('.chat-line');
// const blocks = lines[lines.length - 1].querySelectorAll('pre code');
// blocks.forEach((block) => {
// hl.highlightElement(block)
// })
// })
window.addEventListener("resize", () => { window.addEventListener("resize", () => {
this.chatBoxHeight = window.innerHeight - this.toolBoxHeight; this.chatBoxHeight = window.innerHeight - this.toolBoxHeight;
}); });
}, },
methods: { methods: {
@ -141,7 +186,7 @@ export default defineComponent({
this.connect(); this.connect();
} }
// //
setTimeout(() => this.checkSession(), 5000); //setTimeout(() => this.checkSession(), 5000);
}).catch((res) => { }).catch((res) => {
if (res.code === 400) { if (res.code === 400) {
this.showLoginDialog = true; this.showLoginDialog = true;
@ -173,9 +218,8 @@ export default defineComponent({
socket.addEventListener('open', () => { socket.addEventListener('open', () => {
ElMessage.success('创建会话成功!'); ElMessage.success('创建会话成功!');
if (this.connectingMessageBox != null) { if (this.connectingMessageBox && typeof this.connectingMessageBox.close === 'function') {
this.connectingMessageBox.close(); this.connectingMessageBox.close();
this.connectingMessageBox = null;
} }
}); });
@ -195,16 +239,19 @@ export default defineComponent({
}); });
} else if (data.type === 'end') { } else if (data.type === 'end') {
this.sending = false; this.sending = false;
this.lineBuffer = ''; //
} else { } else {
let content = data.content; this.lineBuffer += data.content;
// let md = require('markdown-it')();
if (content.indexOf("\n\n") >= 0) { this.chatData[this.chatData.length - 1]["content"] = md.render(this.lineBuffer);
if (this.chatData[this.chatData.length - 1]["content"].length === 0) {
return nextTick(() => {
} const lines = document.querySelectorAll('.chat-line');
content = content.replace("\n\n", "<br />"); const blocks = lines[lines.length - 1].querySelectorAll('pre code');
} blocks.forEach((block) => {
this.chatData[this.chatData.length - 1]["content"] += content; hl.highlightElement(block)
})
})
} }
// //
nextTick(() => { nextTick(() => {

49
web/src/views/Test.vue Normal file
View File

@ -0,0 +1,49 @@
<template>
<div v-html="content" id="content"></div>
</template>
<script>
import {defineComponent, nextTick} from "vue"
import hl from 'highlight.js'
import 'highlight.js/styles/a11y-dark.css'
export default defineComponent({
name: 'TestPage',
data() {
return {
content: "测试页面",
}
},
mounted() {
let md = require('markdown-it')();
this.content = md.render("```\n" +
"const socket = new WebSocket('ws://localhost:8080');\n" +
"\n" +
"// 连接成功\n" +
"socket.addEventListener('open', event => {\n" +
" console.log('WebSocket 连接成功!');\n" +
"});\n" +
"\n" +
"// 接收消息\n" +
"socket.addEventListener('message', event => {\n" +
" console.log('收到消息:', event.data);\n" +
"});\n" +
"\n" +
"// 发送消息\n" +
"socket.send('Hello, WebSocket!');\n" +
"\n" +
"```\n" +
"\n" +
"\n" +
"以上代码创建了一个 WebSocket 连接,并在连接成功后输出一条提示信息。当收到消息时,会在控制台打印该消息。同时还演示了如何发送消息。在实际应用中,不同的框架和库可能会提供不同的 WebSocket 实现,代码可能会有所区别。");
nextTick(() => {
const blocks = document.getElementById('content').querySelectorAll('pre code');
console.log(blocks)
blocks.forEach((block) => {
hl.highlightBlock(block)
})
})
}
})
</script>