sybz-components 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,252 @@
1
+ const n = `import qs from 'qs'
2
+
3
+ type Timeout = ReturnType<typeof setTimeout>
4
+ type Interval = ReturnType<typeof setInterval>
5
+ type Nullable<T> = T | null
6
+
7
+ const reconnectMaxCount = 3
8
+ const message = 'ping'
9
+ const interval = 3000
10
+ const timeout = 1000
11
+
12
+ /**
13
+ * WebSocket 自动重连配置。
14
+ */
15
+ export interface WSAutoReconnectOptions {
16
+ /**
17
+ * 最大重连次数,默认 \`3\`。
18
+ */
19
+ reconnectMaxCount?: number
20
+ }
21
+
22
+ /**
23
+ * WebSocket 心跳配置。
24
+ */
25
+ export interface WSHeartbeatOptions {
26
+ /**
27
+ * 心跳消息内容,默认 \`ping\`。
28
+ */
29
+ message: string
30
+ /**
31
+ * 心跳间隔,单位毫秒,默认 \`3000\`。
32
+ */
33
+ interval: number
34
+ }
35
+
36
+ /**
37
+ * \`WS\` 构造函数可选配置。
38
+ */
39
+ export interface WSOptions {
40
+ /**
41
+ * 是否自动重连。
42
+ *
43
+ * - \`true\`: 使用默认重连策略
44
+ * - \`false\`: 不自动重连
45
+ * - 对象: 自定义重连次数
46
+ */
47
+ autoReconnect: boolean | WSAutoReconnectOptions
48
+ /**
49
+ * 是否开启心跳。
50
+ *
51
+ * - \`false\`: 不发送心跳
52
+ * - \`true\`: 使用默认心跳策略
53
+ * - 对象: 自定义心跳内容和间隔
54
+ */
55
+ heartbeat: boolean | WSHeartbeatOptions
56
+ /**
57
+ * 需要拼接到 url 上的查询参数。
58
+ */
59
+ query: Record<string, string>
60
+ }
61
+
62
+ /**
63
+ * WebSocket 轻量封装,支持自动连接、自动重连、心跳和 query 参数。
64
+ *
65
+ * @example
66
+ * const ws = new WS('wss://example.com/ws', {
67
+ * autoReconnect: true,
68
+ * heartbeat: { message: 'ping', interval: 3000 },
69
+ * query: { token: 'demo-token' },
70
+ * })
71
+ *
72
+ * ws.onMessage((message) => {
73
+ * console.log(message)
74
+ * })
75
+ *
76
+ * ws.send('hello')
77
+ */
78
+ export class WS {
79
+ url: string
80
+ socket: WebSocket | null = null
81
+ reconnectCount = 0
82
+ delay: Nullable<Timeout> = null
83
+ timer: Nullable<Interval> = null
84
+ autoReconnect: WSOptions['autoReconnect']
85
+ heartbeat: WSOptions['heartbeat']
86
+ query: WSOptions['query']
87
+
88
+ /**
89
+ * 创建并立即连接一个 WebSocket 实例。
90
+ *
91
+ * @param url WebSocket 地址,例如 \`wss://example.com/ws\`。
92
+ * @param options 连接配置,支持重连、心跳和 query 参数。
93
+ *
94
+ * @example
95
+ * const ws = new WS('wss://example.com/ws', {
96
+ * autoReconnect: { reconnectMaxCount: 5 },
97
+ * heartbeat: { message: 'ping', interval: 5000 },
98
+ * query: { token: 'abc123' },
99
+ * })
100
+ */
101
+ constructor(url?: string, options?: WSOptions) {
102
+ const { autoReconnect = true, query = {}, heartbeat = false } = options || {}
103
+ this.autoReconnect = autoReconnect
104
+ this.heartbeat = heartbeat
105
+ this.query = query
106
+
107
+ this.url = \`\${url}\` + qs.stringify({ ...this.query }, { addQueryPrefix: true })
108
+
109
+ this.connect()
110
+ }
111
+
112
+ /**
113
+ * 主动发起连接。
114
+ *
115
+ * 调用时会先关闭旧连接,再创建新的 WebSocket 实例。
116
+ *
117
+ * @example
118
+ * const ws = new WS('wss://example.com/ws')
119
+ * ws.connect()
120
+ */
121
+ connect(): void {
122
+ this.close()
123
+ this.socket = new WebSocket(this.url)
124
+ this.onError()
125
+ this.onOpen()
126
+ }
127
+
128
+ /**
129
+ * 注册连接成功后的处理逻辑,并在需要时开启心跳。
130
+ *
131
+ * @example
132
+ * const ws = new WS('wss://example.com/ws')
133
+ * ws.onOpen()
134
+ */
135
+ onOpen(): void {
136
+ if (this.socket) {
137
+ this.socket.onopen = () => {
138
+ this.send('ping')
139
+ this.heartbeat && this.startHeartbeat()
140
+ }
141
+ }
142
+ }
143
+
144
+ /**
145
+ * 开启心跳发送。
146
+ *
147
+ * @example
148
+ * const ws = new WS('wss://example.com/ws', {
149
+ * heartbeat: { message: 'ping', interval: 3000 },
150
+ * })
151
+ * ws.startHeartbeat()
152
+ */
153
+ startHeartbeat(): void {
154
+ const msg = (this.heartbeat as WSHeartbeatOptions)?.message || message
155
+ const int = (this.heartbeat as WSHeartbeatOptions)?.interval || interval
156
+ this.timer = setInterval(() => {
157
+ this.send(msg)
158
+ }, int)
159
+ }
160
+
161
+ /**
162
+ * 注册错误处理和自动重连逻辑。
163
+ *
164
+ * @example
165
+ * const ws = new WS('wss://example.com/ws', { autoReconnect: true })
166
+ * ws.onError()
167
+ */
168
+ onError(): void {
169
+ if (this.socket) {
170
+ this.socket.onerror = () => {
171
+ const count = (this.autoReconnect as WSAutoReconnectOptions)?.reconnectMaxCount || reconnectMaxCount
172
+ if (this.autoReconnect && this.reconnectCount < count) {
173
+ this.reconnectCount++
174
+ this.connect()
175
+ }
176
+ }
177
+ }
178
+ }
179
+
180
+ /**
181
+ * 关闭连接并清理相关定时器。
182
+ *
183
+ * @example
184
+ * ws.close()
185
+ */
186
+ close(): void {
187
+ this.socket && this.socket.close()
188
+ this.delay && clearTimeout(this.delay)
189
+ this.timer && clearInterval(this.timer)
190
+ this.socket = null
191
+ }
192
+
193
+ /**
194
+ * 监听服务端消息。
195
+ *
196
+ * 内部会优先尝试将消息解析为 JSON;解析失败时会回传原始 \`MessageEvent\`。
197
+ *
198
+ * @param callback 接收到消息时触发的回调。
199
+ *
200
+ * @example
201
+ * ws.onMessage((message) => {
202
+ * console.log(message)
203
+ * })
204
+ */
205
+ onMessage(callback: (data: unknown) => any): void {
206
+ if (this.socket) {
207
+ this.socket.onmessage = (data) => {
208
+ try {
209
+ const res = JSON.parse(data.data)
210
+ callback(res)
211
+ } catch (err) {
212
+ callback(data)
213
+ }
214
+ }
215
+ }
216
+ }
217
+
218
+ /**
219
+ * 发送消息。
220
+ *
221
+ * - 如果连接已就绪,会立即发送
222
+ * - 如果正在连接,会延迟发送
223
+ * - 如果连接已关闭,会先重新连接再发送
224
+ *
225
+ * @param data 需要发送的消息内容。
226
+ *
227
+ * @example
228
+ * ws.send('hello')
229
+ *
230
+ * @example
231
+ * ws.send(JSON.stringify({ type: 'ping' }))
232
+ */
233
+ send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void {
234
+ if (!this.socket) return
235
+ if (this.socket.readyState === this.socket.OPEN) {
236
+ this.socket.send(JSON.stringify(data))
237
+ } else if (this.socket.readyState === this.socket.CONNECTING) {
238
+ this.delay = setTimeout(() => {
239
+ this.socket?.send(data)
240
+ }, timeout)
241
+ } else {
242
+ this.connect()
243
+ this.delay = setTimeout(() => {
244
+ this.socket?.send(data)
245
+ }, timeout)
246
+ }
247
+ }
248
+ }
249
+ `;
250
+ export {
251
+ n as default
252
+ };
package/package.json ADDED
@@ -0,0 +1,116 @@
1
+ {
2
+ "name": "sybz-components",
3
+ "version": "0.0.2",
4
+ "description": "Vue3 中基于Element-plus二次封装基础组件文档",
5
+ "private": false,
6
+ "type": "module",
7
+ "main": "dist/sybz-components-es.js",
8
+ "unpkg": "dist/sybz-components-umd.js",
9
+ "module": "dist/sybz-components-es.js",
10
+ "style": "dist/style.css",
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/sybz-components-es.js",
14
+ "default": "./dist/sybz-components-es.js"
15
+ },
16
+ "./style.css": "./dist/style.css",
17
+ "./utilities.css": "./dist/utilities.css",
18
+ "./utilities.scss": "./dist/utilities.scss"
19
+ },
20
+ "files": [
21
+ "dist"
22
+ ],
23
+ "workspaces": [
24
+ "packages/utils"
25
+ ],
26
+ "scripts": {
27
+ "dev": "vitepress dev docs",
28
+ "build": "vite build",
29
+ "preview": "vite preview",
30
+ "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
31
+ "release": "pnpm build && npm version patch && npm publish",
32
+ "format": "prettier --write example/ packages/ docs/",
33
+ "docsdev": "vitepress dev docs",
34
+ "docsbuild": "vitepress build docs",
35
+ "docsserve": "vitepress serve docs",
36
+ "deploy": "sh -x deploy.sh",
37
+ "release-deploy": "pnpm release && npm run deploy",
38
+ "update-document": "pnpm build && npm run deploy",
39
+ "deploy-no-build": "sh -x deploy.sh -k",
40
+ "utils:release": "pnpm run -C packages/utils release"
41
+ },
42
+ "dependencies": {
43
+ "@element-plus/icons-vue": "^2.3.1",
44
+ "@fortawesome/fontawesome-svg-core": "^6.3.0",
45
+ "@fortawesome/free-solid-svg-icons": "^6.3.0",
46
+ "@fortawesome/vue-fontawesome": "^3.0.6",
47
+ "@iconify/json": "^2.2.438",
48
+ "@sybz-components/utils": "workspace:*",
49
+ "@rollup/plugin-terser": "^0.4.4",
50
+ "@typescript-eslint/eslint-plugin": "^5.40.0",
51
+ "@typescript-eslint/parser": "^5.40.0",
52
+ "@vitejs/plugin-vue-jsx": "^3.1.0",
53
+ "@vue/shared": "^3.4.27",
54
+ "@vueuse/core": "^10.9.0",
55
+ "autoprefixer": "^10.4.18",
56
+ "chalk": "^5.3.0",
57
+ "consola": "^3.2.3",
58
+ "dayjs": "^1.11.19",
59
+ "element-plus": "^2.11.5",
60
+ "escape-html": "^1.0.3",
61
+ "fast-glob": "^3.3.3",
62
+ "lodash-es": "^4.17.21",
63
+ "markdown-it": "^13.0.1",
64
+ "markdown-it-container": "^3.0.0",
65
+ "normalize.css": "^8.0.1",
66
+ "pinia": "^2.1.7",
67
+ "prismjs": "^1.29.0",
68
+ "rollup": "^4.9.6",
69
+ "sass": "^1.70.0",
70
+ "tippy.js": "^6.3.7",
71
+ "typescript": "^5.3.3",
72
+ "unbuild": "^3.6.0",
73
+ "unplugin-icons": "^23.0.1",
74
+ "vite-plugin-svg-icons": "^2.0.1",
75
+ "vite-plugin-vue-setup-extend": "^0.4.0",
76
+ "vite-svg-loader": "^5.1.0",
77
+ "vitepress": "1.0.0-rc.1",
78
+ "vue-router": "^4.2.5",
79
+ "vue-tippy": "^6.4.1",
80
+ "vue-tsc": "^3.1.5"
81
+ },
82
+ "devDependencies": {
83
+ "@rushstack/eslint-patch": "^1.3.3",
84
+ "@vitejs/plugin-vue": "^5.0.3",
85
+ "@vue/eslint-config-prettier": "^8.0.0",
86
+ "code-inspector-plugin": "^0.10.1",
87
+ "eslint": "^8.49.0",
88
+ "eslint-plugin-vue": "^9.17.0",
89
+ "prettier": "^3.0.3",
90
+ "terser": "^5.31.1",
91
+ "vite": "^5.2.11",
92
+ "vite-plugin-md": "^0.21.5",
93
+ "echarts": "^5.5.0",
94
+ "vue-echarts": "^7.0.3",
95
+ "vue": "^3.4.15"
96
+ },
97
+ "repository": {
98
+ "type": "git",
99
+ "url": "https://github.com/liulihao88/sybz-components"
100
+ },
101
+ "homepage": "https://liulihao88.github.io/sybz-components/",
102
+ "keywords": [
103
+ "sybz",
104
+ "vue3",
105
+ "element-plus",
106
+ "components",
107
+ "sybz",
108
+ "思云博志",
109
+ "llh"
110
+ ],
111
+ "peerDependencies": {
112
+ "echarts": ">=5.5.0 <6",
113
+ "vue-echarts": ">=6.7.3 <8",
114
+ "vue": ">=3.4.0 <4"
115
+ }
116
+ }