@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,224 @@
1
+ <template>
2
+ <view :class="componentClassNames">
3
+ <button-cpn
4
+ v-for="btn in buttons"
5
+ :key="btn.key"
6
+ :cool-down="0"
7
+ :class="[$style['Numpad--key'], $style[btn.className]]"
8
+ @click="onClick(btn)"
9
+ >
10
+ <icon-cpn v-if="btn.icon" :icon="btn.icon" />
11
+ <text v-else>{{ btn.title || btn.key }}</text>
12
+ </button-cpn>
13
+ </view>
14
+ </template>
15
+
16
+ <script>
17
+ import componentName from '../../mixins/componentName';
18
+ import { freezeDeep } from '../../utils/freezeDeep';
19
+ import ButtonCpn from '../button/button.vue';
20
+ import IconCpn from '../icon/icon.vue';
21
+
22
+ /** 默认最小值 */
23
+ const MIN = 0;
24
+ /** 默认最大值 */
25
+ const MAX = 9999;
26
+
27
+ const buttons = freezeDeep([
28
+ { key: '1', type: 'number' },
29
+ { key: '2', type: 'number' },
30
+ { key: '3', type: 'number' },
31
+ { key: 'delete', type: 'delete', icon: 'play' },
32
+ { key: '4', type: 'number' },
33
+ { key: '5', type: 'number' },
34
+ { key: '6', type: 'number' },
35
+ { key: 'clear', type: 'clear', title: '清空' },
36
+ { key: '7', type: 'number' },
37
+ { key: '8', type: 'number' },
38
+ { key: '9', type: 'number' },
39
+ { key: '-', type: '-', title: '+/-', className: 'Numpad--negative-key' },
40
+ { key: '.', type: 'dot' },
41
+ { key: '0', type: 'number', className: 'Numpad--zero-key' },
42
+ ]);
43
+
44
+ export default {
45
+ name: 'AppNumpad',
46
+ options: {
47
+ virtualHost: true,
48
+ styleIsolation: 'shared',
49
+ },
50
+ components: { ButtonCpn, IconCpn },
51
+ mixins: [componentName],
52
+ props: {
53
+ /** 绑定值 */
54
+ value: {
55
+ type: [String, Number],
56
+ default: '',
57
+ },
58
+ /** 小数的精度 */
59
+ precision: {
60
+ type: Number,
61
+ default: 0,
62
+ },
63
+ /** 允许输入的最大值 */
64
+ max: {
65
+ type: Number,
66
+ default: MAX,
67
+ },
68
+ /** 允许输入的最小值 */
69
+ min: {
70
+ type: Number,
71
+ default: MIN,
72
+ },
73
+ },
74
+ data() {
75
+ return {
76
+ buttons,
77
+ };
78
+ },
79
+ computed: {
80
+ editValue: {
81
+ get() {
82
+ return this.value || this.value === 0 ? this.value.toString() : '';
83
+ },
84
+ set(val) {
85
+ this.$emit('input', val);
86
+ },
87
+ },
88
+ },
89
+ created() {},
90
+ methods: {
91
+ /** 点击按钮 */
92
+ onClick(btn) {
93
+ switch (btn.type) {
94
+ case 'number':
95
+ this.onInputNumber(btn.key);
96
+ break;
97
+ case 'dot':
98
+ this.onInputDot();
99
+ break;
100
+ case '-':
101
+ this.onNegative();
102
+ break;
103
+ case 'delete':
104
+ this.onDelete();
105
+ break;
106
+ case 'clear':
107
+ this.onClear();
108
+ break;
109
+ }
110
+ },
111
+ /** 输入数字 */
112
+ onInputNumber(key) {
113
+ const nextValue = this.editValue + key;
114
+ if (Number(nextValue) <= this.min) {
115
+ this.editValue = this.min + '';
116
+ return;
117
+ }
118
+ if (Number(nextValue) >= this.max) {
119
+ this.editValue = this.max + '';
120
+ return;
121
+ }
122
+
123
+ if (this.editValue === '0') {
124
+ if (key === '0') return;
125
+ this.editValue = key;
126
+ return;
127
+ }
128
+
129
+ if (this.precision > 0 && this.editValue.includes('.')) {
130
+ const decimalPart = this.editValue.split('.')[1];
131
+ if (decimalPart.length >= this.precision) {
132
+ return;
133
+ }
134
+ }
135
+
136
+ this.editValue += key;
137
+ },
138
+ /** 输入小数点 */
139
+ onInputDot() {
140
+ if (this.precision <= 0) return;
141
+ if (this.editValue.includes('.')) return;
142
+
143
+ if (this.editValue) {
144
+ this.editValue += '.';
145
+ } else {
146
+ this.editValue = '0.';
147
+ }
148
+ },
149
+ /** 负号 */
150
+ onNegative() {
151
+ if (this.min >= 0) return;
152
+
153
+ const nextValue = -this.editValue;
154
+ if (nextValue < this.min) {
155
+ this.editValue = this.min + '';
156
+ return;
157
+ }
158
+ if (nextValue > this.max) {
159
+ this.editValue = this.max + '';
160
+ return;
161
+ }
162
+
163
+ if (this.editValue.startsWith('-')) {
164
+ this.editValue = this.editValue.slice(1);
165
+ } else {
166
+ this.editValue = '-' + this.editValue;
167
+ }
168
+ },
169
+ /** 删除 */
170
+ onDelete() {
171
+ if (!this.editValue) return;
172
+
173
+ this.editValue = this.editValue.slice(0, -1);
174
+ },
175
+ /** 清空 */
176
+ onClear() {
177
+ this.editValue = '';
178
+ },
179
+ // onConfirm() {
180
+ // this.$emit('input', false);
181
+ // this.$emit('confirm', { value: this.editValue, number: Number(this.editValue) });
182
+ // },
183
+ },
184
+ };
185
+ </script>
186
+
187
+ <style lang="scss" module>
188
+ @use '../../styles/index' as *;
189
+
190
+ // 定义外部变量
191
+ $component-name: 'numpad';
192
+ $component-vars: $numpad;
193
+ %external-vars {
194
+ @include UTILS__DEFINE_COMPONENT_VARS();
195
+ }
196
+
197
+ .Numpad {
198
+ @extend %external-vars;
199
+ width: 100%;
200
+ height: 400rpx;
201
+ display: grid;
202
+ gap: 12rpx 12rpx;
203
+ grid-auto-flow: row;
204
+ grid-template-columns: repeat(3, 4fr) 3fr;
205
+
206
+ .Numpad--key {
207
+ width: 100%;
208
+ height: 100%;
209
+ font-size: 38rpx;
210
+ box-shadow: 2px 2px 4px 0 #00000040;
211
+ &:not(.Numpad--confirm-key) {
212
+ color: UTILS__GLOBAL_VAR(color, foreground);
213
+ #{UTILS__VAR_NAME(theme, button)}: white;
214
+ #{UTILS__VAR_NAME(active-mask, button)}: UTILS__GLOBAL_VAR(theme, primary);
215
+ }
216
+ }
217
+ .Numpad--zero-key {
218
+ grid-area: auto / span 2;
219
+ }
220
+ .Numpad--negative-key {
221
+ grid-area: span 2 / auto;
222
+ }
223
+ }
224
+ </style>
@@ -0,0 +1,227 @@
1
+ <template>
2
+ <view
3
+ :class="[componentClassNames, useScroll ? $style['PageBody--with-scroll'] : $style['PageBody--no-scroll']]"
4
+ :style="styleStr"
5
+ >
6
+ <!-- 不使用 scroll-view ,即直接使用 Page 的滚动功能 -->
7
+ <view v-if="!useScroll" :class="$style['PageBody--body']">
8
+ <view :class="$style['PageBody--content']">
9
+ <slot></slot>
10
+ </view>
11
+ </view>
12
+ <scroll-view
13
+ v-else-if="enableRefresh"
14
+ scroll-y
15
+ refresher-enabled
16
+ :refresher-triggered="refreshing"
17
+ :scroll-with-animation="scrollWithAnimation"
18
+ :scroll-top="scrollTop"
19
+ :class="$style['PageBody--scroll-body']"
20
+ @refresherrefresh="$emit('refresh')"
21
+ @scroll="$_handleScroll"
22
+ @scrolltolower="$emit('reach-bottom')"
23
+ >
24
+ <view :class="$style['PageBody--content']">
25
+ <slot></slot>
26
+ </view>
27
+ </scroll-view>
28
+ <scroll-view
29
+ v-else
30
+ scroll-y
31
+ :scroll-with-animation="scrollWithAnimation"
32
+ :scroll-top="scrollTop"
33
+ :class="$style['PageBody--scroll-body']"
34
+ @scroll="$_handleScroll"
35
+ @scrolltolower="$emit('reach-bottom')"
36
+ >
37
+ <view :class="$style['PageBody--content']">
38
+ <slot></slot>
39
+ </view>
40
+ </scroll-view>
41
+ </view>
42
+ </template>
43
+
44
+ <script>
45
+ /**
46
+ * 页面内容部分容器组件,不单独使用,通过 page 组件间接引入
47
+ */
48
+
49
+ import debounce from 'lodash-es/debounce';
50
+ import componentName from '../../mixins/componentName';
51
+ import windowInfoMixin from '../../mixins/windowInfo';
52
+
53
+ /** 滚动动画持续时长 */
54
+ const SCROLL_ANIMATION_DURATION = 300;
55
+
56
+ export default {
57
+ name: 'AppPageBody',
58
+ options: {
59
+ virtualHost: true,
60
+ styleIsolation: 'shared',
61
+ },
62
+ mixins: [componentName, windowInfoMixin],
63
+ props: {
64
+ /** 是否有自定义导航头 */
65
+ hasCustomNav: {
66
+ type: Boolean,
67
+ default: true,
68
+ },
69
+ /** 是否有底部区域 */
70
+ hasFooter: {
71
+ type: Boolean,
72
+ default: false,
73
+ },
74
+ /** 是否使用scroll-view */
75
+ useScroll: {
76
+ type: Boolean,
77
+ default: false,
78
+ },
79
+ /** 是否是 tab 页 */
80
+ isTabPage: {
81
+ type: Boolean,
82
+ default: false,
83
+ },
84
+ /** 是否启用下拉刷新,仅 useScroll 为 true 时有效 */
85
+ enableRefresh: {
86
+ type: Boolean,
87
+ default: false,
88
+ },
89
+ /** 是否触发下拉刷新,仅 useScroll 为 true 时有效 */
90
+ refreshing: {
91
+ type: Boolean,
92
+ default: false,
93
+ },
94
+ },
95
+ data() {
96
+ return {
97
+ /** scroll-view 的当前滚动距离 */
98
+ scrollOffset: 0,
99
+ /** 传递给 scroll-view ,用于控制其滚动距离 */
100
+ scrollTop: 0,
101
+ /** 传递给 scroll-view ,用于控制其是否有滚动动画 */
102
+ scrollWithAnimation: true,
103
+ };
104
+ },
105
+ computed: {
106
+ styleStr() {
107
+ return [
108
+ `--header-bar-bottom: ${this.navBarBottomOffset}px;`,
109
+ `--safe-area-bottom: ${this.isTabPage ? 0 : this.safeAreaInsetBottom}px;`,
110
+ ...(this.hasCustomNav ? [] : ['--header-placeholder-height: 0px;']),
111
+ ...(this.hasFooter
112
+ ? ['--bottom-safe-height: 0px;']
113
+ : ['--footer-placeholder-height: 0px;', '--bottom-safe-height: var(--safe-area-bottom);']),
114
+ ].join(' ');
115
+ },
116
+ },
117
+ methods: {
118
+ $_debounceScroll: debounce(function () {
119
+ uni.createSelectorQuery()
120
+ /* #ifndef MP-ALIPAY */
121
+ .in(this)
122
+ /* #endif */
123
+ .select('.' + this.$style['PageBody--scroll-body'])
124
+ .fields({ size: true, scrollOffset: true }, (data) => {
125
+ if (data.scrollHeight - data.height - data.scrollTop <= 50) {
126
+ this.$emit('reach-bottom');
127
+ }
128
+ })
129
+ .exec();
130
+ }, 100),
131
+ /** 处理 scroll-view 滚动 */
132
+ $_handleScroll(e) {
133
+ this.scrollOffset = e.detail.scrollTop;
134
+ this.$emit('scroll', e.detail);
135
+ if (this.useScroll) {
136
+ this.$_debounceScroll(this.loadedPages);
137
+ }
138
+ },
139
+ /** 滚动到顶部
140
+ * @param {number} position 滚动到与顶部的距离
141
+ * @param {boolean} animation 是否有滚动动画
142
+ */
143
+ scrollToTop(position = 0, animation = true) {
144
+ if (this.useScroll) {
145
+ this.scrollWithAnimation = animation;
146
+ this.$nextTick(() => {
147
+ this.scrollTop = typeof this.scrollTop === 'number' ? position + 'px' : position;
148
+ this.scrollOffset = position;
149
+ setTimeout(() => {
150
+ this.scrollWithAnimation = true;
151
+ }, SCROLL_ANIMATION_DURATION);
152
+ });
153
+ } else {
154
+ uni.pageScrollTo({
155
+ scrollTop: position,
156
+ duration: animation ? SCROLL_ANIMATION_DURATION : 0,
157
+ });
158
+ }
159
+ },
160
+ },
161
+ };
162
+ </script>
163
+
164
+ <style lang="scss" module>
165
+ @use '../../styles/index' as *;
166
+
167
+ // 定义外部变量
168
+ $component-name: 'page-body';
169
+ $component-vars: $page-body;
170
+ %external-vars {
171
+ @include UTILS__DEFINE_COMPONENT_VARS();
172
+ }
173
+
174
+ :host {
175
+ display: block;
176
+ }
177
+
178
+ .PageBody {
179
+ @extend %external-vars;
180
+
181
+ --header-placeholder-height: calc(var(--header-bar-bottom) + #{UTILS__VAR(extra-height, page-header, 0px)});
182
+ --footer-placeholder-height: calc(var(--safe-area-bottom) + #{UTILS__VAR(height, page-footer, 100rpx)});
183
+
184
+ box-sizing: border-box;
185
+ padding-top: var(--header-placeholder-height);
186
+ padding-bottom: var(--footer-placeholder-height);
187
+ &.PageBody--with-scroll {
188
+ height: 100vh;
189
+ }
190
+ &.PageBody--no-scroll {
191
+ min-height: 100vh;
192
+ display: flex;
193
+ }
194
+ }
195
+
196
+ .PageBody--body {
197
+ position: relative;
198
+ background: UTILS__LOCAL_VAR(background);
199
+ width: 100%;
200
+ padding-bottom: var(--bottom-safe-height);
201
+ box-sizing: border-box;
202
+
203
+ display: flex;
204
+ flex-direction: column;
205
+ }
206
+ .PageBody--scroll-body {
207
+ position: relative;
208
+ background: UTILS__LOCAL_VAR(background);
209
+ width: 100%;
210
+ height: 100%;
211
+ }
212
+
213
+ .PageBody--content {
214
+ position: relative;
215
+ width: 100%;
216
+ min-height: 100%;
217
+ padding: UTILS__LOCAL_VAR(padding-y) UTILS__LOCAL_VAR(padding-x);
218
+ box-sizing: border-box;
219
+
220
+ flex: 1;
221
+ display: flex;
222
+ flex-direction: column;
223
+ .PageBody--scroll-body & {
224
+ padding-bottom: calc(var(--padding-y) + var(--bottom-safe-height));
225
+ }
226
+ }
227
+ </style>
@@ -0,0 +1,75 @@
1
+ <template>
2
+ <view :class="componentClassNames" :style="styleStr" @touchmove.stop.prevent="doNothing">
3
+ <view :class="$style['PageFooter--content']">
4
+ <slot></slot>
5
+ </view>
6
+ </view>
7
+ </template>
8
+
9
+ <script>
10
+ /**
11
+ * 页面页脚部分容器组件,不单独使用,通过 page 组件间接引入
12
+ */
13
+
14
+ import componentName from '../../mixins/componentName';
15
+ import windowInfoMixin from '../../mixins/windowInfo';
16
+
17
+ export default {
18
+ name: 'AppPageFooter',
19
+ options: {
20
+ virtualHost: true,
21
+ styleIsolation: 'shared',
22
+ },
23
+ mixins: [componentName, windowInfoMixin],
24
+ props: {
25
+ /** 是否是 tab 页 */
26
+ isTabPage: {
27
+ type: Boolean,
28
+ default: false,
29
+ },
30
+ },
31
+ computed: {
32
+ styleStr() {
33
+ return `--safe-area-bottom: ${(this.isTabPage ? 0 : this.safeAreaInsetBottom) + 'px'};`;
34
+ },
35
+ },
36
+ methods: {
37
+ doNothing() {},
38
+ },
39
+ };
40
+ </script>
41
+
42
+ <style lang="scss" module>
43
+ @use '../../styles/index' as *;
44
+
45
+ // 定义外部变量
46
+ $component-name: 'page-footer';
47
+ $component-vars: $page-footer;
48
+ %external-vars {
49
+ @include UTILS__DEFINE_COMPONENT_VARS();
50
+ }
51
+
52
+ :host {
53
+ display: block;
54
+ }
55
+
56
+ .PageFooter {
57
+ @extend %external-vars;
58
+ position: fixed;
59
+ bottom: 0;
60
+ left: 0;
61
+ right: 0;
62
+ background: UTILS__LOCAL_VAR(background);
63
+ padding-bottom: var(--safe-area-bottom);
64
+ box-sizing: border-box;
65
+ z-index: UTILS__z-index();
66
+ box-shadow: 0 -4rpx 4rpx 4rpx #ccc;
67
+ }
68
+
69
+ // 将内容占满空间
70
+ .PageFooter--content {
71
+ height: UTILS__LOCAL_VAR(height);
72
+ padding: 0 UTILS__LOCAL_VAR(spacing-horizontal);
73
+ box-sizing: border-box;
74
+ }
75
+ </style>