nv-img-barcode-bw 1.0.1
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.
- package/DEPS/html2canvas.min.js +20 -0
- package/DEPS/jsbarcode.min.js +2 -0
- package/DEPS/zxing.js +1 -0
- package/DIST/nv-img-barcode-bw.full.js +3173 -0
- package/DIST/nv-img-barcode-bw.js +265 -0
- package/TEST/api.html +1132 -0
- package/TEST/code128-VS-ean128.html +501 -0
- package/TEST/gs1-VS-nongs1.html +208 -0
- package/TEST/index.html +746 -0
- package/TEST/tst.html +950 -0
- package/TOOL/api.tmpl.html +867 -0
- package/TOOL/cli-creat-dist.js +5 -0
- package/TOOL/cli-creat-html.js +13 -0
- package/TOOL/index.tmpl.html +481 -0
- package/cfg.js +56 -0
- package/com.sh +5 -0
- package/css.js +170 -0
- package/decd.js +270 -0
- package/eng.js +589 -0
- package/index.js +366 -0
- package/package.json +17 -0
- package/ui.js +36 -0
package/TEST/tst.html
ADDED
|
@@ -0,0 +1,950 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="zh-CN">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>条形码生成器 - 使用 jsbarcode</title>
|
|
7
|
+
<style>
|
|
8
|
+
* {
|
|
9
|
+
margin: 0;
|
|
10
|
+
padding: 0;
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
body {
|
|
15
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
16
|
+
line-height: 1.6;
|
|
17
|
+
color: #333;
|
|
18
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
19
|
+
min-height: 100vh;
|
|
20
|
+
padding: 20px;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.container {
|
|
24
|
+
max-width: 1000px;
|
|
25
|
+
margin: 0 auto;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
header {
|
|
29
|
+
text-align: center;
|
|
30
|
+
color: white;
|
|
31
|
+
margin-bottom: 30px;
|
|
32
|
+
padding: 20px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
h1 {
|
|
36
|
+
font-size: 2.5rem;
|
|
37
|
+
margin-bottom: 10px;
|
|
38
|
+
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.subtitle {
|
|
42
|
+
font-size: 1.1rem;
|
|
43
|
+
opacity: 0.9;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.lib-badge {
|
|
47
|
+
display: inline-block;
|
|
48
|
+
background: #07c160;
|
|
49
|
+
color: white;
|
|
50
|
+
padding: 5px 15px;
|
|
51
|
+
border-radius: 20px;
|
|
52
|
+
font-size: 0.9rem;
|
|
53
|
+
margin-top: 10px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.content {
|
|
57
|
+
display: grid;
|
|
58
|
+
grid-template-columns: 1fr 1fr;
|
|
59
|
+
gap: 20px;
|
|
60
|
+
margin-bottom: 30px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@media (max-width: 768px) {
|
|
64
|
+
.content {
|
|
65
|
+
grid-template-columns: 1fr;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.card {
|
|
70
|
+
background: white;
|
|
71
|
+
border-radius: 15px;
|
|
72
|
+
padding: 25px;
|
|
73
|
+
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.card-title {
|
|
77
|
+
font-size: 1.5rem;
|
|
78
|
+
color: #2d3748;
|
|
79
|
+
margin-bottom: 20px;
|
|
80
|
+
padding-bottom: 10px;
|
|
81
|
+
border-bottom: 3px solid #667eea;
|
|
82
|
+
display: flex;
|
|
83
|
+
align-items: center;
|
|
84
|
+
gap: 10px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.form-group {
|
|
88
|
+
margin-bottom: 20px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
label {
|
|
92
|
+
display: block;
|
|
93
|
+
margin-bottom: 8px;
|
|
94
|
+
font-weight: 600;
|
|
95
|
+
color: #4a5568;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
input, textarea, select {
|
|
99
|
+
width: 100%;
|
|
100
|
+
padding: 12px 15px;
|
|
101
|
+
border: 2px solid #e2e8f0;
|
|
102
|
+
border-radius: 8px;
|
|
103
|
+
font-size: 1rem;
|
|
104
|
+
transition: border-color 0.3s ease;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
input:focus, textarea:focus, select:focus {
|
|
108
|
+
outline: none;
|
|
109
|
+
border-color: #667eea;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
textarea {
|
|
113
|
+
min-height: 100px;
|
|
114
|
+
resize: vertical;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.btn {
|
|
118
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
119
|
+
color: white;
|
|
120
|
+
border: none;
|
|
121
|
+
padding: 12px 30px;
|
|
122
|
+
border-radius: 8px;
|
|
123
|
+
font-size: 1rem;
|
|
124
|
+
font-weight: 600;
|
|
125
|
+
cursor: pointer;
|
|
126
|
+
transition: all 0.3s ease;
|
|
127
|
+
display: inline-flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
gap: 8px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.btn:hover {
|
|
133
|
+
transform: translateY(-2px);
|
|
134
|
+
box-shadow: 0 5px 15px rgba(0,0,0,0.2);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.btn-full {
|
|
138
|
+
width: 100%;
|
|
139
|
+
justify-content: center;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.btn-secondary {
|
|
143
|
+
background: linear-gradient(135deg, #4fd1c7 0%, #319795 100%);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
.result-area {
|
|
147
|
+
margin-top: 20px;
|
|
148
|
+
padding: 20px;
|
|
149
|
+
background: #f7fafc;
|
|
150
|
+
border-radius: 8px;
|
|
151
|
+
border-left: 4px solid #667eea;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.barcode-container {
|
|
155
|
+
margin: 20px 0;
|
|
156
|
+
text-align: center;
|
|
157
|
+
padding: 20px;
|
|
158
|
+
background: white;
|
|
159
|
+
border-radius: 8px;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.barcode-image {
|
|
163
|
+
max-width: 100%;
|
|
164
|
+
height: auto;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.controls {
|
|
168
|
+
display: flex;
|
|
169
|
+
gap: 10px;
|
|
170
|
+
margin-top: 20px;
|
|
171
|
+
flex-wrap: wrap;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.option-group {
|
|
175
|
+
display: grid;
|
|
176
|
+
grid-template-columns: 1fr 1fr;
|
|
177
|
+
gap: 15px;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.loading {
|
|
181
|
+
display: inline-block;
|
|
182
|
+
width: 20px;
|
|
183
|
+
height: 20px;
|
|
184
|
+
border: 3px solid #f3f3f3;
|
|
185
|
+
border-top: 3px solid #667eea;
|
|
186
|
+
border-radius: 50%;
|
|
187
|
+
animation: spin 1s linear infinite;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
@keyframes spin {
|
|
191
|
+
0% { transform: rotate(0deg); }
|
|
192
|
+
100% { transform: rotate(360deg); }
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.supported-formats {
|
|
196
|
+
margin-top: 20px;
|
|
197
|
+
padding: 15px;
|
|
198
|
+
background: #e6fffa;
|
|
199
|
+
border-radius: 8px;
|
|
200
|
+
border-left: 4px solid #38a169;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.format-list {
|
|
204
|
+
display: grid;
|
|
205
|
+
grid-template-columns: repeat(2, 1fr);
|
|
206
|
+
gap: 10px;
|
|
207
|
+
margin-top: 10px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.format-item {
|
|
211
|
+
padding: 5px 10px;
|
|
212
|
+
background: #b2f5ea;
|
|
213
|
+
border-radius: 4px;
|
|
214
|
+
font-size: 0.9rem;
|
|
215
|
+
text-align: center;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
.examples {
|
|
219
|
+
margin-top: 30px;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
.examples-grid {
|
|
223
|
+
display: grid;
|
|
224
|
+
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
|
|
225
|
+
gap: 15px;
|
|
226
|
+
margin-top: 15px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.example-item {
|
|
230
|
+
padding: 15px;
|
|
231
|
+
background: white;
|
|
232
|
+
border-radius: 8px;
|
|
233
|
+
border: 2px solid #e2e8f0;
|
|
234
|
+
cursor: pointer;
|
|
235
|
+
transition: all 0.3s ease;
|
|
236
|
+
text-align: center;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.example-item:hover {
|
|
240
|
+
border-color: #667eea;
|
|
241
|
+
transform: translateY(-2px);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.example-text {
|
|
245
|
+
font-weight: 600;
|
|
246
|
+
color: #4a5568;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.example-desc {
|
|
250
|
+
font-size: 0.8rem;
|
|
251
|
+
color: #718096;
|
|
252
|
+
margin-top: 5px;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.hint {
|
|
256
|
+
font-size: 0.9rem;
|
|
257
|
+
color: #718096;
|
|
258
|
+
margin-top: 5px;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
footer {
|
|
262
|
+
text-align: center;
|
|
263
|
+
color: white;
|
|
264
|
+
margin-top: 40px;
|
|
265
|
+
opacity: 0.8;
|
|
266
|
+
}
|
|
267
|
+
</style>
|
|
268
|
+
<!-- 引入 jsbarcode 库 -->
|
|
269
|
+
<script src="https://cdn.jsdelivr.net/npm/jsbarcode@3.11.5/dist/JsBarcode.all.min.js"></script>
|
|
270
|
+
<!-- 引入 html2canvas 用于生成图片 -->
|
|
271
|
+
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
|
|
272
|
+
</head>
|
|
273
|
+
<body>
|
|
274
|
+
<div class="container">
|
|
275
|
+
<header>
|
|
276
|
+
<h1>📊 专业条形码生成器</h1>
|
|
277
|
+
<p class="subtitle">基于 jsbarcode 库,支持多种编码格式,微信可扫描</p>
|
|
278
|
+
<div class="lib-badge">使用 jsbarcode 3.11.5</div>
|
|
279
|
+
</header>
|
|
280
|
+
|
|
281
|
+
<div class="content">
|
|
282
|
+
<!-- 左侧:条形码生成 -->
|
|
283
|
+
<div class="card">
|
|
284
|
+
<h2 class="card-title">🔧 生成条形码</h2>
|
|
285
|
+
|
|
286
|
+
<div class="form-group">
|
|
287
|
+
<label for="inputText">条形码内容:</label>
|
|
288
|
+
<textarea id="inputText" placeholder="请输入条形码内容">123456789012</textarea>
|
|
289
|
+
<div class="hint">支持中文、英文、数字等</div>
|
|
290
|
+
</div>
|
|
291
|
+
|
|
292
|
+
<div class="option-group">
|
|
293
|
+
<div class="form-group">
|
|
294
|
+
<label for="barcodeType">编码格式:</label>
|
|
295
|
+
<select id="barcodeType">
|
|
296
|
+
<option value="CODE128" selected>CODE128</option>
|
|
297
|
+
<option value="EAN13">EAN13 (商品条码)</option>
|
|
298
|
+
<option value="EAN8">EAN8</option>
|
|
299
|
+
<option value="UPC">UPC</option>
|
|
300
|
+
<option value="CODE39">CODE39</option>
|
|
301
|
+
<option value="ITF14">ITF14</option>
|
|
302
|
+
<option value="MSI">MSI</option>
|
|
303
|
+
<option value="pharmacode">Pharmacode</option>
|
|
304
|
+
</select>
|
|
305
|
+
</div>
|
|
306
|
+
<div class="form-group">
|
|
307
|
+
<label for="lineColor">线条颜色:</label>
|
|
308
|
+
<input type="color" id="lineColor" value="#000000">
|
|
309
|
+
</div>
|
|
310
|
+
</div>
|
|
311
|
+
|
|
312
|
+
<div class="option-group">
|
|
313
|
+
<div class="form-group">
|
|
314
|
+
<label for="width">宽度:</label>
|
|
315
|
+
<input type="number" id="width" value="2" min="1" max="5" step="0.5">
|
|
316
|
+
</div>
|
|
317
|
+
<div class="form-group">
|
|
318
|
+
<label for="height">高度:</label>
|
|
319
|
+
<input type="number" id="height" value="100" min="20" max="200">
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
|
|
323
|
+
<div class="form-group">
|
|
324
|
+
<label>
|
|
325
|
+
<input type="checkbox" id="showText" checked> 显示文本
|
|
326
|
+
</label>
|
|
327
|
+
<label>
|
|
328
|
+
<input type="checkbox" id="showBackground" checked> 显示白色背景
|
|
329
|
+
</label>
|
|
330
|
+
</div>
|
|
331
|
+
|
|
332
|
+
<button id="generateBtn" class="btn btn-full">
|
|
333
|
+
<span id="generateText">生成条形码</span>
|
|
334
|
+
<span id="generateLoading" class="loading" style="display: none;"></span>
|
|
335
|
+
</button>
|
|
336
|
+
|
|
337
|
+
<div id="barcodeResult" class="result-area" style="display: none;">
|
|
338
|
+
<div class="result-title">生成的条形码:</div>
|
|
339
|
+
<div id="barcodeDisplay" class="barcode-container">
|
|
340
|
+
<!-- 条形码将在这里显示 -->
|
|
341
|
+
</div>
|
|
342
|
+
|
|
343
|
+
<div class="controls">
|
|
344
|
+
<button id="downloadBtn" class="btn">💾 下载PNG</button>
|
|
345
|
+
<button id="downloadSvgBtn" class="btn btn-secondary">📁 下载SVG</button>
|
|
346
|
+
<button id="copyBtn" class="btn">📋 复制图片</button>
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
<div class="supported-formats">
|
|
350
|
+
<div class="result-title">当前编码格式信息:</div>
|
|
351
|
+
<div id="formatInfo" style="margin: 10px 0;"></div>
|
|
352
|
+
</div>
|
|
353
|
+
</div>
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
<!-- 右侧:设置和选项 -->
|
|
357
|
+
<div class="card">
|
|
358
|
+
<h2 class="card-title">⚙️ 条形码设置</h2>
|
|
359
|
+
|
|
360
|
+
<div class="form-group">
|
|
361
|
+
<label for="fontSize">字体大小:</label>
|
|
362
|
+
<input type="number" id="fontSize" value="20" min="10" max="40">
|
|
363
|
+
</div>
|
|
364
|
+
|
|
365
|
+
<div class="form-group">
|
|
366
|
+
<label for="margin">边距:</label>
|
|
367
|
+
<input type="number" id="margin" value="10" min="0" max="50">
|
|
368
|
+
</div>
|
|
369
|
+
|
|
370
|
+
<div class="form-group">
|
|
371
|
+
<label for="background">背景色:</label>
|
|
372
|
+
<input type="color" id="background" value="#ffffff">
|
|
373
|
+
</div>
|
|
374
|
+
|
|
375
|
+
<div class="supported-formats">
|
|
376
|
+
<div class="result-title">支持的编码格式:</div>
|
|
377
|
+
<div class="format-list">
|
|
378
|
+
<div class="format-item">CODE128</div>
|
|
379
|
+
<div class="format-item">EAN13</div>
|
|
380
|
+
<div class="format-item">EAN8</div>
|
|
381
|
+
<div class="format-item">UPC</div>
|
|
382
|
+
<div class="format-item">CODE39</div>
|
|
383
|
+
<div class="format-item">ITF14</div>
|
|
384
|
+
<div class="format-item">MSI</div>
|
|
385
|
+
<div class="format-item">Pharmacode</div>
|
|
386
|
+
</div>
|
|
387
|
+
</div>
|
|
388
|
+
|
|
389
|
+
<div class="examples">
|
|
390
|
+
<div class="result-title">常用示例:</div>
|
|
391
|
+
<div class="examples-grid">
|
|
392
|
+
<div class="example-item" data-text="123456789012" data-type="EAN13">
|
|
393
|
+
<div class="example-text">123456789012</div>
|
|
394
|
+
<div class="example-desc">EAN13 商品码</div>
|
|
395
|
+
</div>
|
|
396
|
+
<div class="example-item" data-text="PRODUCT-001" data-type="CODE128">
|
|
397
|
+
<div class="example-text">PRODUCT-001</div>
|
|
398
|
+
<div class="example-desc">产品编码</div>
|
|
399
|
+
</div>
|
|
400
|
+
<div class="example-item" data-text="12345678" data-type="EAN8">
|
|
401
|
+
<div class="example-text">12345678</div>
|
|
402
|
+
<div class="example-desc">EAN8 短码</div>
|
|
403
|
+
</div>
|
|
404
|
+
<div class="example-item" data-text="微信扫码测试" data-type="CODE128">
|
|
405
|
+
<div class="example-text">微信扫码测试</div>
|
|
406
|
+
<div class="example-desc">中文内容</div>
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
|
|
413
|
+
<!-- Web Component 示例 -->
|
|
414
|
+
<div class="card">
|
|
415
|
+
<h2 class="card-title">🎯 代码示例</h2>
|
|
416
|
+
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
|
|
417
|
+
<div>
|
|
418
|
+
<h3>JavaScript 使用:</h3>
|
|
419
|
+
<pre style="background: #f6f8fa; padding: 15px; border-radius: 8px; overflow: auto; font-size: 0.9rem;">
|
|
420
|
+
// 1. 直接使用
|
|
421
|
+
JsBarcode("#barcode", "123456789012", {
|
|
422
|
+
format: "CODE128",
|
|
423
|
+
width: 2,
|
|
424
|
+
height: 100,
|
|
425
|
+
displayValue: true
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// 2. 生成图片
|
|
429
|
+
async function generateBarcodeImage(text, options) {
|
|
430
|
+
const svg = JsBarcode.getSVG(text, options);
|
|
431
|
+
// 转换为PNG
|
|
432
|
+
return await svgToPng(svg);
|
|
433
|
+
}
|
|
434
|
+
</pre>
|
|
435
|
+
</div>
|
|
436
|
+
<div>
|
|
437
|
+
<h3>HTML 使用:</h3>
|
|
438
|
+
<pre style="background: #f6f8fa; padding: 15px; border-radius: 8px; overflow: auto; font-size: 0.9rem;">
|
|
439
|
+
<!-- 直接生成 -->
|
|
440
|
+
<svg id="barcode"></svg>
|
|
441
|
+
|
|
442
|
+
<script>
|
|
443
|
+
JsBarcode("#barcode", "123456789012");
|
|
444
|
+
</script>
|
|
445
|
+
|
|
446
|
+
<!-- 使用img标签 -->
|
|
447
|
+
<img id="barcode" src="barcode.png"/>
|
|
448
|
+
|
|
449
|
+
<script>
|
|
450
|
+
JsBarcode("#barcode", "123456789012");
|
|
451
|
+
</script>
|
|
452
|
+
</pre>
|
|
453
|
+
</div>
|
|
454
|
+
</div>
|
|
455
|
+
</div>
|
|
456
|
+
|
|
457
|
+
<!-- 测试区域 -->
|
|
458
|
+
<div class="card">
|
|
459
|
+
<h2 class="card-title">🧪 实时测试</h2>
|
|
460
|
+
<div style="display: flex; gap: 20px; flex-wrap: wrap; justify-content: center;">
|
|
461
|
+
<div style="flex: 1; min-width: 300px;">
|
|
462
|
+
<h3>生成测试:</h3>
|
|
463
|
+
<input type="text" id="testInput" value="TEST-123456" style="margin-bottom: 10px;">
|
|
464
|
+
<button id="testBtn" class="btn">快速生成</button>
|
|
465
|
+
<div id="testResult" style="margin-top: 20px;"></div>
|
|
466
|
+
</div>
|
|
467
|
+
<div style="flex: 1; min-width: 300px;">
|
|
468
|
+
<h3>微信扫描测试:</h3>
|
|
469
|
+
<div style="background: #f0f9ff; padding: 20px; border-radius: 8px; text-align: center;">
|
|
470
|
+
<p>📱 用微信扫描右侧生成的条形码</p>
|
|
471
|
+
<p style="font-size: 0.9rem; color: #666; margin-top: 10px;">
|
|
472
|
+
✅ 确保包含静区<br>
|
|
473
|
+
✅ 确保对比度足够<br>
|
|
474
|
+
✅ 确保大小合适
|
|
475
|
+
</p>
|
|
476
|
+
</div>
|
|
477
|
+
</div>
|
|
478
|
+
</div>
|
|
479
|
+
</div>
|
|
480
|
+
|
|
481
|
+
<footer>
|
|
482
|
+
<p>© 2024 条形码生成器 | 基于 jsbarcode 库 | 支持多种编码格式</p>
|
|
483
|
+
<p style="margin-top: 10px; font-size: 0.9rem;">https://www.npmjs.com/package/jsbarcode</p>
|
|
484
|
+
</footer>
|
|
485
|
+
</div>
|
|
486
|
+
|
|
487
|
+
<script>
|
|
488
|
+
// 初始化
|
|
489
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
490
|
+
// DOM元素
|
|
491
|
+
const inputText = document.getElementById('inputText');
|
|
492
|
+
const barcodeType = document.getElementById('barcodeType');
|
|
493
|
+
const lineColor = document.getElementById('lineColor');
|
|
494
|
+
const width = document.getElementById('width');
|
|
495
|
+
const height = document.getElementById('height');
|
|
496
|
+
const fontSize = document.getElementById('fontSize');
|
|
497
|
+
const margin = document.getElementById('margin');
|
|
498
|
+
const background = document.getElementById('background');
|
|
499
|
+
const showText = document.getElementById('showText');
|
|
500
|
+
const showBackground = document.getElementById('showBackground');
|
|
501
|
+
const generateBtn = document.getElementById('generateBtn');
|
|
502
|
+
const generateLoading = document.getElementById('generateLoading');
|
|
503
|
+
const generateText = document.getElementById('generateText');
|
|
504
|
+
const barcodeResult = document.getElementById('barcodeResult');
|
|
505
|
+
const barcodeDisplay = document.getElementById('barcodeDisplay');
|
|
506
|
+
const downloadBtn = document.getElementById('downloadBtn');
|
|
507
|
+
const downloadSvgBtn = document.getElementById('downloadSvgBtn');
|
|
508
|
+
const copyBtn = document.getElementById('copyBtn');
|
|
509
|
+
const formatInfo = document.getElementById('formatInfo');
|
|
510
|
+
const testInput = document.getElementById('testInput');
|
|
511
|
+
const testBtn = document.getElementById('testBtn');
|
|
512
|
+
const testResult = document.getElementById('testResult');
|
|
513
|
+
|
|
514
|
+
let currentSvg = null;
|
|
515
|
+
let currentOptions = {};
|
|
516
|
+
|
|
517
|
+
// 更新格式信息
|
|
518
|
+
function updateFormatInfo(type) {
|
|
519
|
+
const formatInfoMap = {
|
|
520
|
+
'CODE128': '通用编码,支持所有ASCII字符',
|
|
521
|
+
'EAN13': '国际商品条码,13位数字',
|
|
522
|
+
'EAN8': '短商品条码,8位数字',
|
|
523
|
+
'UPC': '北美商品条码,12位数字',
|
|
524
|
+
'CODE39': '字母数字编码,支持A-Z,0-9',
|
|
525
|
+
'ITF14': '物流包装编码,14位数字',
|
|
526
|
+
'MSI': '库存管理编码',
|
|
527
|
+
'pharmacode': '药品编码'
|
|
528
|
+
};
|
|
529
|
+
|
|
530
|
+
formatInfo.innerHTML = `
|
|
531
|
+
<strong>${type}</strong>: ${formatInfoMap[type] || '通用编码'}
|
|
532
|
+
`;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
// 生成条形码
|
|
536
|
+
function generateBarcode() {
|
|
537
|
+
const text = inputText.value.trim();
|
|
538
|
+
if (!text) {
|
|
539
|
+
alert('请输入条形码内容');
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const options = {
|
|
544
|
+
format: barcodeType.value,
|
|
545
|
+
width: parseFloat(width.value),
|
|
546
|
+
height: parseInt(height.value),
|
|
547
|
+
lineColor: lineColor.value,
|
|
548
|
+
background: showBackground.checked ? background.value : 'transparent',
|
|
549
|
+
displayValue: showText.checked,
|
|
550
|
+
fontSize: parseInt(fontSize.value),
|
|
551
|
+
margin: parseInt(margin.value),
|
|
552
|
+
valid: function(valid) {
|
|
553
|
+
if (!valid) {
|
|
554
|
+
console.warn('条形码内容可能不符合格式要求');
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
|
|
559
|
+
currentOptions = options;
|
|
560
|
+
|
|
561
|
+
// 清除之前的内容
|
|
562
|
+
barcodeDisplay.innerHTML = '';
|
|
563
|
+
|
|
564
|
+
// 创建SVG元素
|
|
565
|
+
const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
|
566
|
+
svg.id = "dynamicBarcode";
|
|
567
|
+
barcodeDisplay.appendChild(svg);
|
|
568
|
+
|
|
569
|
+
try {
|
|
570
|
+
// 生成条形码
|
|
571
|
+
JsBarcode("#dynamicBarcode", text, options);
|
|
572
|
+
|
|
573
|
+
// 保存SVG
|
|
574
|
+
currentSvg = svg.outerHTML;
|
|
575
|
+
|
|
576
|
+
// 显示结果
|
|
577
|
+
barcodeResult.style.display = 'block';
|
|
578
|
+
|
|
579
|
+
// 更新格式信息
|
|
580
|
+
updateFormatInfo(options.format);
|
|
581
|
+
|
|
582
|
+
} catch (error) {
|
|
583
|
+
alert('生成条形码失败: ' + error.message);
|
|
584
|
+
console.error(error);
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// SVG转PNG
|
|
589
|
+
async function svgToPng(svgString) {
|
|
590
|
+
return new Promise((resolve, reject) => {
|
|
591
|
+
const svgBlob = new Blob([svgString], {type: 'image/svg+xml;charset=utf-8'});
|
|
592
|
+
const url = URL.createObjectURL(svgBlob);
|
|
593
|
+
const img = new Image();
|
|
594
|
+
|
|
595
|
+
img.onload = function() {
|
|
596
|
+
const canvas = document.createElement('canvas');
|
|
597
|
+
canvas.width = img.width;
|
|
598
|
+
canvas.height = img.height;
|
|
599
|
+
const ctx = canvas.getContext('2d');
|
|
600
|
+
|
|
601
|
+
// 设置背景
|
|
602
|
+
if (currentOptions.background !== 'transparent') {
|
|
603
|
+
ctx.fillStyle = currentOptions.background;
|
|
604
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
ctx.drawImage(img, 0, 0);
|
|
608
|
+
|
|
609
|
+
canvas.toBlob(function(blob) {
|
|
610
|
+
URL.revokeObjectURL(url);
|
|
611
|
+
resolve(blob);
|
|
612
|
+
}, 'image/png');
|
|
613
|
+
};
|
|
614
|
+
|
|
615
|
+
img.onerror = reject;
|
|
616
|
+
img.src = url;
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
// 下载PNG
|
|
621
|
+
async function downloadPng() {
|
|
622
|
+
if (!currentSvg) {
|
|
623
|
+
alert('请先生成条形码');
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
try {
|
|
628
|
+
const blob = await svgToPng(currentSvg);
|
|
629
|
+
const url = URL.createObjectURL(blob);
|
|
630
|
+
const a = document.createElement('a');
|
|
631
|
+
a.href = url;
|
|
632
|
+
a.download = `barcode_${Date.now()}.png`;
|
|
633
|
+
document.body.appendChild(a);
|
|
634
|
+
a.click();
|
|
635
|
+
document.body.removeChild(a);
|
|
636
|
+
URL.revokeObjectURL(url);
|
|
637
|
+
} catch (error) {
|
|
638
|
+
alert('下载失败: ' + error.message);
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// 下载SVG
|
|
643
|
+
function downloadSvg() {
|
|
644
|
+
if (!currentSvg) {
|
|
645
|
+
alert('请先生成条形码');
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
const blob = new Blob([currentSvg], {type: 'image/svg+xml'});
|
|
650
|
+
const url = URL.createObjectURL(blob);
|
|
651
|
+
const a = document.createElement('a');
|
|
652
|
+
a.href = url;
|
|
653
|
+
a.download = `barcode_${Date.now()}.svg`;
|
|
654
|
+
document.body.appendChild(a);
|
|
655
|
+
a.click();
|
|
656
|
+
document.body.removeChild(a);
|
|
657
|
+
URL.revokeObjectURL(url);
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
// 复制到剪贴板
|
|
661
|
+
async function copyToClipboard() {
|
|
662
|
+
if (!currentSvg) {
|
|
663
|
+
alert('请先生成条形码');
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
try {
|
|
668
|
+
const blob = await svgToPng(currentSvg);
|
|
669
|
+
const item = new ClipboardItem({
|
|
670
|
+
'image/png': blob
|
|
671
|
+
});
|
|
672
|
+
await navigator.clipboard.write([item]);
|
|
673
|
+
alert('条形码已复制到剪贴板');
|
|
674
|
+
} catch (error) {
|
|
675
|
+
console.error('复制失败:', error);
|
|
676
|
+
alert('复制失败,请尝试下载功能');
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// 事件监听
|
|
681
|
+
generateBtn.addEventListener('click', function() {
|
|
682
|
+
generateText.style.display = 'none';
|
|
683
|
+
generateLoading.style.display = 'inline-block';
|
|
684
|
+
|
|
685
|
+
setTimeout(() => {
|
|
686
|
+
generateBarcode();
|
|
687
|
+
generateText.style.display = 'inline-block';
|
|
688
|
+
generateLoading.style.display = 'none';
|
|
689
|
+
}, 100);
|
|
690
|
+
});
|
|
691
|
+
|
|
692
|
+
downloadBtn.addEventListener('click', downloadPng);
|
|
693
|
+
downloadSvgBtn.addEventListener('click', downloadSvg);
|
|
694
|
+
copyBtn.addEventListener('click', copyToClipboard);
|
|
695
|
+
|
|
696
|
+
// 示例点击
|
|
697
|
+
document.querySelectorAll('.example-item').forEach(item => {
|
|
698
|
+
item.addEventListener('click', function() {
|
|
699
|
+
inputText.value = this.dataset.text;
|
|
700
|
+
barcodeType.value = this.dataset.type || 'CODE128';
|
|
701
|
+
generateBarcode();
|
|
702
|
+
});
|
|
703
|
+
});
|
|
704
|
+
|
|
705
|
+
// 测试按钮
|
|
706
|
+
testBtn.addEventListener('click', function() {
|
|
707
|
+
const text = testInput.value.trim();
|
|
708
|
+
if (!text) {
|
|
709
|
+
alert('请输入测试内容');
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
testResult.innerHTML = `
|
|
714
|
+
<div style="text-align: center;">
|
|
715
|
+
<svg id="testBarcode" style="max-width: 100%;"></svg>
|
|
716
|
+
<p style="margin-top: 10px; font-size: 0.9rem;">测试内容: ${text}</p>
|
|
717
|
+
</div>
|
|
718
|
+
`;
|
|
719
|
+
|
|
720
|
+
setTimeout(() => {
|
|
721
|
+
try {
|
|
722
|
+
JsBarcode("#testBarcode", text, {
|
|
723
|
+
format: "CODE128",
|
|
724
|
+
width: 2,
|
|
725
|
+
height: 60,
|
|
726
|
+
displayValue: true,
|
|
727
|
+
fontSize: 16
|
|
728
|
+
});
|
|
729
|
+
} catch (error) {
|
|
730
|
+
testResult.innerHTML = `<p style="color: red;">生成失败: ${error.message}</p>`;
|
|
731
|
+
}
|
|
732
|
+
}, 100);
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
// 格式变化时更新信息
|
|
736
|
+
barcodeType.addEventListener('change', function() {
|
|
737
|
+
updateFormatInfo(this.value);
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
// 初始生成
|
|
741
|
+
setTimeout(() => {
|
|
742
|
+
generateBarcode();
|
|
743
|
+
}, 500);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
// 工具函数
|
|
747
|
+
function str2png(text, options = {}) {
|
|
748
|
+
return new Promise((resolve, reject) => {
|
|
749
|
+
try {
|
|
750
|
+
const svg = JsBarcode.getSVG(text, {
|
|
751
|
+
format: options.format || 'CODE128',
|
|
752
|
+
width: options.width || 2,
|
|
753
|
+
height: options.height || 100,
|
|
754
|
+
lineColor: options.lineColor || '#000000',
|
|
755
|
+
background: options.background || '#FFFFFF',
|
|
756
|
+
displayValue: options.displayValue !== false,
|
|
757
|
+
fontSize: options.fontSize || 20,
|
|
758
|
+
margin: options.margin || 10
|
|
759
|
+
});
|
|
760
|
+
|
|
761
|
+
const svgBlob = new Blob([svg], {type: 'image/svg+xml;charset=utf-8'});
|
|
762
|
+
const url = URL.createObjectURL(svgBlob);
|
|
763
|
+
const img = new Image();
|
|
764
|
+
|
|
765
|
+
img.onload = function() {
|
|
766
|
+
const canvas = document.createElement('canvas');
|
|
767
|
+
canvas.width = img.width;
|
|
768
|
+
canvas.height = img.height;
|
|
769
|
+
const ctx = canvas.getContext('2d');
|
|
770
|
+
|
|
771
|
+
ctx.fillStyle = options.background || '#FFFFFF';
|
|
772
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
773
|
+
ctx.drawImage(img, 0, 0);
|
|
774
|
+
|
|
775
|
+
canvas.toBlob(function(blob) {
|
|
776
|
+
URL.revokeObjectURL(url);
|
|
777
|
+
const reader = new FileReader();
|
|
778
|
+
reader.onloadend = function() {
|
|
779
|
+
resolve(reader.result);
|
|
780
|
+
};
|
|
781
|
+
reader.readAsDataURL(blob);
|
|
782
|
+
}, 'image/png');
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
img.onerror = reject;
|
|
786
|
+
img.src = url;
|
|
787
|
+
} catch (error) {
|
|
788
|
+
reject(error);
|
|
789
|
+
}
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
async function png2str(pngData) {
|
|
794
|
+
// 注意:jsbarcode 不支持从图片解码
|
|
795
|
+
// 这是一个占位符实现
|
|
796
|
+
return new Promise((resolve) => {
|
|
797
|
+
setTimeout(() => {
|
|
798
|
+
resolve("解码结果: jsbarcode 不支持从图片解码,建议使用专业的解码库如 quaggaJS 或 zxing");
|
|
799
|
+
}, 500);
|
|
800
|
+
});
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
// Web Component
|
|
804
|
+
class JsBarcodeButton extends HTMLElement {
|
|
805
|
+
constructor() {
|
|
806
|
+
super();
|
|
807
|
+
this.attachShadow({ mode: 'open' });
|
|
808
|
+
this.render();
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
static get observedAttributes() {
|
|
812
|
+
return ['text', 'format', 'width', 'height'];
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
attributeChangedCallback() {
|
|
816
|
+
this.render();
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
connectedCallback() {
|
|
820
|
+
this.addEventListener('click', this.handleClick.bind(this));
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
async handleClick() {
|
|
824
|
+
const text = this.getAttribute('text') || '';
|
|
825
|
+
if (!text) {
|
|
826
|
+
alert('请设置 text 属性');
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
try {
|
|
831
|
+
const pngData = await str2png(text, {
|
|
832
|
+
format: this.getAttribute('format') || 'CODE128',
|
|
833
|
+
width: parseFloat(this.getAttribute('width')) || 2,
|
|
834
|
+
height: parseInt(this.getAttribute('height')) || 100
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
this.showBarcode(pngData, text);
|
|
838
|
+
} catch (error) {
|
|
839
|
+
alert('生成失败: ' + error.message);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
showBarcode(pngData, text) {
|
|
844
|
+
const overlay = document.createElement('div');
|
|
845
|
+
overlay.style.cssText = `
|
|
846
|
+
position: fixed;
|
|
847
|
+
top: 0;
|
|
848
|
+
left: 0;
|
|
849
|
+
right: 0;
|
|
850
|
+
bottom: 0;
|
|
851
|
+
background: rgba(0,0,0,0.5);
|
|
852
|
+
display: flex;
|
|
853
|
+
align-items: center;
|
|
854
|
+
justify-content: center;
|
|
855
|
+
z-index: 10000;
|
|
856
|
+
`;
|
|
857
|
+
|
|
858
|
+
const popup = document.createElement('div');
|
|
859
|
+
popup.style.cssText = `
|
|
860
|
+
background: white;
|
|
861
|
+
padding: 30px;
|
|
862
|
+
border-radius: 10px;
|
|
863
|
+
text-align: center;
|
|
864
|
+
max-width: 90%;
|
|
865
|
+
max-height: 90%;
|
|
866
|
+
`;
|
|
867
|
+
|
|
868
|
+
const img = document.createElement('img');
|
|
869
|
+
img.src = pngData;
|
|
870
|
+
img.style.cssText = 'max-width: 300px; max-height: 200px;';
|
|
871
|
+
img.alt = text;
|
|
872
|
+
|
|
873
|
+
const closeBtn = document.createElement('button');
|
|
874
|
+
closeBtn.textContent = '关闭';
|
|
875
|
+
closeBtn.style.cssText = `
|
|
876
|
+
margin-top: 20px;
|
|
877
|
+
padding: 10px 30px;
|
|
878
|
+
background: #667eea;
|
|
879
|
+
color: white;
|
|
880
|
+
border: none;
|
|
881
|
+
border-radius: 5px;
|
|
882
|
+
cursor: pointer;
|
|
883
|
+
`;
|
|
884
|
+
closeBtn.onclick = () => overlay.remove();
|
|
885
|
+
|
|
886
|
+
popup.appendChild(img);
|
|
887
|
+
popup.appendChild(document.createElement('br'));
|
|
888
|
+
popup.appendChild(closeBtn);
|
|
889
|
+
overlay.appendChild(popup);
|
|
890
|
+
document.body.appendChild(overlay);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
render() {
|
|
894
|
+
const text = this.getAttribute('text') || '生成条形码';
|
|
895
|
+
const width = this.getAttribute('width') || '150px';
|
|
896
|
+
const height = this.getAttribute('height') || '40px';
|
|
897
|
+
|
|
898
|
+
this.shadowRoot.innerHTML = `
|
|
899
|
+
<style>
|
|
900
|
+
button {
|
|
901
|
+
width: ${width};
|
|
902
|
+
height: ${height};
|
|
903
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
904
|
+
color: white;
|
|
905
|
+
border: none;
|
|
906
|
+
border-radius: 5px;
|
|
907
|
+
cursor: pointer;
|
|
908
|
+
font-weight: 600;
|
|
909
|
+
}
|
|
910
|
+
button:hover {
|
|
911
|
+
opacity: 0.9;
|
|
912
|
+
}
|
|
913
|
+
</style>
|
|
914
|
+
<button>
|
|
915
|
+
<slot>${text}</slot>
|
|
916
|
+
</button>
|
|
917
|
+
`;
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
// 注册Web Component
|
|
922
|
+
customElements.define('jsbarcode-button', JsBarcodeButton);
|
|
923
|
+
|
|
924
|
+
console.log('jsbarcode 条形码生成器已加载');
|
|
925
|
+
console.log('支持格式: CODE128, EAN13, EAN8, UPC, CODE39, ITF14, MSI, Pharmacode');
|
|
926
|
+
</script>
|
|
927
|
+
|
|
928
|
+
<!-- Web Component 使用示例 -->
|
|
929
|
+
<script>
|
|
930
|
+
// 添加一些Web Component到页面
|
|
931
|
+
document.addEventListener('DOMContentLoaded', function() {
|
|
932
|
+
const demoArea = document.querySelector('.container');
|
|
933
|
+
const demoHtml = `
|
|
934
|
+
<div style="margin-top: 30px;">
|
|
935
|
+
<h3>Web Component 示例:</h3>
|
|
936
|
+
<div style="display: flex; gap: 15px; margin-top: 15px; flex-wrap: wrap;">
|
|
937
|
+
<jsbarcode-button text="TEST-001" width="150px">测试1</jsbarcode-button>
|
|
938
|
+
<jsbarcode-button text="123456789012" format="EAN13" width="150px">商品码</jsbarcode-button>
|
|
939
|
+
<jsbarcode-button text="微信扫码" width="150px">中文</jsbarcode-button>
|
|
940
|
+
</div>
|
|
941
|
+
</div>
|
|
942
|
+
`;
|
|
943
|
+
|
|
944
|
+
const tempDiv = document.createElement('div');
|
|
945
|
+
tempDiv.innerHTML = demoHtml;
|
|
946
|
+
demoArea.appendChild(tempDiv);
|
|
947
|
+
});
|
|
948
|
+
</script>
|
|
949
|
+
</body>
|
|
950
|
+
</html>
|