vue3-smart-table 1.0.0 → 1.0.3

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 CHANGED
@@ -181,7 +181,6 @@ src/
181
181
  │ ├─ renderer.ts # 渲染器管理器
182
182
  │ ├─ config.ts # 全局配置管理
183
183
  │ ├─ utils/ # 内部工具函数
184
- │ ├─ styles/ # 组件样式
185
184
  │ ├─ types.ts # 类型定义
186
185
  │ └─ index.vue # SmartTable 主组件
187
186
  ├─ types/ # 类型工具(对外提供)
@@ -231,7 +230,7 @@ const loading = ref(false)
231
230
 
232
231
  ---
233
232
 
234
- ## 新特性 (v1.0.0)
233
+
235
234
 
236
235
  ### 1. 插件化架构
237
236
 
@@ -266,9 +265,6 @@ setSmartTableConfig({
266
265
  page: 1,
267
266
  size: 20
268
267
  },
269
- theme: {
270
- primaryColor: '#409EFF'
271
- },
272
268
  renderers: {
273
269
  // 全局注册自定义渲染器
274
270
  'custom-renderer': MyRendererComponent
@@ -359,771 +355,771 @@ export interface ButtonConfig<R = any> {
359
355
 
360
356
  ---
361
357
 
362
- ## 4. 内置渲染器完整指南
363
-
364
- SmartTable 提供 13 种内置渲染器,按功能分为 4 类:
365
-
366
- - **📝 展示型** (7种):html、copy、img、dict、map、formatter、icon
367
- - **✏️ 编辑型** (3种):input、input-number、select
368
- - **🔘 操作型** (2种):button、link
369
- - **🔧 扩展型** (1种):slot
370
-
371
- ### 快速查找表
372
-
373
- | 渲染器 | 类型 | 配置复杂度 | 支持事件 |
374
- |--------|------|-----------|---------|
375
- | `html` | 展示 | ⭐ | ❌ |
376
- | `copy` | 展示 | ⭐⭐ | ❌ |
377
- | `img` | 展示 | ⭐⭐ | ❌ |
378
- | `dict` | 展示 | ⭐⭐⭐ | ❌ |
379
- | `map` | 展示 | ⭐⭐ | ❌ |
380
- | `formatter` | 展示 | ⭐⭐ | ❌ |
381
- | `icon` | 展示 | ⭐⭐ | ❌ |
382
- | `input` | 编辑 | ⭐⭐ | ✅ |
383
- | `input-number` | 编辑 | ⭐⭐ | ✅ |
384
- | `select` | 编辑 | ⭐⭐ | ✅ |
385
- | `button` | 操作 | ⭐ | ✅ |
386
- | `link` | 操作 | ⭐ | ✅ |
387
- | `slot` | 扩展 | ⭐⭐⭐⭐ | ❌ |
388
-
389
- ---
390
-
391
- ### 📝 展示型渲染器
392
-
393
- 用于数据展示,不涉及用户交互。
394
-
395
- #### 1. `html` - HTML 内容渲染
396
-
397
- **功能**:渲染 HTML 内容,支持多行文本截断(最多 2 行)。
398
-
399
- **配置**:
400
- ```typescript
401
- {
402
- key: 'description',
403
- label: '描述',
404
- render: 'html',
405
- renderProps: {
406
- style?: string // 自定义样式
407
- class?: string // 自定义类名
408
- }
409
- }
410
- ```
411
-
412
- **示例**:
413
- ```typescript
414
- const columns = [
415
- {
416
- key: 'content',
417
- label: '商品描述',
418
- render: 'html'
419
- }
420
- ]
421
-
422
- const tableData = [
423
- {
424
- content: '<p>这是一段<strong>加粗</strong>的文本</p>'
425
- }
426
- ]
427
- ```
428
-
429
- **效果**:
430
- - 自动截断为 2 行
431
- - 支持富文本 HTML
432
- - 超出部分显示省略号
433
-
434
- ---
435
-
436
- #### 2. `copy` - 可复制文本
437
-
438
- **功能**:hover 显示复制按钮,点击复制文本到剪贴板。
439
-
440
- **配置**:
441
- ```typescript
442
- {
443
- key: 'code',
444
- label: '编号',
445
- render: 'copy',
446
- renderProps: {
447
- iconColor?: string // 图标颜色,默认 '#409EFF'
448
- copyTitle?: string // 复制提示文本,默认 '复制'
449
- successText?: string // 成功提示,默认 '复制成功'
450
- errorText?: string // 失败提示,默认 '复制失败'
451
- }
452
- }
453
- ```
454
-
455
- **示例**:
456
- ```typescript
457
- const columns = [
458
- {
459
- key: 'orderNo',
460
- label: '订单号',
461
- render: 'copy',
462
- renderProps: {
463
- iconColor: '#67C23A',
464
- successText: '订单号已复制',
465
- errorText: '复制失败,请重试'
466
- }
467
- }
468
- ]
469
- ```
470
-
471
- **效果**:
472
- - hover 显示复制按钮图标
473
- - 点击自动复制到剪贴板
474
- - 使用 ElMessage 提示结果
475
- - 支持单行文本截断
476
-
477
- ---
478
-
479
- #### 3. `img` - 图片预览
480
-
481
- **功能**:图片展示,支持单图/多图预览。
482
-
483
- **配置**:
484
- ```typescript
485
- {
486
- key: 'avatar',
487
- label: '头像',
488
- render: 'img',
489
- renderProps: {
490
- width?: string | number // 图片宽度,默认 '80px'
491
- height?: string | number // 图片高度,默认 '80px'
492
- fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down' // 适应方式
493
- previewSrcList?: string[] // 预览图片列表(可选)
494
- placeholder?: string // 无图片时的占位文本
495
- style?: string // 自定义样式
496
- }
497
- }
498
- ```
499
-
500
- **示例 - 单图**:
501
- ```typescript
502
- const columns = [
503
- {
504
- key: 'avatar',
505
- label: '头像',
506
- render: 'img',
507
- renderProps: {
508
- width: '60px',
509
- height: '60px',
510
- fit: 'cover'
511
- }
512
- }
513
- ]
514
-
515
- const tableData = [
516
- { avatar: 'https://example.com/avatar.jpg' }
517
- ]
518
- ```
519
-
520
- **示例 - 多图**:
521
- ```typescript
522
- const columns = [
523
- {
524
- key: 'gallery',
525
- label: '相册',
526
- render: 'img',
527
- renderProps: {
528
- width: '80px',
529
- height: '80px'
530
- }
531
- }
532
- ]
533
-
534
- const tableData = [
535
- {
536
- gallery: [
537
- 'https://example.com/img1.jpg',
538
- 'https://example.com/img2.jpg',
539
- 'https://example.com/img3.jpg'
540
- ]
541
- }
542
- ]
543
- ```
544
-
545
- **效果**:
546
- - **单图**:直接显示,点击预览
547
- - **多图**:显示第一张 + 数量标记(如:+2),点击预览全部
548
- - 支持 Element Plus Image 的所有预览功能
549
- - 无图片时显示占位符或空内容
550
-
551
- ---
552
-
553
- #### 4. `dict` - 字典标签映射
554
-
555
- **功能**:将值映射为标签显示(使用 ElTag)。
556
-
557
- **配置**:
558
- ```typescript
559
- {
560
- key: 'status',
561
- label: '状态',
562
- render: 'dict',
563
- renderProps: {
564
- options: Array<{ // 字典配置(必需)
565
- label: string // 显示文本
566
- value: any // 值
567
- listClass?: string // ElTag 类型:'primary' | 'success' | 'warning' | 'danger' | 'info'
568
- cssClass?: string // 自定义类名
569
- }>
570
- showValue?: boolean // 是否显示未匹配的值,默认 false
571
- }
572
- }
573
- ```
574
-
575
- **示例 - 单值**:
576
- ```typescript
577
- const columns = [
578
- {
579
- key: 'status',
580
- label: '状态',
581
- render: 'dict',
582
- renderProps: {
583
- options: [
584
- { label: '启用', value: 1, listClass: 'success' },
585
- { label: '禁用', value: 0, listClass: 'danger' },
586
- { label: '审核中', value: 2, listClass: 'warning' }
587
- ]
588
- }
589
- }
590
- ]
591
-
592
- const tableData = [
593
- { status: 1 } // 显示:[启用]
594
- ]
595
- ```
596
-
597
- **示例 - 多值**:
598
- ```typescript
599
- const columns = [
600
- {
601
- key: 'tags',
602
- label: '标签',
603
- render: 'dict',
604
- renderProps: {
605
- options: [
606
- { label: '重要', value: 'important', listClass: 'danger' },
607
- { label: '紧急', value: 'urgent', listClass: 'warning' }
608
- ],
609
- showValue: true // 显示未匹配的值
610
- }
611
- }
612
- ]
613
-
614
- const tableData = [
615
- { tags: ['important', 'urgent'] } // 显示:[重要] [紧急]
616
- ]
617
- ```
618
-
619
- **效果**:
620
- - 单值映射为单个标签
621
- - 多值映射为多个标签
622
- - 未匹配的值根据 `showValue` 决定是否显示
623
- - 支持自定义标签颜色和样式
624
-
625
- ---
626
-
627
- #### 5. `map` - 键值映射
628
-
629
- **功能**:简单的 key-value 映射。
630
-
631
- **配置**:
632
- ```typescript
633
- {
634
- key: 'gender',
635
- label: '性别',
636
- render: 'map',
637
- renderProps: {
638
- options: Record<string | number, any> // 映射配置(必需)
639
- }
640
- }
641
- ```
642
-
643
- **示例**:
644
- ```typescript
645
- const columns = [
646
- {
647
- key: 'gender',
648
- label: '性别',
649
- render: 'map',
650
- renderProps: {
651
- options: {
652
- 1: '男',
653
- 2: '女',
654
- 0: '未知'
655
- }
656
- }
657
- }
658
- ]
659
-
660
- const tableData = [
661
- { gender: 1 }, // 显示:男
662
- { gender: 2 }, // 显示:女
663
- { gender: 99 } // 显示:(空)
664
- ]
665
- ```
666
-
667
- **效果**:
668
- - 根据值映射显示对应文本
669
- - 未匹配的值显示空字符串
670
- - 比 `dict` 更简单,适合不需要标签样式的场景
671
-
672
- ---
673
-
674
- #### 6. `formatter` - 自定义格式化
675
-
676
- **功能**:使用自定义函数格式化显示。
677
-
678
- **配置**:
679
- ```typescript
680
- {
681
- key: 'price',
682
- label: '价格',
683
- render: 'formatter',
684
- formatter: (value: any, row: any) => string // 格式化函数
685
- }
686
- ```
687
-
688
- **示例**:
689
- ```typescript
690
- const columns = [
691
- {
692
- key: 'price',
693
- label: '价格',
694
- render: 'formatter',
695
- formatter: (value, row) => {
696
- return `¥${Number(value).toFixed(2)}`
697
- }
698
- },
699
- {
700
- key: 'date',
701
- label: '日期',
702
- render: 'formatter',
703
- formatter: (value) => {
704
- return new Date(value).toLocaleDateString('zh-CN')
705
- }
706
- }
707
- ]
708
-
709
- const tableData = [
710
- { price: 99.9, date: '2024-01-01' }
711
- ]
712
- ```
713
-
714
- **效果**:
715
- - 完全自定义格式化逻辑
716
- - 可以访问当前行数据
717
- - 适合复杂的格式化需求
718
-
719
- ---
720
-
721
- #### 7. `icon` - 图标渲染
722
-
723
- **功能**:支持多种图标格式。
724
-
725
- **配置**:
726
- ```typescript
727
- {
728
- key: 'icon',
729
- label: '图标',
730
- render: 'icon',
731
- renderProps: {
732
- style?: string // 自定义样式
733
- size?: number // 图标大小(像素)
734
- class?: string // 自定义类名
735
- }
736
- }
737
- ```
738
-
739
- **示例**:
740
- ```typescript
741
- const columns = [
742
- {
743
- key: 'avatarIcon',
744
- label: '头像',
745
- render: 'icon',
746
- renderProps: {
747
- style: 'font-size: 32px; color: #409EFF'
748
- }
749
- }
750
- ]
751
-
752
- const tableData = [
753
- // 1. 网络图片
754
- { icon: 'https://example.com/icon.png' },
755
-
756
- // 2. SVG 源码
757
- { icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">...</svg>' },
758
-
759
- // 3. iconfont 类名
760
- { icon: 'iconfont icon-user' }
761
- ]
762
- ```
763
-
764
- **效果**:
765
- - 自动识别图标类型
766
- - 网络图片:显示为 ElImage
767
- - SVG:直接渲染
768
- - iconfont:应用类名样式
769
-
770
- ---
771
-
772
- ### ✏️ 编辑型渲染器
773
-
774
- 支持单元格编辑,触发 `cellChange`、`cellBlur`、`cellEnter` 事件。
775
-
776
- #### 8. `input` - 可编辑输入框
777
-
778
- **配置**:
779
- ```typescript
780
- {
781
- key: 'username',
782
- label: '用户名',
783
- render: 'input',
784
- renderProps: {
785
- placeholder?: string // 占位文本,默认 ''
786
- size?: 'large' | 'default' | 'small' // 尺寸,默认 'small'
787
- clearable?: boolean // 是否可清空,默认 true
788
- // ... 其他 ElInput 属性
789
- }
790
- }
791
- ```
792
-
793
- **示例**:
794
- ```typescript
795
- const columns = [
796
- {
797
- key: 'username',
798
- label: '用户名',
799
- render: 'input',
800
- renderProps: {
801
- placeholder: '请输入用户名',
802
- clearable: true
803
- }
804
- }
805
- ]
806
- ```
807
-
808
- **事件处理**:
809
- ```vue
810
- <script setup>
811
- const handleCellChange = (row, col) => {
812
- console.log('值已修改:', row[col.key])
813
- }
814
-
815
- const handleCellBlur = (row, col) => {
816
- console.log('失去焦点')
817
- }
818
-
819
- const handleCellEnter = (row, col) => {
820
- console.log('回车确认')
821
- }
822
- </script>
823
-
824
- <template>
825
- <SmartTable
826
- :columns="columns"
827
- :data="tableData"
828
- @cellChange="handleCellChange"
829
- @cellBlur="handleCellBlur"
830
- @cellEnter="handleCellEnter"
831
- />
832
- </template>
833
- ```
834
-
835
- ---
836
-
837
- #### 9. `input-number` - 可编辑数字输入框
838
-
839
- **配置**:
840
- ```typescript
841
- {
842
- key: 'age',
843
- label: '年龄',
844
- render: 'input-number',
845
- renderProps: {
846
- min?: number // 最小值
847
- max?: number // 最大值
848
- step?: number // 步长
849
- precision?: number // 精度
850
- size?: 'large' | 'default' | 'small'
851
- controls?: boolean // 是否显示增减按钮
852
- // ... 其他 ElInputNumber 属性
853
- }
854
- }
855
- ```
856
-
857
- **示例**:
858
- ```typescript
859
- const columns = [
860
- {
861
- key: 'orderNum',
862
- label: '序号',
863
- render: 'input-number',
864
- renderProps: {
865
- min: 0,
866
- max: 100,
867
- step: 1,
868
- controls: false // 隐藏增减按钮
869
- }
870
- }
871
- ]
872
- ```
873
-
874
- ---
875
-
876
- #### 10. `select` - 可编辑下拉选择
877
-
878
- **配置**:
879
- ```typescript
880
- {
881
- key: 'status',
882
- label: '状态',
883
- render: 'select',
884
- renderProps: {
885
- options: Array<{ // 选项配置(必需)
886
- label: string
887
- value: any
888
- }>
889
- placeholder?: string // 占位文本,默认 '请选择'
890
- size?: 'large' | 'default' | 'small'
891
- clearable?: boolean // 是否可清空
892
- // ... 其他 ElSelect 属性
893
- }
894
- }
895
- ```
896
-
897
- **示例**:
898
- ```typescript
899
- const columns = [
900
- {
901
- key: 'role',
902
- label: '角色',
903
- render: 'select',
904
- renderProps: {
905
- placeholder: '请选择角色',
906
- clearable: true,
907
- options: [
908
- { label: '管理员', value: 'admin' },
909
- { label: '普通用户', value: 'user' },
910
- { label: '访客', value: 'guest' }
911
- ]
912
- }
913
- }
914
- ]
915
- ```
916
-
917
- ---
918
-
919
- ### 🔘 操作型渲染器
920
-
921
- 用于触发操作或跳转。
922
-
923
- #### 11. `button` - 操作按钮
924
-
925
- **配置**:
926
- ```typescript
927
- {
928
- key: 'action',
929
- label: '操作',
930
- render: 'button',
931
- renderProps: {
932
- label?: string // 按钮文本
933
- type?: 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text'
934
- size?: 'large' | 'default' | 'small'
935
- disabled?: boolean
936
- // ... 其他 ElButton 属性
937
- }
938
- }
939
- ```
940
-
941
- **示例**:
942
- ```typescript
943
- const columns = [
944
- {
945
- key: 'edit',
946
- label: '编辑',
947
- render: 'button',
948
- renderProps: {
949
- label: '编辑',
950
- type: 'primary',
951
- size: 'small'
952
- }
953
- }
954
- ]
955
- ```
956
-
957
- **事件处理**:
958
- ```vue
959
- <script setup>
960
- const handleCellClick = (row, col) => {
961
- if (col.key === 'edit') {
962
- console.log('编辑行:', row)
963
- }
964
- }
965
- </script>
966
-
967
- <template>
968
- <SmartTable
969
- :columns="columns"
970
- :data="tableData"
971
- @cellClick="handleCellClick"
972
- />
973
- </template>
974
- ```
975
-
976
- ---
977
-
978
- #### 12. `link` - 链接
979
-
980
- **配置**:
981
- ```typescript
982
- {
983
- key: 'detail',
984
- label: '详情',
985
- render: 'link',
986
- renderProps: {
987
- label?: string // 链接文本
988
- href: string // 链接地址(必需)
989
- blank?: boolean // 是否新窗口打开,默认 false
990
- style?: string // 自定义样式
991
- }
992
- }
993
- ```
994
-
995
- **示例**:
996
- ```typescript
997
- const columns = [
998
- {
999
- key: 'url',
1000
- label: '查看',
1001
- render: 'link',
1002
- renderProps: {
1003
- label: '查看详情',
1004
- href: 'https://example.com',
1005
- blank: true,
1006
- style: 'color: #409EFF'
1007
- }
1008
- }
1009
- ]
1010
- ```
1011
-
1012
- ---
1013
-
1014
- ### 🔧 扩展型渲染器
1015
-
1016
- 用于自定义复杂场景。
1017
-
1018
- #### 13. `slot` - 自定义插槽
1019
-
1020
- **功能**:使用 Vue 插槽完全自定义列内容。
1021
-
1022
- **配置**:
1023
- ```typescript
1024
- {
1025
- key: 'attachments',
1026
- label: '附件',
1027
- render: 'slot',
1028
- slot?: string // 插槽名称,默认使用 key
1029
- }
1030
- ```
1031
-
1032
- **示例**:
1033
- ```vue
1034
- <script setup>
1035
- const columns = [
1036
- {
1037
- key: 'attachments',
1038
- label: '附件列表',
1039
- render: 'slot',
1040
- slot: 'attachments'
1041
- }
1042
- ]
1043
-
1044
- const tableData = ref([
1045
- {
1046
- id: 1,
1047
- attachments: [
1048
- { name: 'file1.pdf', url: '/files/file1.pdf' },
1049
- { name: 'file2.jpg', url: '/files/file2.jpg' }
1050
- ]
1051
- }
1052
- ])
1053
-
1054
- const download = (url) => {
1055
- console.log('下载:', url)
1056
- }
1057
- </script>
1058
-
1059
- <template>
1060
- <SmartTable :columns="columns" :data="tableData">
1061
- <template #attachments="{ row }">
1062
- <div v-for="(file, index) in row.attachments" :key="index">
1063
- <el-button type="text" @click="download(file.url)">
1064
- {{ file.name }}
1065
- </el-button>
1066
- </div>
1067
- </template>
1068
- </SmartTable>
1069
- </template>
1070
- ```
1071
-
1072
- **效果**:
1073
- - 完全自定义列内容
1074
- - 访问完整的行数据
1075
- - 可以包含复杂的交互逻辑
1076
-
1077
- ---
1078
-
1079
- ### TypeScript 类型支持
1080
-
1081
- 所有渲染器的 `renderProps` 都有完整的 TypeScript 类型定义:
1082
-
1083
- ```typescript
1084
- import type { ColumnConfig, RendererPropsMap } from 'vue3-smart-table'
1085
-
1086
- // 类型安全
1087
- const column: ColumnConfig = {
1088
- key: 'status',
1089
- label: '状态',
1090
- render: 'dict',
1091
- renderProps: {
1092
- options: [ // ✅ 类型提示和检查
1093
- { label: '启用', value: 1 }
1094
- ]
1095
- }
1096
- }
1097
-
1098
- // 提取特定渲染器的 props 类型
1099
- type DictProps = RendererPropsMap['dict']
1100
- const dictConfig: DictProps = {
1101
- options: [],
1102
- showValue: true
1103
- }
1104
- ```
1105
-
1106
- ---
1107
-
1108
- ### 最佳实践
1109
-
1110
- 1. **选择合适的渲染器**
1111
- - 简单映射 → `map`
1112
- - 需要标签样式 → `dict`
1113
- - 复杂逻辑 → `formatter`
1114
- - 自定义内容 → `slot`
1115
-
1116
- 2. **性能优化**
1117
- - 大量数据时避免 `formatter`,使用 `map` 或 `dict`
1118
- - 复杂自定义内容优先使用 `slot`
1119
-
1120
- 3. **用户体验**
1121
- - 图片显示添加 `placeholder`
1122
- - 复制功能添加友好的提示文本
1123
- - 编辑单元格添加合适的 `placeholder`
1124
-
1125
- ---
1126
-
358
+ ## 4. 内置渲染器完整指南
359
+
360
+ SmartTable 提供 13 种内置渲染器,按功能分为 4 类:
361
+
362
+ - **📝 展示型** (7种):html、copy、img、dict、map、formatter、icon
363
+ - **✏️ 编辑型** (3种):input、input-number、select
364
+ - **🔘 操作型** (2种):button、link
365
+ - **🔧 扩展型** (1种):slot
366
+
367
+ ### 快速查找表
368
+
369
+ | 渲染器 | 类型 | 配置复杂度 | 支持事件 |
370
+ |--------|------|-----------|---------|
371
+ | `html` | 展示 | ⭐ | ❌ |
372
+ | `copy` | 展示 | ⭐⭐ | ❌ |
373
+ | `img` | 展示 | ⭐⭐ | ❌ |
374
+ | `dict` | 展示 | ⭐⭐⭐ | ❌ |
375
+ | `map` | 展示 | ⭐⭐ | ❌ |
376
+ | `formatter` | 展示 | ⭐⭐ | ❌ |
377
+ | `icon` | 展示 | ⭐⭐ | ❌ |
378
+ | `input` | 编辑 | ⭐⭐ | ✅ |
379
+ | `input-number` | 编辑 | ⭐⭐ | ✅ |
380
+ | `select` | 编辑 | ⭐⭐ | ✅ |
381
+ | `button` | 操作 | ⭐ | ✅ |
382
+ | `link` | 操作 | ⭐ | ✅ |
383
+ | `slot` | 扩展 | ⭐⭐⭐⭐ | ❌ |
384
+
385
+ ---
386
+
387
+ ### 📝 展示型渲染器
388
+
389
+ 用于数据展示,不涉及用户交互。
390
+
391
+ #### 1. `html` - HTML 内容渲染
392
+
393
+ **功能**:渲染 HTML 内容,支持多行文本截断(最多 2 行)。
394
+
395
+ **配置**:
396
+ ```typescript
397
+ {
398
+ key: 'description',
399
+ label: '描述',
400
+ render: 'html',
401
+ renderProps: {
402
+ style?: string // 自定义样式
403
+ class?: string // 自定义类名
404
+ }
405
+ }
406
+ ```
407
+
408
+ **示例**:
409
+ ```typescript
410
+ const columns = [
411
+ {
412
+ key: 'content',
413
+ label: '商品描述',
414
+ render: 'html'
415
+ }
416
+ ]
417
+
418
+ const tableData = [
419
+ {
420
+ content: '<p>这是一段<strong>加粗</strong>的文本</p>'
421
+ }
422
+ ]
423
+ ```
424
+
425
+ **效果**:
426
+ - 自动截断为 2 行
427
+ - 支持富文本 HTML
428
+ - 超出部分显示省略号
429
+
430
+ ---
431
+
432
+ #### 2. `copy` - 可复制文本
433
+
434
+ **功能**:hover 显示复制按钮,点击复制文本到剪贴板。
435
+
436
+ **配置**:
437
+ ```typescript
438
+ {
439
+ key: 'code',
440
+ label: '编号',
441
+ render: 'copy',
442
+ renderProps: {
443
+ iconColor?: string // 图标颜色,默认 '#409EFF'
444
+ copyTitle?: string // 复制提示文本,默认 '复制'
445
+ successText?: string // 成功提示,默认 '复制成功'
446
+ errorText?: string // 失败提示,默认 '复制失败'
447
+ }
448
+ }
449
+ ```
450
+
451
+ **示例**:
452
+ ```typescript
453
+ const columns = [
454
+ {
455
+ key: 'orderNo',
456
+ label: '订单号',
457
+ render: 'copy',
458
+ renderProps: {
459
+ iconColor: '#67C23A',
460
+ successText: '订单号已复制',
461
+ errorText: '复制失败,请重试'
462
+ }
463
+ }
464
+ ]
465
+ ```
466
+
467
+ **效果**:
468
+ - hover 显示复制按钮图标
469
+ - 点击自动复制到剪贴板
470
+ - 使用 ElMessage 提示结果
471
+ - 支持单行文本截断
472
+
473
+ ---
474
+
475
+ #### 3. `img` - 图片预览
476
+
477
+ **功能**:图片展示,支持单图/多图预览。
478
+
479
+ **配置**:
480
+ ```typescript
481
+ {
482
+ key: 'avatar',
483
+ label: '头像',
484
+ render: 'img',
485
+ renderProps: {
486
+ width?: string | number // 图片宽度,默认 '80px'
487
+ height?: string | number // 图片高度,默认 '80px'
488
+ fit?: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down' // 适应方式
489
+ previewSrcList?: string[] // 预览图片列表(可选)
490
+ placeholder?: string // 无图片时的占位文本
491
+ style?: string // 自定义样式
492
+ }
493
+ }
494
+ ```
495
+
496
+ **示例 - 单图**:
497
+ ```typescript
498
+ const columns = [
499
+ {
500
+ key: 'avatar',
501
+ label: '头像',
502
+ render: 'img',
503
+ renderProps: {
504
+ width: '60px',
505
+ height: '60px',
506
+ fit: 'cover'
507
+ }
508
+ }
509
+ ]
510
+
511
+ const tableData = [
512
+ { avatar: 'https://example.com/avatar.jpg' }
513
+ ]
514
+ ```
515
+
516
+ **示例 - 多图**:
517
+ ```typescript
518
+ const columns = [
519
+ {
520
+ key: 'gallery',
521
+ label: '相册',
522
+ render: 'img',
523
+ renderProps: {
524
+ width: '80px',
525
+ height: '80px'
526
+ }
527
+ }
528
+ ]
529
+
530
+ const tableData = [
531
+ {
532
+ gallery: [
533
+ 'https://example.com/img1.jpg',
534
+ 'https://example.com/img2.jpg',
535
+ 'https://example.com/img3.jpg'
536
+ ]
537
+ }
538
+ ]
539
+ ```
540
+
541
+ **效果**:
542
+ - **单图**:直接显示,点击预览
543
+ - **多图**:显示第一张 + 数量标记(如:+2),点击预览全部
544
+ - 支持 Element Plus Image 的所有预览功能
545
+ - 无图片时显示占位符或空内容
546
+
547
+ ---
548
+
549
+ #### 4. `dict` - 字典标签映射
550
+
551
+ **功能**:将值映射为标签显示(使用 ElTag)。
552
+
553
+ **配置**:
554
+ ```typescript
555
+ {
556
+ key: 'status',
557
+ label: '状态',
558
+ render: 'dict',
559
+ renderProps: {
560
+ options: Array<{ // 字典配置(必需)
561
+ label: string // 显示文本
562
+ value: any // 值
563
+ listClass?: string // ElTag 类型:'primary' | 'success' | 'warning' | 'danger' | 'info'
564
+ cssClass?: string // 自定义类名
565
+ }>
566
+ showValue?: boolean // 是否显示未匹配的值,默认 false
567
+ }
568
+ }
569
+ ```
570
+
571
+ **示例 - 单值**:
572
+ ```typescript
573
+ const columns = [
574
+ {
575
+ key: 'status',
576
+ label: '状态',
577
+ render: 'dict',
578
+ renderProps: {
579
+ options: [
580
+ { label: '启用', value: 1, listClass: 'success' },
581
+ { label: '禁用', value: 0, listClass: 'danger' },
582
+ { label: '审核中', value: 2, listClass: 'warning' }
583
+ ]
584
+ }
585
+ }
586
+ ]
587
+
588
+ const tableData = [
589
+ { status: 1 } // 显示:[启用]
590
+ ]
591
+ ```
592
+
593
+ **示例 - 多值**:
594
+ ```typescript
595
+ const columns = [
596
+ {
597
+ key: 'tags',
598
+ label: '标签',
599
+ render: 'dict',
600
+ renderProps: {
601
+ options: [
602
+ { label: '重要', value: 'important', listClass: 'danger' },
603
+ { label: '紧急', value: 'urgent', listClass: 'warning' }
604
+ ],
605
+ showValue: true // 显示未匹配的值
606
+ }
607
+ }
608
+ ]
609
+
610
+ const tableData = [
611
+ { tags: ['important', 'urgent'] } // 显示:[重要] [紧急]
612
+ ]
613
+ ```
614
+
615
+ **效果**:
616
+ - 单值映射为单个标签
617
+ - 多值映射为多个标签
618
+ - 未匹配的值根据 `showValue` 决定是否显示
619
+ - 支持自定义标签颜色和样式
620
+
621
+ ---
622
+
623
+ #### 5. `map` - 键值映射
624
+
625
+ **功能**:简单的 key-value 映射。
626
+
627
+ **配置**:
628
+ ```typescript
629
+ {
630
+ key: 'gender',
631
+ label: '性别',
632
+ render: 'map',
633
+ renderProps: {
634
+ options: Record<string | number, any> // 映射配置(必需)
635
+ }
636
+ }
637
+ ```
638
+
639
+ **示例**:
640
+ ```typescript
641
+ const columns = [
642
+ {
643
+ key: 'gender',
644
+ label: '性别',
645
+ render: 'map',
646
+ renderProps: {
647
+ options: {
648
+ 1: '男',
649
+ 2: '女',
650
+ 0: '未知'
651
+ }
652
+ }
653
+ }
654
+ ]
655
+
656
+ const tableData = [
657
+ { gender: 1 }, // 显示:男
658
+ { gender: 2 }, // 显示:女
659
+ { gender: 99 } // 显示:(空)
660
+ ]
661
+ ```
662
+
663
+ **效果**:
664
+ - 根据值映射显示对应文本
665
+ - 未匹配的值显示空字符串
666
+ - 比 `dict` 更简单,适合不需要标签样式的场景
667
+
668
+ ---
669
+
670
+ #### 6. `formatter` - 自定义格式化
671
+
672
+ **功能**:使用自定义函数格式化显示。
673
+
674
+ **配置**:
675
+ ```typescript
676
+ {
677
+ key: 'price',
678
+ label: '价格',
679
+ render: 'formatter',
680
+ formatter: (value: any, row: any) => string // 格式化函数
681
+ }
682
+ ```
683
+
684
+ **示例**:
685
+ ```typescript
686
+ const columns = [
687
+ {
688
+ key: 'price',
689
+ label: '价格',
690
+ render: 'formatter',
691
+ formatter: (value, row) => {
692
+ return `¥${Number(value).toFixed(2)}`
693
+ }
694
+ },
695
+ {
696
+ key: 'date',
697
+ label: '日期',
698
+ render: 'formatter',
699
+ formatter: (value) => {
700
+ return new Date(value).toLocaleDateString('zh-CN')
701
+ }
702
+ }
703
+ ]
704
+
705
+ const tableData = [
706
+ { price: 99.9, date: '2024-01-01' }
707
+ ]
708
+ ```
709
+
710
+ **效果**:
711
+ - 完全自定义格式化逻辑
712
+ - 可以访问当前行数据
713
+ - 适合复杂的格式化需求
714
+
715
+ ---
716
+
717
+ #### 7. `icon` - 图标渲染
718
+
719
+ **功能**:支持多种图标格式。
720
+
721
+ **配置**:
722
+ ```typescript
723
+ {
724
+ key: 'icon',
725
+ label: '图标',
726
+ render: 'icon',
727
+ renderProps: {
728
+ style?: string // 自定义样式
729
+ size?: number // 图标大小(像素)
730
+ class?: string // 自定义类名
731
+ }
732
+ }
733
+ ```
734
+
735
+ **示例**:
736
+ ```typescript
737
+ const columns = [
738
+ {
739
+ key: 'avatarIcon',
740
+ label: '头像',
741
+ render: 'icon',
742
+ renderProps: {
743
+ style: 'font-size: 32px; color: #409EFF'
744
+ }
745
+ }
746
+ ]
747
+
748
+ const tableData = [
749
+ // 1. 网络图片
750
+ { icon: 'https://example.com/icon.png' },
751
+
752
+ // 2. SVG 源码
753
+ { icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024">...</svg>' },
754
+
755
+ // 3. iconfont 类名
756
+ { icon: 'iconfont icon-user' }
757
+ ]
758
+ ```
759
+
760
+ **效果**:
761
+ - 自动识别图标类型
762
+ - 网络图片:显示为 ElImage
763
+ - SVG:直接渲染
764
+ - iconfont:应用类名样式
765
+
766
+ ---
767
+
768
+ ### ✏️ 编辑型渲染器
769
+
770
+ 支持单元格编辑,触发 `cellChange`、`cellBlur`、`cellEnter` 事件。
771
+
772
+ #### 8. `input` - 可编辑输入框
773
+
774
+ **配置**:
775
+ ```typescript
776
+ {
777
+ key: 'username',
778
+ label: '用户名',
779
+ render: 'input',
780
+ renderProps: {
781
+ placeholder?: string // 占位文本,默认 ''
782
+ size?: 'large' | 'default' | 'small' // 尺寸,默认 'small'
783
+ clearable?: boolean // 是否可清空,默认 true
784
+ // ... 其他 ElInput 属性
785
+ }
786
+ }
787
+ ```
788
+
789
+ **示例**:
790
+ ```typescript
791
+ const columns = [
792
+ {
793
+ key: 'username',
794
+ label: '用户名',
795
+ render: 'input',
796
+ renderProps: {
797
+ placeholder: '请输入用户名',
798
+ clearable: true
799
+ }
800
+ }
801
+ ]
802
+ ```
803
+
804
+ **事件处理**:
805
+ ```vue
806
+ <script setup>
807
+ const handleCellChange = (row, col) => {
808
+ console.log('值已修改:', row[col.key])
809
+ }
810
+
811
+ const handleCellBlur = (row, col) => {
812
+ console.log('失去焦点')
813
+ }
814
+
815
+ const handleCellEnter = (row, col) => {
816
+ console.log('回车确认')
817
+ }
818
+ </script>
819
+
820
+ <template>
821
+ <SmartTable
822
+ :columns="columns"
823
+ :data="tableData"
824
+ @cellChange="handleCellChange"
825
+ @cellBlur="handleCellBlur"
826
+ @cellEnter="handleCellEnter"
827
+ />
828
+ </template>
829
+ ```
830
+
831
+ ---
832
+
833
+ #### 9. `input-number` - 可编辑数字输入框
834
+
835
+ **配置**:
836
+ ```typescript
837
+ {
838
+ key: 'age',
839
+ label: '年龄',
840
+ render: 'input-number',
841
+ renderProps: {
842
+ min?: number // 最小值
843
+ max?: number // 最大值
844
+ step?: number // 步长
845
+ precision?: number // 精度
846
+ size?: 'large' | 'default' | 'small'
847
+ controls?: boolean // 是否显示增减按钮
848
+ // ... 其他 ElInputNumber 属性
849
+ }
850
+ }
851
+ ```
852
+
853
+ **示例**:
854
+ ```typescript
855
+ const columns = [
856
+ {
857
+ key: 'orderNum',
858
+ label: '序号',
859
+ render: 'input-number',
860
+ renderProps: {
861
+ min: 0,
862
+ max: 100,
863
+ step: 1,
864
+ controls: false // 隐藏增减按钮
865
+ }
866
+ }
867
+ ]
868
+ ```
869
+
870
+ ---
871
+
872
+ #### 10. `select` - 可编辑下拉选择
873
+
874
+ **配置**:
875
+ ```typescript
876
+ {
877
+ key: 'status',
878
+ label: '状态',
879
+ render: 'select',
880
+ renderProps: {
881
+ options: Array<{ // 选项配置(必需)
882
+ label: string
883
+ value: any
884
+ }>
885
+ placeholder?: string // 占位文本,默认 '请选择'
886
+ size?: 'large' | 'default' | 'small'
887
+ clearable?: boolean // 是否可清空
888
+ // ... 其他 ElSelect 属性
889
+ }
890
+ }
891
+ ```
892
+
893
+ **示例**:
894
+ ```typescript
895
+ const columns = [
896
+ {
897
+ key: 'role',
898
+ label: '角色',
899
+ render: 'select',
900
+ renderProps: {
901
+ placeholder: '请选择角色',
902
+ clearable: true,
903
+ options: [
904
+ { label: '管理员', value: 'admin' },
905
+ { label: '普通用户', value: 'user' },
906
+ { label: '访客', value: 'guest' }
907
+ ]
908
+ }
909
+ }
910
+ ]
911
+ ```
912
+
913
+ ---
914
+
915
+ ### 🔘 操作型渲染器
916
+
917
+ 用于触发操作或跳转。
918
+
919
+ #### 11. `button` - 操作按钮
920
+
921
+ **配置**:
922
+ ```typescript
923
+ {
924
+ key: 'action',
925
+ label: '操作',
926
+ render: 'button',
927
+ renderProps: {
928
+ label?: string // 按钮文本
929
+ type?: 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'text'
930
+ size?: 'large' | 'default' | 'small'
931
+ disabled?: boolean
932
+ // ... 其他 ElButton 属性
933
+ }
934
+ }
935
+ ```
936
+
937
+ **示例**:
938
+ ```typescript
939
+ const columns = [
940
+ {
941
+ key: 'edit',
942
+ label: '编辑',
943
+ render: 'button',
944
+ renderProps: {
945
+ label: '编辑',
946
+ type: 'primary',
947
+ size: 'small'
948
+ }
949
+ }
950
+ ]
951
+ ```
952
+
953
+ **事件处理**:
954
+ ```vue
955
+ <script setup>
956
+ const handleCellClick = (row, col) => {
957
+ if (col.key === 'edit') {
958
+ console.log('编辑行:', row)
959
+ }
960
+ }
961
+ </script>
962
+
963
+ <template>
964
+ <SmartTable
965
+ :columns="columns"
966
+ :data="tableData"
967
+ @cellClick="handleCellClick"
968
+ />
969
+ </template>
970
+ ```
971
+
972
+ ---
973
+
974
+ #### 12. `link` - 链接
975
+
976
+ **配置**:
977
+ ```typescript
978
+ {
979
+ key: 'detail',
980
+ label: '详情',
981
+ render: 'link',
982
+ renderProps: {
983
+ label?: string // 链接文本
984
+ href: string // 链接地址(必需)
985
+ blank?: boolean // 是否新窗口打开,默认 false
986
+ style?: string // 自定义样式
987
+ }
988
+ }
989
+ ```
990
+
991
+ **示例**:
992
+ ```typescript
993
+ const columns = [
994
+ {
995
+ key: 'url',
996
+ label: '查看',
997
+ render: 'link',
998
+ renderProps: {
999
+ label: '查看详情',
1000
+ href: 'https://example.com',
1001
+ blank: true,
1002
+ style: 'color: #409EFF'
1003
+ }
1004
+ }
1005
+ ]
1006
+ ```
1007
+
1008
+ ---
1009
+
1010
+ ### 🔧 扩展型渲染器
1011
+
1012
+ 用于自定义复杂场景。
1013
+
1014
+ #### 13. `slot` - 自定义插槽
1015
+
1016
+ **功能**:使用 Vue 插槽完全自定义列内容。
1017
+
1018
+ **配置**:
1019
+ ```typescript
1020
+ {
1021
+ key: 'attachments',
1022
+ label: '附件',
1023
+ render: 'slot',
1024
+ slot?: string // 插槽名称,默认使用 key
1025
+ }
1026
+ ```
1027
+
1028
+ **示例**:
1029
+ ```vue
1030
+ <script setup>
1031
+ const columns = [
1032
+ {
1033
+ key: 'attachments',
1034
+ label: '附件列表',
1035
+ render: 'slot',
1036
+ slot: 'attachments'
1037
+ }
1038
+ ]
1039
+
1040
+ const tableData = ref([
1041
+ {
1042
+ id: 1,
1043
+ attachments: [
1044
+ { name: 'file1.pdf', url: '/files/file1.pdf' },
1045
+ { name: 'file2.jpg', url: '/files/file2.jpg' }
1046
+ ]
1047
+ }
1048
+ ])
1049
+
1050
+ const download = (url) => {
1051
+ console.log('下载:', url)
1052
+ }
1053
+ </script>
1054
+
1055
+ <template>
1056
+ <SmartTable :columns="columns" :data="tableData">
1057
+ <template #attachments="{ row }">
1058
+ <div v-for="(file, index) in row.attachments" :key="index">
1059
+ <el-button type="text" @click="download(file.url)">
1060
+ {{ file.name }}
1061
+ </el-button>
1062
+ </div>
1063
+ </template>
1064
+ </SmartTable>
1065
+ </template>
1066
+ ```
1067
+
1068
+ **效果**:
1069
+ - 完全自定义列内容
1070
+ - 访问完整的行数据
1071
+ - 可以包含复杂的交互逻辑
1072
+
1073
+ ---
1074
+
1075
+ ### TypeScript 类型支持
1076
+
1077
+ 所有渲染器的 `renderProps` 都有完整的 TypeScript 类型定义:
1078
+
1079
+ ```typescript
1080
+ import type { ColumnConfig, RendererPropsMap } from 'vue3-smart-table'
1081
+
1082
+ // 类型安全
1083
+ const column: ColumnConfig = {
1084
+ key: 'status',
1085
+ label: '状态',
1086
+ render: 'dict',
1087
+ renderProps: {
1088
+ options: [ // ✅ 类型提示和检查
1089
+ { label: '启用', value: 1 }
1090
+ ]
1091
+ }
1092
+ }
1093
+
1094
+ // 提取特定渲染器的 props 类型
1095
+ type DictProps = RendererPropsMap['dict']
1096
+ const dictConfig: DictProps = {
1097
+ options: [],
1098
+ showValue: true
1099
+ }
1100
+ ```
1101
+
1102
+ ---
1103
+
1104
+ ### 最佳实践
1105
+
1106
+ 1. **选择合适的渲染器**
1107
+ - 简单映射 → `map`
1108
+ - 需要标签样式 → `dict`
1109
+ - 复杂逻辑 → `formatter`
1110
+ - 自定义内容 → `slot`
1111
+
1112
+ 2. **性能优化**
1113
+ - 大量数据时避免 `formatter`,使用 `map` 或 `dict`
1114
+ - 复杂自定义内容优先使用 `slot`
1115
+
1116
+ 3. **用户体验**
1117
+ - 图片显示添加 `placeholder`
1118
+ - 复制功能添加友好的提示文本
1119
+ - 编辑单元格添加合适的 `placeholder`
1120
+
1121
+ ---
1122
+
1127
1123
  ## 5. 事件
1128
1124
 
1129
1125
  ### 单元格编辑事件
@@ -1150,44 +1146,7 @@ interface SmartTableEmits {
1150
1146
 
1151
1147
  ---
1152
1148
 
1153
- ## 7. 主题定制
1154
-
1155
- ### CSS 变量
1156
-
1157
- 在项目中覆盖 CSS 变量来自定义主题:
1158
-
1159
- ```css
1160
- /* 你的样式文件 */
1161
- :root {
1162
- --st-primary-color: #1890ff;
1163
- --st-success-color: #52c41a;
1164
- --st-warning-color: #faad14;
1165
- --st-danger-color: #ff4d4f;
1166
- --st-info-color: #8c8c8c;
1167
-
1168
- /* 文本颜色 */
1169
- --st-text-primary: #262626;
1170
- --st-border-color: #d9d9d9;
1171
- --st-bg-color: #ffffff;
1172
- }
1173
- ```
1174
-
1175
- ### JavaScript 配置
1176
-
1177
- ```typescript
1178
- import { setSmartTableConfig } from 'vue3-smart-table'
1179
-
1180
- setSmartTableConfig({
1181
- theme: {
1182
- primaryColor: '#1890ff',
1183
- successColor: '#52c41a'
1184
- }
1185
- })
1186
- ```
1187
-
1188
- ---
1189
-
1190
- ## 8. 按需引入
1149
+ ## 6. 按需引入
1191
1150
 
1192
1151
  ### 只引入需要的部分
1193
1152
 
@@ -1220,7 +1179,7 @@ import { getRendererManager, createFunctionalRenderer } from 'vue3-smart-table'
1220
1179
 
1221
1180
  ---
1222
1181
 
1223
- ## 9. 高级用法
1182
+ ## 7. 高级用法
1224
1183
 
1225
1184
  ### 自定义渲染器(3种方式)
1226
1185
 
@@ -1338,7 +1297,7 @@ const permissions = ['user:edit', 'user:view']
1338
1297
 
1339
1298
  ---
1340
1299
 
1341
- ## 10. 完整示例
1300
+ ## 8. 完整示例
1342
1301
 
1343
1302
  ```vue
1344
1303
  <!-- 全局注册 -->