@ecolovo/uniapp-components 1.0.0

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.
Files changed (97) hide show
  1. package/components/aspect/aspect.vue +43 -0
  2. package/components/badge/badge.vue +88 -0
  3. package/components/button/button.vue +409 -0
  4. package/components/checkbox/checkbox.vue +183 -0
  5. package/components/checkbox-group/checkbox-group.vue +101 -0
  6. package/components/checkbox-group2/checkbox-group2.vue +138 -0
  7. package/components/checkbox-group2/checkbox.vue +103 -0
  8. package/components/data-list/data-list.vue +130 -0
  9. package/components/date-picker/date-picker-view.vue +181 -0
  10. package/components/date-picker/date-picker.vue +237 -0
  11. package/components/datetime-picker/datetime-picker-view.vue +209 -0
  12. package/components/datetime-picker/datetime-picker.vue +235 -0
  13. package/components/dialog/dialog-content.vue +162 -0
  14. package/components/dialog/dialog.vue +166 -0
  15. package/components/dropdown/dropdown.vue +145 -0
  16. package/components/empty/empty.vue +102 -0
  17. package/components/flex/flex.vue +76 -0
  18. package/components/form/form.vue +43 -0
  19. package/components/form/mixin.js +13 -0
  20. package/components/form-item/form-item.vue +141 -0
  21. package/components/icon/icon.vue +114 -0
  22. package/components/image/image.vue +61 -0
  23. package/components/input/input.vue +154 -0
  24. package/components/input/password-input.vue +95 -0
  25. package/components/list-page/list-page.js +10 -0
  26. package/components/list-page/list-page.vue +150 -0
  27. package/components/load-more/load-more.vue +97 -0
  28. package/components/loading/animations/loading-animation1.vue +92 -0
  29. package/components/loading/animations/loading-animation2.vue +28 -0
  30. package/components/loading/animations/loading-animation3.vue +81 -0
  31. package/components/loading/animations/loading-animation4.vue +74 -0
  32. package/components/loading/loading.vue +91 -0
  33. package/components/message-box/message-box.vue +60 -0
  34. package/components/number-dialog/number-dialog.vue +360 -0
  35. package/components/number-input/number-input.vue +352 -0
  36. package/components/numpad/numpad.vue +224 -0
  37. package/components/page/page-body.vue +227 -0
  38. package/components/page/page-footer.vue +75 -0
  39. package/components/page/page-header.vue +222 -0
  40. package/components/page/page.vue +128 -0
  41. package/components/picker/picker-popup.vue +295 -0
  42. package/components/picker/picker.vue +151 -0
  43. package/components/popover/popover-content.vue +255 -0
  44. package/components/popover/popover-mask.vue +113 -0
  45. package/components/popover/popover.vue +84 -0
  46. package/components/popup/popup-content.vue +162 -0
  47. package/components/popup/popup.vue +168 -0
  48. package/components/price/price.vue +104 -0
  49. package/components/search/search.vue +220 -0
  50. package/components/searching/searching.vue +86 -0
  51. package/components/selector/selector.vue +86 -0
  52. package/components/switch/switch.vue +180 -0
  53. package/components/tab/tab.vue +235 -0
  54. package/components/table/table.vue +112 -0
  55. package/components/textarea/textarea.vue +192 -0
  56. package/components/time-picker/time-picker-view.vue +127 -0
  57. package/components/time-picker/time-picker.vue +140 -0
  58. package/components/uploader/download.js +81 -0
  59. package/components/uploader/file-uploader.vue +52 -0
  60. package/components/uploader/files.js +225 -0
  61. package/components/uploader/media-uploader.vue +133 -0
  62. package/components/uploader/mixin.js +106 -0
  63. package/components/uploader/uni.js +38 -0
  64. package/components/uploader/upload-button.vue +29 -0
  65. package/components/uploader/uploader copy.vue +547 -0
  66. package/components/uploader/uploader.vue +117 -0
  67. package/configs/index.js +41 -0
  68. package/easyCom.js +25 -0
  69. package/init.js +17 -0
  70. package/mixins/componentName.js +32 -0
  71. package/mixins/listPage.js +1 -0
  72. package/mixins/windowInfo.js +1 -0
  73. package/package.json +12 -0
  74. package/resources/iconfont/uniapp_ui_icon/demo.css +539 -0
  75. package/resources/iconfont/uniapp_ui_icon/demo_index.html +555 -0
  76. package/resources/iconfont/uniapp_ui_icon/iconfont.css +78 -0
  77. package/resources/iconfont/uniapp_ui_icon/iconfont.js +1 -0
  78. package/resources/iconfont/uniapp_ui_icon/iconfont.json +121 -0
  79. package/resources/iconfont/uniapp_ui_icon/iconfont.woff2 +0 -0
  80. package/resources/image/empty.svg +13 -0
  81. package/styles/global.scss +24 -0
  82. package/styles/index.scss +2 -0
  83. package/styles/utils/css-var.scss +87 -0
  84. package/styles/utils/ellipsis.scss +26 -0
  85. package/styles/utils/global-var.scss +11 -0
  86. package/styles/utils/index.scss +5 -0
  87. package/styles/utils/selector.scss +5 -0
  88. package/styles/utils/z-index.scss +10 -0
  89. package/styles/var/component.scss +242 -0
  90. package/styles/var/index.scss +2 -0
  91. package/styles/var/theme.scss +40 -0
  92. package/utils/date.js +151 -0
  93. package/utils/floor.js +20 -0
  94. package/utils/freezeDeep.js +19 -0
  95. package/utils/price.js +32 -0
  96. package/utils/round.js +22 -0
  97. package/utils/windowInfo.js +77 -0
