vue3-components-plus 3.0.10

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/README.md ADDED
@@ -0,0 +1,1022 @@
1
+ # vue3-components-plus 组件库
2
+
3
+ ## 简介
4
+
5
+ vue3-components-plus 是一个功能丰富的 Vue 3 企业级组件库,提供办公文档预览、动态表单、视频播放、权限控制等完整解决方案。
6
+
7
+ 组件使用示例参考 `dist/ComponentDemo`
8
+
9
+ ## 📸 部分组件预览
10
+
11
+ ### NsVideo
12
+
13
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db61dbffe264705f9b033)
14
+
15
+ ### NsDialog
16
+
17
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db64084aa6b1f690b64aa)
18
+
19
+ ### NsForm
20
+
21
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db6559c0db14c9eab014d)
22
+
23
+ ### NsOffice
24
+
25
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db66d8dbb075444370b09)
26
+
27
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db68829cd2a22227ba9e0)
28
+
29
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db698af380f3b56b06c4b)
30
+
31
+ ### NsMD
32
+
33
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db6c1c5602355134e07c1)
34
+
35
+ ### 自定义指令集
36
+
37
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db6aa15bee62062d24bcb)
38
+
39
+ ### 浸润线
40
+
41
+ ![emh1eWluZw==](https://tc-cdn.processon.com/po/605c2da663768970077b1422-695db6d88dbb075444370b13)
42
+
43
+ ## 📊 功能特性总结
44
+
45
+ ### 组件功能
46
+
47
+ - ✅ **NsOffice**: 办公文档统一预览(Excel/PDF/Word)
48
+ - ✅ **NsForm**: 动态表单生成和管理
49
+ - ✅ **NsVideo**: 专业视频播放器
50
+ - ✅ **NsDialog**: 灵活弹窗对话框
51
+ - ✅ **NsPdf**: PDF文档预览和搜索
52
+ - ✅ **NsExcel**: Excel预览和编辑
53
+ - ✅ **NsWord**: Word文档预览
54
+ - ✅ **NsImage**: 图片预览
55
+ - ✅ **NsMD**: Markdown编辑器
56
+ - ✅ **NsSaturationline**: 浸润线
57
+ - ✅ **NsAutoScreen**: 自适应屏幕工具
58
+
59
+ ### 指令功能
60
+
61
+ - ✅ **v-permission**: 按钮权限控制
62
+ - ✅ **v-length**: 输入长度和格式限制
63
+ - ✅ **v-sline**: 单行文本省略
64
+ - ✅ **v-event-unuse/use**: 事件穿透控制
65
+
66
+ ### 工具函数
67
+
68
+ - ✅ **HTTP请求**: 完整的RESTful API封装
69
+ - ✅ **资源加载**: 动态JS/CSS资源管理
70
+ - ✅ **表格排序**: 表格排序功能
71
+ - ✅ **SM2加密**: 国密算法加密
72
+ - ✅ **CSS变量**: 主题样式管理
73
+ - ✅ **通用工具**: 常用工具函数
74
+
75
+
76
+ ## 创建公共组件库步骤
77
+
78
+ - npm create vue@latest
79
+ - 主目录:创建packages(任意文件夹), 创建全局导出文件index.ts
80
+
81
+ ```typescript
82
+ // 主index.ts
83
+ import NsXX from './packages/NsXX/index.ts'
84
+ const components = { NsXX, 其他公共组件 }
85
+ const NsComponents = {
86
+ install: (app: App)=> {
87
+ Object.Keys(components).forEach((compName)=>{
88
+ app.component(compName, components[compName])
89
+ })
90
+ }
91
+ }
92
+ // 按需导出
93
+ export {
94
+ NsXX,
95
+ 其他公共组件
96
+ }
97
+ // 全局导入
98
+ export default NsComponents
99
+ ```
100
+
101
+ - 子目录:NsXX目录,创建独立导出index.ts
102
+
103
+ ```typescript
104
+ // 子index.ts:
105
+ import NsXX from './comps/index.ts'
106
+ // 按需导出
107
+ NsXX.install = (app)=>{
108
+ app.component(NsXX.name, NsXX)
109
+ }
110
+ // 导出子组件
111
+ export default NsXX
112
+ ```
113
+
114
+ - 配置package.json
115
+
116
+ ```json
117
+ {
118
+ "name": "vue3-components-plus",
119
+ "version": "2.0.100",
120
+ "private": false,
121
+ "type": "module",
122
+ "files": [
123
+ "dist"
124
+ ],
125
+ "main": "./dist/vue3-components-plus.umd.cjs",
126
+ "module": "./dist/vue3-components-plus.js",
127
+ "exports": {
128
+ "./dist/vue3-components-plus.css": "./dist/vue3-components-plus.css",
129
+ "./css": "./dist/vue3-components-plus.css",
130
+ ".": {
131
+ "import": "./dist/vue3-components-plus.js",
132
+ "require": "./dist/vue3-components-plus.umd.cjs"
133
+ }
134
+ },
135
+ "publishConfig": {
136
+ "registry": "http://199.10.9.178:8081/repository/npm-hosted/"
137
+ }
138
+ }
139
+ ```
140
+
141
+ - 配置vite.config.ts
142
+
143
+ ```typescript
144
+ build: {
145
+ outDir: "dist",
146
+ lib: {
147
+ // 指定入口主文件
148
+ entry: fileURLToPath(new URL("./pacakges/index.ts"), import.meta.url),
149
+ // 组件库导出后可以使用的全局变量
150
+ name: 'MatrixComponents',
151
+ // 不指定为package.json的name属性
152
+ fileName: 'vue3-components-plus',
153
+ },
154
+ rollupOptions: {
155
+ // 使用外部依赖(打包时删除的包,避免打入到组件库中)
156
+ external: ["vue"],
157
+ output: {
158
+ // 主index.ts导出多个module时需要指定"named"否则报警告,默认为"default"
159
+ exports: 'named',
160
+ // 配合external: ["vue"], 使用外部项目的变量映射
161
+ globals: {
162
+ vue: 'Vue',
163
+ },
164
+ }
165
+ },
166
+ // 【可选】压缩方式,viet3+需安装pnpm i terser -D
167
+ minify: 'terser',
168
+ terserOptions: {
169
+ compress: {
170
+ drop_console: true,
171
+ drop_debugger: true,
172
+ },
173
+ format: {
174
+ comments: false,
175
+ },
176
+ },
177
+ }
178
+ ```
179
+
180
+ - 打包
181
+
182
+ ```bash
183
+ npm run build
184
+ ```
185
+
186
+ - 当前项目main.ts使用
187
+
188
+ ```typescript
189
+ import NsComponents from '../dist/vue3-components-plus.js'
190
+ // 按需引入
191
+ // import {NsXX} from '../dist/vue3-components-plus,js'
192
+ ...
193
+ app.use(NsComponents)
194
+ // 按需引入
195
+ // app.use(NsXX)
196
+ ```
197
+
198
+ - 当前项目Test.vue使用
199
+
200
+ ```vue
201
+ <template>
202
+ <NsXX />
203
+ </template>
204
+ ```
205
+
206
+ ## 使用公共组件库
207
+
208
+ ```bash
209
+ # 1. 引入组件库
210
+ pnpm i element-plus
211
+ pnpm i vue3-components-plus -S --registry=http://199.10.9.178:8081/repository/npm-group/
212
+ # 安装失败:pnpm i vue3-components-plus --registry=http://199.10.9.178:8081/repository/npm-hosted/
213
+
214
+ # 非初始化安装
215
+ pnpm i -S --registry=http://199.10.9.178:8081/repository/npm-group/
216
+ ```
217
+
218
+ ```typescript
219
+ // 2. main.ts中引入
220
+ // 安装 Element-Plus
221
+ import 'element-plus/dist/index.css'
222
+ import ElementPlus from 'element-plus'
223
+ import zhCn from 'element-plus/es/locale/lang/zh-cn'
224
+ app.use(ElementPlus, {
225
+ locale: zhCn,
226
+ })
227
+ // 安装组件库(ts需要//@ts-ignore)
228
+ //@ts-ignore
229
+ import NsComponents from 'vue3-components-plus'
230
+ import 'vue3-components-plus/dist/vue3-components-plus.css'
231
+ app.use(NsComponents)
232
+ ```
233
+
234
+ ## 📋 组件列表
235
+
236
+ ### 1. NsOffice - 办公文档统一预览组件
237
+
238
+ 支持格式:Excel(.xlsx/.xls)、PDF(.pdf)、Word(.docx/.doc)
239
+
240
+ ```vue
241
+ <template>
242
+ <!-- 基础使用 -->
243
+ <NsOffice :url="fileUrl" />
244
+
245
+ <!-- Excel编辑模式 -->
246
+ <NsOffice :url="excelUrl" :isEdit="true" />
247
+
248
+ <!-- 获取组件引用 -->
249
+ <NsOffice ref="officeRef" :url="fileUrl" />
250
+ </template>
251
+
252
+ <script setup>
253
+ import { ref } from 'vue'
254
+ import { NsOffice } from 'vue3-components-plus'
255
+
256
+ const officeRef = ref()
257
+
258
+ // 获取文件类型
259
+ const fileType = officeRef.value?.getFileType() // 'excel' | 'pdf' | 'word' | 'unsupported'
260
+
261
+ // 获取当前激活的组件实例
262
+ const activeComponent = officeRef.value?.getActiveComponent()
263
+
264
+ // 刷新组件
265
+ officeRef.value?.refresh()
266
+ </script>
267
+ ```
268
+
269
+ ### 2. NsForm - 动态表单组件
270
+
271
+ ```vue
272
+ <template>
273
+ <NsForm :rows="formConfig" ref="formRef" />
274
+ </template>
275
+
276
+ <script setup>
277
+ import { ref } from 'vue'
278
+ import { NsForm } from 'vue3-components-plus'
279
+
280
+ const formRef = ref()
281
+ const formConfig = [
282
+ {
283
+ key: 'name',
284
+ label: '姓名',
285
+ component: 'el-input',
286
+ props: { placeholder: '请输入姓名' }
287
+ },
288
+ {
289
+ key: 'age',
290
+ label: '年龄',
291
+ component: 'el-input-number',
292
+ props: { min: 0, max: 100 }
293
+ }
294
+ ]
295
+
296
+ // 获取表单数据
297
+ const formData = formRef.value?.getFormData()
298
+
299
+ // 重置表单
300
+ formRef.value?.resetForm()
301
+
302
+ // 验证表单
303
+ const isValid = formRef.value?.validate()
304
+ </script>
305
+ ```
306
+
307
+ ### 3. NsVideo - 视频播放组件
308
+
309
+ ```vue
310
+ <template>
311
+ <NsVideo
312
+ ref="nsVideoRef"
313
+ v-bind="videoData"
314
+ v-on="videoEvent"
315
+ @changeSplit='changeSplitHandler'
316
+ >
317
+ <!-- 自定义插槽 -->
318
+ <template #video-tree><span>左侧树-自定义插槽</span></template>
319
+ <template #video-player-head><span>播放区域头部-自定义插槽</span></template>
320
+ <template #video-player-view><span>播放区域主体-自定义插槽</span></template>
321
+ <template #video-player-foot><span>播放区域底部控制按钮-自定义插槽</span></template>
322
+ <template #video-player-cover><span>播放器canvas画布区域(除head+foot+tree区域)</span></template>
323
+ </NsVideo>
324
+ </template>
325
+
326
+ <script setup>
327
+ import { ref } from 'vue'
328
+ import { NsVideo } from 'vue3-components-plus'
329
+
330
+ const nsVideoRef = ref()
331
+
332
+ // 视频配置数据
333
+ const videoData = {
334
+ // 显示视频关闭按钮
335
+ showClose: true,
336
+ // 是否支持全屏
337
+ hasFullScreen: true,
338
+ // 显示树
339
+ showTree: true,
340
+ // 树数据
341
+ treeData: [
342
+ {
343
+ id: '1',
344
+ label: '分组1',
345
+ children: [
346
+ {
347
+ videoModel: 'easyplayer',
348
+ id: '111',
349
+ label: '视频A',
350
+ url: 'ws://example.com/rtp/video.live.flv',
351
+ deviceId: 'a1',
352
+ channelId: 'a11',
353
+ icontype: 'on',
354
+ }
355
+ ]
356
+ }
357
+ ],
358
+ // 树节点对应的key
359
+ treeNodeKey: 'id',
360
+ // 树节点展开的key
361
+ treeExpandedKeys: ['11'],
362
+ // 树节点属性
363
+ treeOptions: {
364
+ icontype: 'icontype',
365
+ background: 'background',
366
+ videoUrlKey: 'url',
367
+ children: 'children',
368
+ label: 'label',
369
+ },
370
+ // 获取、设置打开的播放视频信息
371
+ videoInfos: [
372
+ {
373
+ index: 0,
374
+ url: 'https://example.com/video.flv',
375
+ info: {
376
+ videoModel: 'easyplayer',
377
+ id: 'video1',
378
+ url: 'https://example.com/video.flv',
379
+ deviceId: 'c1',
380
+ channelId: 'c11',
381
+ },
382
+ }
383
+ ],
384
+ // 单点播放
385
+ videoSingleUrl: false,
386
+ // 已经在播放的是否关闭后再点击打开
387
+ videoSingleClose: false,
388
+ // 播放模式: 1: 单击,2: 双击
389
+ videoPlayModel: 1,
390
+ // 分屏模式: 1: 单屏, 2: 四屏, 3: 九屏
391
+ videoSplitType: 1,
392
+ // 显示分屏按钮
393
+ showVideoSplit: true,
394
+ // 显示方向控制按钮
395
+ showVideoCtrls: false,
396
+ // 禁止控制按钮默认请求行为
397
+ stopVideoCtrlMethods: true,
398
+ // 单个视频错误最大次数
399
+ videoErrorMaxCount: 3,
400
+ // easyplayer配置
401
+ videoConfig: {
402
+ MSE: true,
403
+ WCS: true,
404
+ WASM: true,
405
+ WASMSIMD: true,
406
+ isLive: true,
407
+ hasAudio: false,
408
+ stretch: false
409
+ },
410
+ // 事件回调
411
+ treeClick: () => { console.log('点击树节点') },
412
+ treeDBClick: () => { console.log('双击树节点') },
413
+ treeRightMenu: () => { console.log('右键树菜单') },
414
+ treeExpand: () => { console.log('展开树节点') },
415
+ videoError: () => { console.log('视频错误') },
416
+ }
417
+
418
+ // 视频操作事件
419
+ const videoEvent = {
420
+ videoOriginalInfo: (info) => { console.log('视频原始信息:', info) },
421
+ up: () => { console.log('向上移动') },
422
+ down: () => { console.log('向下移动') },
423
+ left: () => { console.log('向左移动') },
424
+ right: () => { console.log('向右移动') },
425
+ zoomin: () => { console.log('放大') },
426
+ zoomout: () => { console.log('缩小') },
427
+ stop: () => { console.log('停止') },
428
+ speed: () => { console.log('设置速度') },
429
+ speak: () => { console.log('开始说话') },
430
+ scan: () => { console.log('扫描') },
431
+ cruise: () => { console.log('巡航') },
432
+ call: () => { console.log('调用') },
433
+ }
434
+
435
+ // 获取原始视频信息
436
+ const videoInfo = nsVideoRef.value?.getOriginalInfo()
437
+
438
+ // 设置视频URL
439
+ nsVideoRef.value?.setVideoUrl('ws://example.com/rtp/video.live.flv', false, 1, {
440
+ videoModel: 'easyplayer'
441
+ })
442
+
443
+ // 移除视频
444
+ nsVideoRef.value?.removeVideo(1, true)
445
+
446
+ // 分屏变化回调
447
+ function changeSplitHandler(num) {
448
+ console.log('分屏模式:', num)
449
+ }
450
+ </script>
451
+ ```
452
+
453
+ **前置准备:**
454
+
455
+ 1. 复制播放器资源:`js文件夹` 到 `public/` 目录中
456
+ 2. 复制播放器资源:`cdn文件夹` 到 `public/` 目录中
457
+ 3. 在 `index.html` 中引入:
458
+
459
+ ```html
460
+ <script src="./js/EasyPlayer-pro.js"></script>
461
+ <script src="./cdn/h5player/h5player.min.js"></script>
462
+ ```
463
+
464
+ ### 4. NsDialog - 弹出框组件
465
+
466
+ ```javascript
467
+ import { NsDialog, closeAllNsDialog } from 'vue3-components-plus'
468
+
469
+ // 打开对话框
470
+ NsDialog({
471
+ title: '测试',
472
+ // 任何组件添加 $emit('close') 时,会触发关闭弹出框事件
473
+ dom: VideoDemo, // 也可以通过异步方式:import("@/views/VideoDemo.vue") 和 () => import("@/views/VideoDemo.vue")
474
+ option: {
475
+ // dom对应的自定义组件props属性
476
+ ...data,
477
+ },
478
+ events: {
479
+ // dom组件内部自定义事件emit('btnClick', xxx)
480
+ btnClick: () => {
481
+ console.log("点击中间区域内容");
482
+ },
483
+ },
484
+ modalColor: 'rgb(0 21 115 / 20%)', // 遮罩层颜色
485
+ width: '800px', // 宽度, 整个弹出框的高度,非内容高度
486
+ height: '450px', // 高度, 不配置则默认为内容高度
487
+ dialogPadding: [10, 20], // 弹窗内padding
488
+ showFooter: true, // 默认显示底部按钮
489
+ immediately: false, // true立即取消弹出框, false异步请求后取消弹出框,默认false
490
+ draggable: true, // 是否可拖拽,默认false
491
+
492
+ confirm: async (closeFn, componentRef, footerLoading) => { // 底部确认按钮回调事件
493
+ // componentRef可以调用内部函数,前提需要defineExpose
494
+ try{
495
+ const selectRows = componentRef?.value?.getSelectedRows();
496
+ console.log("点击确认,选择数据:", selectRows);
497
+ } catch(e) {
498
+ console.log(e)
499
+ await new Promise(resolve => setTimeout(resolve, 1000))
500
+ }
501
+ // footerLoading可以控制底部loading状态
502
+ if(footerLoading) {
503
+ footerLoading.value = false
504
+ }
505
+ // 请求数据,再关闭
506
+ if(closeFn) {
507
+ closeFn()
508
+ }
509
+ },
510
+ close: () => { // 关闭弹出时立即出发
511
+ console.log("点击关闭");
512
+ },
513
+ closed: () => { // 弹窗销毁时触发
514
+ console.log("完成关闭");
515
+ },
516
+ // 头部+底部自定义配置
517
+ headerDom: xxx,
518
+ headerOption: {},
519
+ headerEvents: {},
520
+ footerDom: yyy,
521
+ footerOption: {},
522
+ footerEvents: {},
523
+ // 底部按钮名称
524
+ footerTitle: {
525
+ close: "取消",
526
+ confirm: "确定",
527
+ },
528
+ }, true, '#app') // true为是否遮罩(非必填), '#app'为挂载点(非必填)
529
+
530
+ // 关闭所有对话框
531
+ closeAllNsDialog()
532
+ ```
533
+
534
+ ### 5. NsPdf - PDF预览组件
535
+
536
+ ```vue
537
+ <template>
538
+ <NsPdf ref="pdfRef" :url="pdfUrl"></NsPdf>
539
+ </template>
540
+
541
+ <script setup>
542
+ import { ref } from 'vue'
543
+ import { NsPdf } from 'vue3-components-plus'
544
+
545
+ const pdfRef = ref()
546
+
547
+ // 搜索关键词
548
+ function searchKeyword() {
549
+ pdfRef.value?.search('关键词')
550
+ }
551
+ </script>
552
+ ```
553
+
554
+ ### 6. NsExcel - Excel预览/编辑组件
555
+
556
+ ```vue
557
+ <template>
558
+ <NsExcel :url="excelUrl" :isEdit="true" />
559
+ </template>
560
+ ```
561
+
562
+ ### 7. NsWord - Word预览组件
563
+
564
+ ```vue
565
+ <template>
566
+ <NsWord :url="wordUrl" />
567
+ </template>
568
+ ```
569
+
570
+ ### 8. NsImage - 图片预览组件
571
+
572
+ ```vue
573
+ <template>
574
+ <NsImage :src="imageUrl" :defaultImg="defaultImage" />
575
+ </template>
576
+ ```
577
+
578
+ ### 9. NsMD - Markdown编辑器组件
579
+
580
+ ```vue
581
+ <template>
582
+ <NsMD v-model="markdownContent" />
583
+ </template>
584
+ ```
585
+
586
+ ### 10. NsSaturationline - 饱和度线组件
587
+
588
+ ```vue
589
+ <template>
590
+ <NsSaturationline :data="saturationData" />
591
+ </template>
592
+ ```
593
+
594
+ ### 11. NsAutoScreen - 自适应屏幕工具
595
+
596
+ ```javascript
597
+ import { autoScaleInit, sacle_x, sacle_y } from 'vue3-components-plus'
598
+
599
+ // 初始化自适应
600
+ autoScaleInit(document.querySelector('body'), {
601
+ designWidth: 1920,
602
+ designHeight: 920,
603
+ mode: 'stretch', // 可选 horizontal/vertical/stretch
604
+ });
605
+
606
+ // 获取缩放比例
607
+ const scaleX = sacle_x()
608
+ const scaleY = sacle_y()
609
+ ```
610
+
611
+ ## 🔧 自定义指令
612
+
613
+ ### 1. v-permission - 按钮权限控制
614
+
615
+ ```vue
616
+ <template>
617
+ <!-- 使用class控制权限,无权限时隐藏 -->
618
+ <el-button v-permission.class.display>查看</el-button>
619
+
620
+ <!-- 使用id控制权限,无权限时隐藏 -->
621
+ <el-button v-permission.id>编辑</el-button>
622
+
623
+ <!-- 默认使用id控制权限 -->
624
+ <el-button id="zuhu_list_add" v-permission>新增</el-button>
625
+ </template>
626
+
627
+ <script setup>
628
+ // 权限配置(需要在引入组件库之前设置)
629
+ import { createApp } from 'vue'
630
+
631
+ const app = createApp(App)
632
+
633
+ // 方式1:使用 provide/inject
634
+ const btnsPermission = ['zuhu_list_add', 'zuhu_list_edit', 'admin-btn']
635
+ app.provide('btnsPermission', btnsPermission)
636
+
637
+ // 方式2:使用全局属性
638
+ app.config.globalProperties.$btnsPermission = ['zuhu_list_add', 'zuhu_list_edit']
639
+
640
+ // 方式3:使用 sessionStorage(适用于动态权限)(推荐)
641
+ sessionStorage.setItem('btnsPermission', JSON.stringify(['zuhu_list_add', 'zuhu_list_edit']))
642
+
643
+ // 方式4:使用 localStorage(持久化权限)
644
+ localStorage.setItem('btnsPermission', JSON.stringify(['zuhu_list_add', 'zuhu_list_edit']))
645
+
646
+ app.use(NsComponents) // 引入组件库
647
+ </script>
648
+ ```
649
+
650
+ #### 权限控制优先级说明
651
+
652
+ 权限控制按以下优先级进行判断(从高到低):
653
+
654
+ 1. **sessionStorage** → `sessionStorage.getItem('btnsPermission')`
655
+ 2. **localStorage** → `localStorage.getItem('btnsPermission')`
656
+ 3. **全局属性** → `app.config.globalProperties.$btnsPermission`
657
+ 4. **provide/inject** → `app.provide('btnsPermission', btnsPermission)`
658
+
659
+ #### 指令修饰符说明
660
+
661
+ - **v-permission** - 默认模式,使用 `id` 选择器,无权限时设置 `visibility: hidden`
662
+ - **v-permission.id** - 显式指定使用 `id` 选择器
663
+ - **v-permission.class** - 使用 `class` 选择器
664
+ - **v-permission.id.display** - 使用 `id` 选择器,无权限时设置 `display: none`
665
+ - **v-permission.class.display** - 使用 `class` 选择器,无权限时设置 `display: none`
666
+
667
+ #### 动态权限切换示例
668
+
669
+ ```javascript
670
+ // 动态切换权限
671
+ function togglePermission() {
672
+ // 获取当前权限列表
673
+ let btnsPermission = JSON.parse(sessionStorage.getItem('btnsPermission')) || []
674
+
675
+ // 添加新权限
676
+ if (!btnsPermission.includes('delete_btn')) {
677
+ btnsPermission.push('delete_btn')
678
+ } else {
679
+ // 移除权限
680
+ btnsPermission = btnsPermission.filter(item => item !== 'delete_btn')
681
+ }
682
+
683
+ // 更新权限存储
684
+ sessionStorage.setItem('btnsPermission', JSON.stringify(btnsPermission))
685
+
686
+ // 刷新页面或重新渲染组件
687
+ location.reload() // 或使用响应式更新
688
+ }
689
+ ```
690
+
691
+ #### 实际应用场景
692
+
693
+ ```vue
694
+ <template>
695
+ <!-- 按钮组权限控制 -->
696
+ <div class="toolbar">
697
+ <el-button id="add_btn" v-permission type="primary">添加</el-button>
698
+ <el-button id="edit_btn" v-permission type="success">编辑</el-button>
699
+ <el-button id="delete_btn" v-permission type="danger">删除</el-button>
700
+ <el-button id="export_btn" v-permission.id.display type="warning">导出</el-button>
701
+ <el-button class="admin-btn" v-permission.class type="info">管理员</el-button>
702
+ </div>
703
+
704
+ <!-- 菜单权限控制 -->
705
+ <el-menu>
706
+ <el-menu-item index="1" id="dashboard_menu" v-permission>
707
+ <span>仪表盘</span>
708
+ </el-menu-item>
709
+ <el-menu-item index="2" class="user-menu" v-permission.class>
710
+ <span>用户管理</span>
711
+ </el-menu-item>
712
+ </el-menu>
713
+ </template>
714
+
715
+ <script setup>
716
+ // 权限配置示例
717
+ const app = createApp(App)
718
+
719
+ // 实际项目中,权限数据通常从后端获取
720
+ const userPermissions = {
721
+ // 普通用户权限
722
+ normal: ['add_btn', 'edit_btn', 'dashboard_menu'],
723
+ // 管理员权限
724
+ admin: ['add_btn', 'edit_btn', 'delete_btn', 'export_btn', 'admin-btn', 'user-menu']
725
+ }
726
+
727
+ // 根据用户角色设置权限
728
+ const userRole = 'admin' // 从登录信息获取
729
+ app.provide('btnsPermission', userPermissions[userRole])
730
+
731
+ app.use(NsComponents)
732
+ </script>
733
+ ```
734
+
735
+ ### 2. v-length - 输入长度限制
736
+
737
+ ```vue
738
+ <template>
739
+ <!-- 限制最大长度50(默认) -->
740
+ <el-input v-length placeholder="请输入用户名" />
741
+
742
+ <!-- 自定义长度限制 -->
743
+ <el-input v-length="100" placeholder="最多100字符" />
744
+
745
+ <!-- 仅允许输入数字 -->
746
+ <el-input v-length.number="11" placeholder="请输入手机号" />
747
+
748
+ <!-- 自定义正则表达式 -->
749
+ <el-input v-length.regex="{ maxLength: 10, pattern: /^[a-zA-Z]*$/ }" placeholder="仅允许字母" />
750
+
751
+ <!-- 数字范围限制 -->
752
+ <el-input v-length.range="{ min: 0, max: 100, int: true, maxLength: 10 }" placeholder="0-100整数" />
753
+ </template>
754
+ ```
755
+
756
+ ### 3. v-sline - 单行文本省略
757
+
758
+ ```vue
759
+ <template>
760
+ <span v-sline>这是一段很长的文本内容,超出部分会自动显示省略号...</span>
761
+ </template>
762
+ ```
763
+
764
+ ### 4. v-event-unuse / v-event-use - 事件穿透控制
765
+
766
+ ```vue
767
+ <template>
768
+ <!-- 阻止事件穿透 -->
769
+ <div v-event-use>
770
+ <button>这个按钮可以点击</button>
771
+ </div>
772
+
773
+ <!-- 允许事件穿透 -->
774
+ <div v-event-unuse>
775
+ <div>这个区域的事件会穿透到下层</div>
776
+ </div>
777
+ </template>
778
+ ```
779
+
780
+ ## 🔧 工具函数
781
+
782
+ ### 1. 通用工具函数
783
+
784
+ ```javascript
785
+ import { isNotNull } from 'vue3-components-plus'
786
+
787
+ // 检查值是否非空
788
+ const result = isNotNull(value) // 返回布尔值
789
+ ```
790
+
791
+ ### 2. 动态资源加载
792
+
793
+ ```javascript
794
+ import { loadAccess, removeDynamicAccess } from 'vue3-components-plus'
795
+
796
+ // 加载JS/CSS资源
797
+ await loadAccess('https://example.com/script.js', 'script-tag', false)
798
+
799
+ // 移除动态加载的资源
800
+ removeDynamicAccess('script-tag')
801
+ ```
802
+
803
+ ### 3. CSS变量管理
804
+
805
+ ```javascript
806
+ import { loadCssVars } from 'vue3-components-plus'
807
+
808
+ // 获取所有CSS变量
809
+ const cssVars = loadCssVars()
810
+ console.log(cssVars['--matrix-primary-color'])
811
+ ```
812
+
813
+ ### 4. 表格排序工具
814
+
815
+ ```javascript
816
+ import { handleSortChange, headerClick, handleHeaderCellClass } from 'vue3-components-plus'
817
+
818
+ // 在表格组件中使用
819
+ <el-table
820
+ @sort-change="(sort) => handleSortChange(sort, searchForm, getList)"
821
+ @header-click="headerClick"
822
+ :header-cell-class-name="(params) => handleHeaderCellClass(params, searchForm)"
823
+ >
824
+ <!-- 表格内容 -->
825
+ </el-table>
826
+ ```
827
+
828
+ ### 5. SM2加密工具
829
+
830
+ ```javascript
831
+ import { getEncryptSm2 } from 'vue3-components-plus'
832
+
833
+ // 使用SM2加密
834
+ const encrypted = getEncryptSm2(publicKey, ["xxx", "yyy"], isAdd04=false, cipherMode=1)
835
+ ```
836
+
837
+ ### 6. 动态表单工具函数
838
+
839
+ ```javascript
840
+ import {
841
+ useFileUpload,
842
+ getAllFormNodeByKey,
843
+ getAllFormKvData,
844
+ getAllFormNodeRefByKey
845
+ } from 'vue3-components-plus'
846
+
847
+ // 表单文件上传hook
848
+ const { uploadFile, deleteFile } = useFileUpload()
849
+
850
+ // 根据key获取表单节点信息
851
+ const formNode = getAllFormNodeByKey(formRows, 'username')
852
+
853
+ // 获取表单所有键值对数据
854
+ const formData = getAllFormKvData(formRows)
855
+
856
+ // 根据key获取表单节点引用
857
+ const nodeRef = getAllFormNodeRefByKey(formRows, 'username')
858
+ ```
859
+
860
+
861
+
862
+ ### 7. 屏幕自适应函数
863
+
864
+ ```javascript
865
+ import { sacle_x, sacle_y, autoScaleInit } from 'vue3-components-plus'
866
+
867
+ // 初始化自适应
868
+ autoScaleInit(document.querySelector('body'), {
869
+ designWidth: 1920,
870
+ designHeight: 920,
871
+ mode: 'stretch' // 可选 horizontal/vertical/stretch
872
+ })
873
+
874
+ // 获取当前缩放比例
875
+ const scaleX = sacle_x()
876
+ const scaleY = sacle_y()
877
+ ```
878
+
879
+ ## 🌐 HTTP请求函数
880
+
881
+ ### 1. 基础HTTP请求方法
882
+
883
+ ```javascript
884
+ import { get, post, put, del, download, downLoadLocalFile, getTokenInfo } from 'vue3-components-plus'
885
+
886
+ // GET请求
887
+ const result = await get('/api/users', { page: 1, size: 10 })
888
+
889
+ // POST请求
890
+ const result = await post('/api/users', { name: '张三', age: 25 })
891
+
892
+ // PUT请求
893
+ const result = await put('/api/users/1', { name: '李四', age: 30 })
894
+
895
+ // DELETE请求
896
+ const result = await del('/api/users/1')
897
+
898
+ // 文件下载
899
+ await download('/api/export', 'report.xlsx', 'get', { type: 'excel' })
900
+
901
+ // 下载本地文件
902
+ downLoadLocalFile('/public/', 'template.xlsx', 'template.xlsx')
903
+
904
+ // 获取token信息
905
+ const tokenInfo = getTokenInfo()
906
+ ```
907
+
908
+ ### 2. 初始化配置
909
+
910
+ ```javascript
911
+ // main.ts中配置
912
+ import { createApp } from 'vue'
913
+ import NsComponents from 'vue3-components-plus'
914
+
915
+ const app = createApp(App)
916
+
917
+ // 请求地址的baseUrl,建议在app.use(NsComponents)之前设置
918
+ app.config.globalProperties.$BaseUrl = 'http://api.example.com/'
919
+
920
+ // 图片、文件请求地址的ImageBaseUrl,建议在app.use(NsComponents)之前设置
921
+ app.config.globalProperties.$ImageBaseUrl = 'http://api.example.com/'
922
+
923
+ // 【可选】401无权显示回调
924
+ app.config.globalProperties.$LogoutCallback = logoutHandler
925
+
926
+ // 【可选】请求添加的token头的key,默认为satoken
927
+ sessionStorage.setItem('tokenName', 'Authorization')
928
+ sessionStorage.setItem('tokenValue', 'Bearer your-token-here')
929
+
930
+ app.use(NsComponents)
931
+ ```
932
+
933
+ ### 3. 实际使用示例
934
+
935
+ ```javascript
936
+ // api/user.js
937
+ import { get, post } from 'vue3-components-plus'
938
+
939
+ export const getUserList = (params) => get('/api/users', params)
940
+
941
+ export const createUser = (data) => post('/api/users', data)
942
+
943
+ export const updateUser = (id, data) => put(`/api/users/${id}`, data)
944
+
945
+ export const deleteUser = (id) => del(`/api/users/${id}`)
946
+
947
+ export const exportUsers = () => download('/api/users/export', 'users.xlsx')
948
+ ```
949
+
950
+ ## 🚀 完整安装和使用
951
+
952
+ ### 1. 安装依赖
953
+
954
+ ```bash
955
+ # 安装Element Plus
956
+ pnpm i element-plus
957
+
958
+ # 安装组件库
959
+ pnpm i vue3-components-plus -S --registry=http://199.10.9.178:8081/repository/npm-group/
960
+
961
+ # 如果安装失败,使用备用地址
962
+ pnpm i vue3-components-plus --registry=http://199.10.9.178:8081/repository/npm-hosted/
963
+ ```
964
+
965
+ ### 2. 全局引入
966
+
967
+ ```javascript
968
+ // main.ts
969
+ import { createApp } from 'vue'
970
+ import App from './App.vue'
971
+
972
+ // 安装 Element-Plus
973
+ import 'element-plus/dist/index.css'
974
+ import ElementPlus from 'element-plus'
975
+ import zhCn from 'element-plus/es/locale/lang/zh-cn'
976
+
977
+ // 安装组件库
978
+ // @ts-ignore
979
+ import NsComponents from 'vue3-components-plus'
980
+ import 'vue3-components-plus/dist/vue3-components-plus.css'
981
+
982
+ const app = createApp(App)
983
+
984
+ // 配置请求地址
985
+ app.config.globalProperties.$BaseUrl = 'http://your-api-server/'
986
+ app.config.globalProperties.$ImageBaseUrl = 'http://your-api-server/'
987
+
988
+ app.use(ElementPlus, {
989
+ locale: zhCn,
990
+ })
991
+ app.use(NsComponents)
992
+
993
+ app.mount('#app')
994
+ ```
995
+
996
+ ### 3. 按需引入
997
+
998
+ ```javascript
999
+ // 按需引入组件和函数
1000
+ import { NsForm, NsVideo, get, post, autoScaleInit } from 'vue3-components-plus'
1001
+
1002
+ // 在组件中使用
1003
+ const app = createApp(App)
1004
+ app.use(NsForm)
1005
+ app.use(NsVideo)
1006
+
1007
+ autoScaleInit(document.querySelector('body'), {
1008
+ designWidth: 1920,
1009
+ designHeight: 920,
1010
+ mode: 'stretch'
1011
+ })
1012
+ ```
1013
+
1014
+ ## 更新日志
1015
+
1016
+ ```text
1017
+ version: 3.0.10
1018
+ 日期: 2026-01-23
1019
+ 更新内容:
1020
+ 1. 修改NsSaturationLine文字字体
1021
+ ```
1022
+