@@ -0,0 +1,86 @@
1
+ <template>
2
+ <view :class="componentClassNames">
3
+ <image v-if="image" :src="image" :class="$style['Searching--image']" />
4
+ <view v-else :class="$style['Searching--search-icon-animation']">
5
+ <icon-cpn icon="search" :class="$style['Searching--search-icon']" />
6
+ </view>
7
+ <view :class="$style['Searching--text']">
8
+ <slot>{{ text }}</slot>
9
+ </view>
10
+ </view>
11
+ </template>
12
+
13
+ <script>
14
+ import componentName from '../../mixins/componentName';
15
+ import IconCpn from '../icon/icon.vue';
16
+
17
+ export default {
18
+ name: 'AppSearching',
19
+ options: {
20
+ virtualHost: true,
21
+ styleIsolation: 'shared',
22
+ },
23
+ components: { IconCpn },
24
+ mixins: [componentName],
25
+ props: {
26
+ /** 图片 */
27
+ image: {
28
+ type: String,
29
+ default: '',
30
+ },
31
+ /** 文本 */
32
+ text: {
33
+ type: String,
34
+ default: '数据加载中',
35
+ },
36
+ },
37
+ };
38
+ </script>
39
+
40
+ <style lang="scss" module>
41
+ @use '../../styles/index' as *;
42
+
43
+ // 自定义样式变量前缀,与组件名称一致
44
+ $component-prefix: '#{$ec-component-prefix}-searching';
45
+ // 自定义样式变量
46
+ %external-vars {
47
+ @include define-component-vars(
48
+ $image-size: 300rpx,
49
+ $image-width: var(--image-size),
50
+ $image-height: var(--image-size),
51
+ $space: get-value('size-m'),
52
+ $color: get-value('color-info'),
53
+ $font-size: get-value('size-font-m')
54
+ );
55
+ }
56
+
57
+ .Searching {
58
+ @extend %external-vars;
59
+ display: flex;
60
+ flex-direction: column;
61
+ justify-content: center;
62
+ align-items: center;
63
+ }
64
+ .Searching--image {
65
+ position: relative;
66
+ width: var(--image-width);
67
+ height: var(--image-height);
68
+ }
69
+ .Searching--search-icon-animation {
70
+ width: 100rpx;
71
+ height: 100rpx;
72
+ transform-origin: center center;
73
+ animation: circle 1.5s infinite linear;
74
+ }
75
+ .Searching--search-icon {
76
+ position: absolute;
77
+ font-size: 60rpx;
78
+ color: var(--color);
79
+ animation: circle 1.5s linear infinite reverse;
80
+ }
81
+ .Searching--text {
82
+ margin-top: var(--space);
83
+ color: var(--color);
84
+ font-size: var(--font-size);
85
+ }
86
+ </style>
@@ -0,0 +1,86 @@
1
+ <template>
2
+ <view :class="componentClassNames" @click="onClick">
3
+ <text v-if="isReadonly || value" :class="$style['Selector--text']">
4
+ <slot>
5
+ {{ value || '' }}
6
+ </slot>
7
+ </text>
8
+
9
+ <text v-else :class="[$style['Selector--text'], $style['Selector--placeholder']]">
10
+ {{ placeholder }}
11
+ </text>
12
+ <icon-cpn v-if="!isReadonly" icon="picker-arrow" :class="$style['Selector--icon']"></icon-cpn>
13
+ </view>
14
+ </template>
15
+
16
+ <script>
17
+ import componentName from '../../mixins/componentName';
18
+ import { isFormReadonly } from '../form/mixin';
19
+ import IconCpn from '../icon/icon.vue';
20
+
21
+ export default {
22
+ name: 'AppSelector',
23
+ options: {
24
+ virtualHost: true,
25
+ styleIsolation: 'shared',
26
+ },
27
+ components: { IconCpn },
28
+ mixins: [componentName, isFormReadonly],
29
+ props: {
30
+ /** 绑定值 */
31
+ value: {
32
+ type: [String, null],
33
+ default: '',
34
+ },
35
+ /** 是否禁用 */
36
+ disabled: {
37
+ type: Boolean,
38
+ default: false,
39
+ },
40
+ /** 是否只读 */
41
+ readonly: {
42
+ type: Boolean,
43
+ default: false,
44
+ },
45
+ /** 占位文本 */
46
+ placeholder: {
47
+ type: String,
48
+ default: '请选择',
49
+ },
50
+ },
51
+ computed: {
52
+ isReadonly() {
53
+ return this.readonly || this.isFormReadonly;
54
+ },
55
+ },
56
+ methods: {
57
+ onClick() {
58
+ if (this.disabled || this.isReadonly) {
59
+ return;
60
+ }
61
+ this.$emit('click');
62
+ },
63
+ },
64
+ };
65
+ </script>
66
+
67
+ <style lang="scss" module>
68
+ @use '../../styles/index' as *;
69
+
70
+ .Selector {
71
+ width: 100%;
72
+ height: 100%;
73
+ display: flex;
74
+ justify-content: flex-end;
75
+ align-items: center;
76
+ }
77
+ .Selector--text {
78
+ flex: 1;
79
+ }
80
+ .Selector--placeholder {
81
+ color: UTILS__GLOBAL_VAR(color, placeholder);
82
+ }
83
+ .Selector--icon {
84
+ color: UTILS__GLOBAL_VAR(color, placeholder);
85
+ }
86
+ </style>
@@ -0,0 +1,180 @@
1
+ <template>
2
+ <view
3
+ :class="[
4
+ componentClassNames,
5
+ {
6
+ [$style['Switch--disabled']]: disabled || loading,
7
+ [$style['Switch--switch-on']]: value === valueOn,
8
+ },
9
+ ]"
10
+ @click.stop="toggle"
11
+ >
12
+ <view :class="$style['Switch--switch-button']">
13
+ <icon-cpn v-if="loading" icon="loading-dot-spinner" :class="$style['Switch--loading']" />
14
+ </view>
15
+ </view>
16
+ </template>
17
+
18
+ <script>
19
+ import componentName from '../../mixins/componentName';
20
+ import { isFormReadonly } from '../form/mixin';
21
+ import IconCpn from '../icon/icon.vue';
22
+
23
+ export default {
24
+ name: 'AppSwitch',
25
+ options: {
26
+ virtualHost: true,
27
+ styleIsolation: 'shared',
28
+ },
29
+ components: { IconCpn },
30
+ mixins: [componentName, isFormReadonly],
31
+ props: {
32
+ /** 绑定值 */
33
+ value: {
34
+ type: [Boolean, Number, String],
35
+ default: false,
36
+ },
37
+ /** 是否异步事件 */
38
+ async: {
39
+ type: Boolean,
40
+ default: false,
41
+ },
42
+ /** 开启状态的值 */
43
+ valueOn: {
44
+ type: [Boolean, Number, String],
45
+ default: true,
46
+ },
47
+ /** 关闭状态的值 */
48
+ valueOff: {
49
+ type: [Boolean, Number, String],
50
+ default: false,
51
+ },
52
+ /** 是否禁用 */
53
+ disabled: {
54
+ type: Boolean,
55
+ default: false,
56
+ },
57
+ /** 是否只读 */
58
+ readonly: {
59
+ type: Boolean,
60
+ default: false,
61
+ },
62
+ },
63
+ data() {
64
+ return {
65
+ /** 是否加载中状态 */
66
+ loading: false,
67
+ };
68
+ },
69
+ computed: {
70
+ isReadonly() {
71
+ return this.readonly || this.isFormReadonly;
72
+ },
73
+ /** 按钮是否可点击 */
74
+ isNotClickable() {
75
+ return this.disabled || this.isReadonly || this.loading;
76
+ },
77
+ },
78
+ methods: {
79
+ /** 开启或关闭 */
80
+ toggle() {
81
+ if (this.isNotClickable) return;
82
+
83
+ if (!this.async) {
84
+ this.$_toggle();
85
+ return;
86
+ }
87
+
88
+ this.loading = true;
89
+ const nextValue = this.value !== this.valueOn ? this.valueOn : this.valueOff;
90
+ const { promise, resolve, reject } = Promise.withResolvers();
91
+ promise
92
+ .then((isOk = true) => {
93
+ if (isOk === false) return;
94
+ this.$_toggle();
95
+ })
96
+ .catch((err) => {
97
+ if (process.env.NODE_ENV === 'development') {
98
+ // eslint-disable-next-line no-console
99
+ console.warn(`${this.componentClass} unresolved error:`, err);
100
+ }
101
+ })
102
+ .finally(() => {
103
+ this.loading = false;
104
+ });
105
+ this.$emit('async', { value: nextValue, resolve, reject });
106
+ },
107
+ /** 开启或关闭,组件内部调用 */
108
+ $_toggle() {
109
+ if (this.value !== this.valueOn) {
110
+ this.$emit('input', this.valueOn);
111
+ } else {
112
+ this.$emit('input', this.valueOff);
113
+ }
114
+ },
115
+ },
116
+ };
117
+ </script>
118
+
119
+ <style lang="scss" module>
120
+ @use '../../styles/index' as *;
121
+
122
+ // 定义外部变量
123
+ $component-name: 'switch';
124
+ $component-vars: $switch;
125
+ %external-vars {
126
+ @include UTILS__DEFINE_COMPONENT_VARS();
127
+ }
128
+
129
+ .Switch {
130
+ @extend %external-vars;
131
+ position: relative;
132
+ width: UTILS__LOCAL_VAR(width);
133
+ height: UTILS__LOCAL_VAR(height);
134
+ border-radius: UTILS__LOCAL_VAR(height);
135
+ background-color: #ccc;
136
+ transition: background-color 0.3s;
137
+
138
+ .Switch--switch-button {
139
+ display: block;
140
+ position: absolute;
141
+ top: 50%;
142
+ left: calc((UTILS__LOCAL_VAR(height) - UTILS__LOCAL_VAR(indicator-size)) / 2);
143
+ transform: translateY(-50%);
144
+ width: UTILS__LOCAL_VAR(indicator-size);
145
+ height: UTILS__LOCAL_VAR(indicator-size);
146
+ border-radius: 50%;
147
+ background-color: #fff;
148
+ transition: left 0.3s;
149
+ }
150
+ .Switch--loading {
151
+ position: absolute;
152
+ top: 50%;
153
+ left: 50%;
154
+ font-size: calc(UTILS__LOCAL_VAR(indicator-size) * 0.7);
155
+ transform: translate(-50%, -50%);
156
+ transform-origin: 0 0;
157
+ color: UTILS__GLOBAL_VAR(color, foreground);
158
+ }
159
+ &.Switch--switch-on {
160
+ background-color: UTILS__LOCAL_VAR(active-color);
161
+ .Switch--switch-button {
162
+ left: calc(100% - (UTILS__LOCAL_VAR(height) + UTILS__LOCAL_VAR(indicator-size)) / 2);
163
+ }
164
+ }
165
+ &::after {
166
+ visibility: hidden;
167
+ opacity: 0;
168
+ content: '';
169
+ position: absolute;
170
+ inset: 0;
171
+ border-radius: UTILS__LOCAL_VAR(height);
172
+ background: #ffffff80;
173
+ transition: all 0.2s;
174
+ }
175
+ &.Switch--disabled::after {
176
+ visibility: visible;
177
+ opacity: 1;
178
+ }
179
+ }
180
+ </style>
@@ -0,0 +1,235 @@
1
+ <template>
2
+ <view :class="[componentClassNames, { [$style['Tab--evenly']]: evenly }]" :style="styleStr">
3
+ <scroll-view scroll-x :class="$style['Tab--tab-scroll']">
4
+ <view :class="$style['Tab--tab-wrapper']">
5
+ <view
6
+ v-for="(tab, index) in tabLabels"
7
+ :key="index"
8
+ :class="[[$style['Tab--tab']], { [$style['Tab--tab-active']]: index === tabIndex }]"
9
+ @click="onChangeTab(index)"
10
+ >
11
+ <view :class="$style['Tab--tab-text']">{{ tab }}</view>
12
+ </view>
13
+ <view
14
+ v-if="indicator"
15
+ :class="[$style['Tab--indicator'], { [$style['Tab--initialing']]: !initialized }]"
16
+ >
17
+ </view>
18
+ </view>
19
+ </scroll-view>
20
+ </view>
21
+ </template>
22
+
23
+ <script>
24
+ import componentName from '../../mixins/componentName';
25
+
26
+ export default {
27
+ name: 'AppTab',
28
+ options: {
29
+ virtualHost: true,
30
+ styleIsolation: 'shared',
31
+ },
32
+ mixins: [componentName],
33
+ props: {
34
+ value: {
35
+ type: [String, Number, null],
36
+ default: null,
37
+ },
38
+ tabs: {
39
+ type: Array,
40
+ default: () => [],
41
+ },
42
+ /** 是否均分大小 */
43
+ evenly: {
44
+ type: Boolean,
45
+ default: true,
46
+ },
47
+ /** 是否显示指示器 */
48
+ indicator: {
49
+ type: Boolean,
50
+ default: true,
51
+ },
52
+ },
53
+ data() {
54
+ return {
55
+ /** 组件内部记录的索引值 */
56
+ innerIndex: 0,
57
+ /** 左边距 */
58
+ boundingLeft: 0,
59
+ /** 标签的绘制信息 */
60
+ tabRects: [],
61
+ /** 是否已初始化 */
62
+ initialized: false,
63
+ };
64
+ },
65
+ computed: {
66
+ /** 当前选中的索引 */
67
+ selectedIndex: {
68
+ get: function () {
69
+ return this.value === null ? this.innerIndex : this.value;
70
+ },
71
+ set: function (value) {
72
+ this.$emit('input', value);
73
+ this.innerIndex = value;
74
+ this.$emit('change', this.innerIndex);
75
+ },
76
+ },
77
+ isTabsNotEmpty() {
78
+ return this.tabs && this.tabs.length > 0;
79
+ },
80
+ isStringTabs() {
81
+ return this.tabs.every((item) => typeof item === 'string');
82
+ },
83
+ tabLabels() {
84
+ return this.tabs.map((item) => (typeof item === 'string' ? item : item.label));
85
+ },
86
+ /** 当前值对应的索引 */
87
+ tabIndex() {
88
+ if (!this.isTabsNotEmpty) return 0;
89
+ return this.isStringTabs
90
+ ? Number(this.selectedIndex) || 0
91
+ : this.tabs.findIndex((item) => item.value === this.selectedIndex);
92
+ },
93
+ /** 指示器宽度 */
94
+ indicatorWidth() {
95
+ const rect = this.tabRects[this.tabIndex];
96
+ if (!rect) return 0;
97
+ return rect.width;
98
+ },
99
+ /** 指示器中心点 */
100
+ indicatorCenter() {
101
+ const rect = this.tabRects[this.tabIndex];
102
+ if (!rect) return 0;
103
+ return rect.left + rect.width / 2 - this.boundingLeft;
104
+ },
105
+ styleStr() {
106
+ return [
107
+ `--tab-count: ${this.tabs.length};`,
108
+ `--tab-text-width: ${this.indicatorWidth}px;`,
109
+ `--indicator-center: ${this.indicatorCenter}px;`,
110
+ ].join(' ');
111
+ },
112
+ },
113
+ watch: {
114
+ tabs: {
115
+ handler() {
116
+ if (this.isStringTabs) {
117
+ this.selectedIndex = Math.min(this.selectedIndex, this.tabs.length - 1);
118
+ return;
119
+ }
120
+ if (this.isTabsNotEmpty && this.tabIndex < 0) {
121
+ this.selectedIndex = this.tabs[0].value;
122
+ }
123
+ },
124
+ immediate: true,
125
+ },
126
+ },
127
+ mounted() {
128
+ uni.createSelectorQuery()
129
+ .in(this)
130
+ .select('.' + this.$style['Tab--tab-wrapper'])
131
+ .boundingClientRect((rect) => {
132
+ this.boundingLeft = rect.left;
133
+ })
134
+ .exec();
135
+ uni.createSelectorQuery()
136
+ .in(this)
137
+ .selectAll('.' + this.$style['Tab--tab-text'])
138
+ .boundingClientRect((rects) => {
139
+ if (!rects[this.tabIndex]) return;
140
+ this.tabRects = rects;
141
+ this.$nextTick(() => {
142
+ this.initialized = true;
143
+ });
144
+ })
145
+ .exec();
146
+ },
147
+ methods: {
148
+ /** 改变标签响应 */
149
+ onChangeTab(index) {
150
+ if (this.isStringTabs) {
151
+ if (this.selectedIndex === index) return;
152
+
153
+ this.selectedIndex = index;
154
+ } else {
155
+ if (this.selectedIndex === this.tabs[index].value) return;
156
+
157
+ this.selectedIndex = this.tabs[index].value;
158
+ }
159
+ this.$emit('change', this.selectedIndex);
160
+ },
161
+ },
162
+ };
163
+ </script>
164
+
165
+ <style lang="scss" module>
166
+ @use '../../styles/index' as *;
167
+
168
+ // 定义外部变量
169
+ $component-name: 'tab';
170
+ $component-vars: $tab;
171
+ %external-vars {
172
+ @include UTILS__DEFINE_COMPONENT_VARS();
173
+ }
174
+
175
+ :host {
176
+ display: block;
177
+ }
178
+
179
+ .Tab {
180
+ @extend %external-vars;
181
+ height: UTILS__LOCAL_VAR(height);
182
+ background: UTILS__LOCAL_VAR(background);
183
+ border-radius: UTILS__LOCAL_VAR(border-radius);
184
+ }
185
+ .Tab--evenly {
186
+ $tab-width: calc(100% / var(--tab-count));
187
+ .Tab--tab {
188
+ flex: auto;
189
+ width: $tab-width;
190
+ }
191
+ }
192
+ .Tab--tab-scroll,
193
+ .Tab--tab-wrapper {
194
+ height: 100%;
195
+ }
196
+ .Tab--tab-wrapper {
197
+ position: relative;
198
+ display: flex;
199
+ align-items: center;
200
+ }
201
+ .Tab--tab {
202
+ height: 100%;
203
+ padding: UTILS__LOCAL_VAR(tab-padding);
204
+ flex: none;
205
+ display: flex;
206
+ justify-content: center;
207
+ align-items: center;
208
+ color: UTILS__LOCAL_VAR(color);
209
+ font-size: UTILS__LOCAL_VAR(font-size);
210
+ font-weight: UTILS__LOCAL_VAR(font-weight);
211
+ transition: color 0.3s;
212
+ &:not(:first-child) {
213
+ margin-left: UTILS__LOCAL_VAR(tab-gaps);
214
+ }
215
+ }
216
+ .Tab--tab-active {
217
+ color: UTILS__LOCAL_VAR(active-color);
218
+ }
219
+ .Tab--tab-text {
220
+ font-size: inherit;
221
+ }
222
+ .Tab--indicator {
223
+ position: absolute;
224
+ bottom: 0;
225
+ height: 10rpx;
226
+ border-radius: 10rpx;
227
+ background: UTILS__LOCAL_VAR(indicator-color);
228
+ transform: translateX(-50%);
229
+ &:not(.Tab--initialing) {
230
+ left: var(--indicator-center);
231
+ width: UTILS__LOCAL_VAR(indicator-width, var(--tab-text-width));
232
+ transition: left 0.3s, width 0.3s;
233
+ }
234
+ }
235
+ </style>
@@ -0,0 +1,112 @@
1
+ <template>
2
+ <view :class="componentClassNames">
3
+ <view :class="[$style['Table--row'], $style['Table--header']]">
4
+ <view
5
+ v-for="(h, i) in headers"
6
+ :key="i"
7
+ :class="[$style['Table--cell'], $style['Table--cell-align'] + (aligns[i] || 2)]"
8
+ >
9
+ <view>{{ h }}</view>
10
+ </view>
11
+ </view>
12
+ <view v-for="(row, i) in value" :key="i" :class="$style['Table--row']">
13
+ <view
14
+ v-for="(col, j) in row"
15
+ :key="j"
16
+ :class="[$style['Table--cell'], $style['Table--cell-align'] + (aligns[j] || 2)]"
17
+ :style="i === 0 && j < row.length - 1 ? { width: widths[j] || colWidth } : ''"
18
+ >
19
+ <view>{{ col }}</view>
20
+ </view>
21
+ </view>
22
+ </view>
23
+ </template>
24
+
25
+ <script>
26
+ import componentName from '../../mixins/componentName';
27
+ import { floor2 } from '../../utils/floor';
28
+
29
+ export default {
30
+ name: 'AppTable',
31
+ options: {
32
+ virtualHost: true,
33
+ styleIsolation: 'shared',
34
+ },
35
+ mixins: [componentName],
36
+ props: {
37
+ /** 各个列的数据 */
38
+ value: {
39
+ type: Array,
40
+ default: () => [],
41
+ },
42
+ /** 定义各个列的表头 */
43
+ headers: {
44
+ type: Array,
45
+ default: () => [],
46
+ },
47
+ /** 定义各个列的对齐方式,默认居中对齐,1左对齐,2居中,3右对齐 */
48
+ aligns: {
49
+ type: Array,
50
+ default: () => [],
51
+ },
52
+ /** 定义各个列的宽度百分比 */
53
+ widths: {
54
+ type: Array,
55
+ default: () => [],
56
+ },
57
+ },
58
+ computed: {
59
+ /** 总列数 */
60
+ colCount() {
61
+ return this.value[0]?.length || 0;
62
+ },
63
+ /** 每列所占宽度百分比 */
64
+ colWidth() {
65
+ return floor2(100 / this.colCount) + '%';
66
+ },
67
+ },
68
+ };
69
+ </script>
70
+
71
+ <style lang="scss" module>
72
+ @use '../../styles/index' as *;
73
+
74
+ // 自定义样式变量前缀,与组件名称一致
75
+ $component-prefix: '#{$ec-component-prefix}-table';
76
+ // 自定义样式变量
77
+ %external-vars {
78
+ @include define-component-vars($cell-padding: get-value('size-l') get-value('size-xxs'));
79
+ }
80
+
81
+ .Table {
82
+ @extend %external-vars;
83
+ display: table;
84
+ width: 100%;
85
+ border: 2rpx solid get-value('color-background');
86
+ border-radius: get-value('size-radius-s');
87
+ overflow: hidden;
88
+ }
89
+ .Table--header {
90
+ color: get-value('color-info-6');
91
+ }
92
+ .Table--row {
93
+ display: table-row;
94
+ &:nth-child(odd) {
95
+ background: get-value('color-background');
96
+ }
97
+ }
98
+ .Table--cell {
99
+ display: table-cell;
100
+ padding: var(--cell-padding);
101
+ vertical-align: middle;
102
+ }
103
+ .Table--cell-align1 {
104
+ text-align: start;
105
+ }
106
+ .Table--cell-align2 {
107
+ text-align: center;
108
+ }
109
+ .Table--cell-align3 {
110
+ text-align: end;
111
+ }
112
+ </style>