v-uni-app-ui 1.0.2 → 1.0.6

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 (65) hide show
  1. package/README.md +127 -0
  2. package/dist/v-uni-app-ui.css +1 -0
  3. package/dist/v-uni-app-ui.es.js +6569 -0
  4. package/dist/v-uni-app-ui.umd.js +7 -0
  5. package/package.json +28 -8
  6. package/components/config.js +0 -123
  7. package/components/layout/v-card/v-card.vue +0 -108
  8. package/components/layout/v-grid/v-grid.vue +0 -162
  9. package/components/layout/v-icon-grid/v-icon-grid.vue +0 -195
  10. package/components/layout/v-infinite-scroll/v-infinite-scroll.vue +0 -172
  11. package/components/layout/v-list/v-list.vue +0 -43
  12. package/components/layout/v-row/v-row.vue +0 -142
  13. package/components/layout/v-waterfall/v-waterfall.vue +0 -79
  14. package/components/model/compound/v-checkbox-group/v-checkbox-group.vue +0 -96
  15. package/components/model/compound/v-console/v-console.js +0 -20
  16. package/components/model/compound/v-console/v-console.vue +0 -299
  17. package/components/model/compound/v-date-time/v-date-time.vue +0 -261
  18. package/components/model/compound/v-dialog/v-dialog.vue +0 -178
  19. package/components/model/compound/v-drum-select-picker/v-drum-select-picker.vue +0 -83
  20. package/components/model/compound/v-form/v-form.vue +0 -226
  21. package/components/model/compound/v-form-item/v-form-item.vue +0 -255
  22. package/components/model/compound/v-image/v-image.vue +0 -357
  23. package/components/model/compound/v-input-desensitize/v-input-desensitize.vue +0 -101
  24. package/components/model/compound/v-page/v-page.vue +0 -11
  25. package/components/model/compound/v-pages/v-pages.vue +0 -141
  26. package/components/model/compound/v-picker-list/v-picker-list.vue +0 -109
  27. package/components/model/compound/v-popup/v-popup.vue +0 -151
  28. package/components/model/compound/v-radio-group/v-radio-group.vue +0 -86
  29. package/components/model/compound/v-select-picker/v-select-picker.vue +0 -202
  30. package/components/model/compound/v-series-picker-list/v-series-picker-list.vue +0 -221
  31. package/components/model/compound/v-series-select-picker/v-series-select-picker.vue +0 -203
  32. package/components/model/compound/v-switch/v-switch.vue +0 -136
  33. package/components/model/compound/v-tabs-page/v-tabs-page.vue +0 -138
  34. package/components/model/native/v-badge/v-badge.vue +0 -143
  35. package/components/model/native/v-button/v-button.vue +0 -273
  36. package/components/model/native/v-carousel/v-carousel.vue +0 -138
  37. package/components/model/native/v-checkbox/v-checkbox.vue +0 -215
  38. package/components/model/native/v-collapse/v-collapse.vue +0 -190
  39. package/components/model/native/v-header-navigation-bar/v-header-navigation-bar.vue +0 -92
  40. package/components/model/native/v-input/v-input.vue +0 -352
  41. package/components/model/native/v-input-code/v-input-code.vue +0 -146
  42. package/components/model/native/v-loading/v-loading.vue +0 -206
  43. package/components/model/native/v-menu/v-menu.vue +0 -222
  44. package/components/model/native/v-menu-slide/v-menu-slide.vue +0 -364
  45. package/components/model/native/v-min-loading/v-min-loading.vue +0 -80
  46. package/components/model/native/v-null/v-null.vue +0 -97
  47. package/components/model/native/v-overlay/v-overlay.vue +0 -96
  48. package/components/model/native/v-pull-up-refresh/v-pull-up-refresh.vue +0 -157
  49. package/components/model/native/v-radio/v-radio.vue +0 -138
  50. package/components/model/native/v-scroll-list/v-scroll-list.vue +0 -169
  51. package/components/model/native/v-steps/v-steps.vue +0 -253
  52. package/components/model/native/v-table/v-table.vue +0 -203
  53. package/components/model/native/v-tabs/v-tabs.vue +0 -235
  54. package/components/model/native/v-tag/v-tag.vue +0 -206
  55. package/components/model/native/v-text/v-text.vue +0 -187
  56. package/components/model/native/v-text-button/v-text-button.vue +0 -139
  57. package/components/model/native/v-textarea/v-textarea.vue +0 -178
  58. package/components/model/native/v-title/v-title.vue +0 -91
  59. package/components/model/native/v-toast/info.png +0 -0
  60. package/components/model/native/v-toast/success.png +0 -0
  61. package/components/model/native/v-toast/v-toast.vue +0 -198
  62. package/components/model/native/v-toast/warn.png +0 -0
  63. package/components/model/native/v-upload-file-button/v-upload-file-button.vue +0 -296
  64. package/components/model/native/v-video/v-video.vue +0 -175
  65. package/components/model/native/v-window/v-window.vue +0 -158
@@ -1,146 +0,0 @@
1
- <template>
2
- <div class="v-input-code">
3
- <div class="input-box" :style="{ width: `${inputWidth * length + (length - 1) * 20}px`, height: `${inputHeight}px` }">
4
- <input
5
- v-for="(item, index) in length"
6
- :key="index"
7
- type="text"
8
- :class="['input-item', { 'input-focus': focusIndex === index }]"
9
- :maxlength="1"
10
- :placeholder="placeholder"
11
- @input="onInput(index, $event)"
12
- @focus="onFocus(index)"
13
- @blur="onBlur(index)"
14
- @keydown="onkeydown(index, $event)"
15
- :focus="inputFocus[index]"
16
- :blur="inputBlur[index]"
17
- />
18
- </div>
19
- </div>
20
- </template>
21
-
22
- <script lang="ts" setup>
23
- import { ref, watch, onMounted, inject } from 'vue';
24
-
25
- const props = defineProps({
26
- value: {
27
- type: String,
28
- default: ''
29
- },
30
- length: {
31
- type: Number,
32
- default: 4
33
- },
34
- inputWidth: {
35
- type: Number,
36
- default: 30
37
- },
38
- inputHeight: {
39
- type: Number,
40
- default: 50
41
- },
42
- focus: {
43
- type: Boolean,
44
- default: false
45
- },
46
- placeholder: {
47
- type: String,
48
- default: ''
49
- }
50
- });
51
-
52
- const emit = defineEmits(['update:value', 'complete']);
53
-
54
- const config = inject<any>('config');
55
- const focusIndex = ref<number | null>(null);
56
- const inputFocus = ref([]);
57
- const inputBlur = ref([]);
58
-
59
- onMounted(() => {
60
- inputFocus.value.length = props.length;
61
- inputBlur.value.length = props.length;
62
- });
63
-
64
- const onInput = (index: number, event: any) => {
65
- const value = event.detail.value;
66
- if (value) {
67
- if (index < props.length - 1) {
68
- console.log(index + 1);
69
- inputFocus.value[index + 1] = true;
70
- }
71
- updateModelValue(value, index);
72
- } else {
73
- updateModelValue('', index);
74
- }
75
- };
76
- const onkeydown = (index: number, event: any) => {
77
- if (event.code === 'Backspace') {
78
- inputFocus.value[index] = false;
79
- // inputFocus.value[index - 2] = false;
80
- // inputFocus.value[index - 2] = true;
81
- }
82
- };
83
-
84
- const onFocus = (index: number) => {
85
- focusIndex.value = index;
86
- };
87
-
88
- const onBlur = (index: number) => {
89
- if (focusIndex.value === index) {
90
- focusIndex.value = null;
91
- }
92
- };
93
-
94
- const updateModelValue = (value: string, index: number) => {
95
- const newValue = props.value.split('');
96
- newValue[index] = value;
97
- const joinedValue = newValue.join('');
98
- emit('update:value', joinedValue);
99
- if (joinedValue.length === props.length) {
100
- emit('complete');
101
- }
102
- };
103
-
104
- watch(
105
- () => props.focus,
106
- (newValue) => {
107
- if (newValue) {
108
- inputFocus.value[0].focus();
109
- }
110
- }
111
- );
112
- </script>
113
-
114
- <style lang="scss" scoped>
115
- .v-input-code {
116
- display: flex;
117
- justify-content: center;
118
- align-items: center;
119
- }
120
-
121
- .input-box {
122
- display: flex;
123
- justify-content: center;
124
- align-items: center;
125
- }
126
-
127
- .input-item {
128
- width: v-bind("inputWidth + 'rpx'");
129
- height: v-bind("inputHeight + 'rpx'");
130
- margin: 0 15rpx;
131
- padding: 0 15rpx;
132
- text-align: center;
133
- font-size: 16px;
134
- border-bottom: 4rpx solid v-bind("config.border.color");
135
- outline: none;
136
- transition: all 0.3s ease;
137
- }
138
-
139
- .input-item:focus {
140
- border-bottom: 4rpx solid v-bind("config.border.default");
141
- }
142
-
143
- .input-focus {
144
- border-bottom: 4rpx solid v-bind("config.border.default");
145
- }
146
- </style>
@@ -1,206 +0,0 @@
1
- <template>
2
- <view v-if="currentShow" :class="['v-loading', { 'v-loading--full-screen': fullScreen }]" :style="loadingStyle">
3
- <slot name="spinner">
4
- <view class="v-loading-spinner">
5
- <view class="spinner-outer"></view>
6
- <view class="spinner-inner"></view>
7
- </view>
8
- </slot>
9
- <text v-if="text" class="v-loading-text">{{ text }}</text>
10
- </view>
11
- </template>
12
-
13
- <script setup lang="ts">
14
- import { computed, ref, watch,onMounted,inject } from 'vue';
15
-
16
- const props = defineProps({
17
- fullScreen: {
18
- type: Boolean,
19
- default: false
20
- },
21
- text: {
22
- type: String,
23
- default: '',
24
- required: true
25
- },
26
- size: {
27
- type: String,
28
- default: 'medium',
29
- validator: (value: any) => {
30
- return ['small', 'medium', 'large'].includes(value);
31
- }
32
- },
33
- color: {
34
- type: String,
35
- default: '#287afa'
36
- },
37
- textColor: {
38
- type: String,
39
- default: '#666'
40
- },
41
- duration: {
42
- type: Number,
43
- default: 0
44
- },
45
- show: {
46
- type: Boolean,
47
- default: false
48
- }
49
- });
50
-
51
- const emit = defineEmits(['update:show']);
52
-
53
- const config = inject<any>('config');
54
- const currentShow = ref(props.show);
55
- let timer: NodeJS.Timeout | null = null;
56
-
57
- watch(
58
- () => props.show,
59
- (newValue) => {
60
- currentShow.value = newValue;
61
- if (newValue) {
62
- if (timer) {
63
- clearTimeout(timer);
64
- }
65
- if (props.duration > 0) {
66
- timer = setTimeout(() => {
67
- currentShow.value = false;
68
- emit('update:show', false);
69
- }, props.duration);
70
- }
71
- }
72
- }
73
- );
74
-
75
- watch(
76
- () => props.duration,
77
- (newValue) => {
78
- if (currentShow.value && newValue > 0) {
79
- if (timer) {
80
- clearTimeout(timer);
81
- }
82
- timer = setTimeout(() => {
83
- currentShow.value = false;
84
- emit('update:show', false);
85
- }, newValue);
86
- }
87
- }
88
- );
89
-
90
- onMounted(()=>{
91
- if (currentShow.value && props.duration > 0) {
92
- if (timer) {
93
- clearTimeout(timer);
94
- }
95
- timer = setTimeout(() => {
96
- currentShow.value = false;
97
- emit('update:show', false);
98
- }, props.duration);
99
- }
100
- })
101
-
102
- const loadingStyle = computed(() => {
103
- return {
104
- '--loading-color': props.color,
105
- '--text-color': props.textColor
106
- };
107
- });
108
- </script>
109
-
110
- <style lang="scss" scoped>
111
- .v-loading {
112
- min-height: 150rpx;
113
- position: relative;
114
- display: flex;
115
- flex-direction: column;
116
- align-items: center;
117
- justify-content: center;
118
- padding: 16rpx;
119
- z-index: 1000;
120
-
121
- &--full-screen {
122
- position: fixed;
123
- top: 0;
124
- left: 0;
125
- right: 0;
126
- bottom: 0;
127
- background-color: rgba(255, 255, 255, 0.8);
128
- }
129
-
130
- .v-loading-spinner {
131
- width: 80rpx;
132
- height: 80rpx;
133
- position: relative;
134
- margin-bottom: 12rpx;
135
- }
136
-
137
- .spinner-outer {
138
- position: absolute;
139
- top: 0;
140
- left: 0;
141
- right: 0;
142
- bottom: 0;
143
- border: 6rpx solid var(--loading-color);
144
- border-radius: 50%;
145
- border-top-color: transparent;
146
- animation: spin 1s linear infinite;
147
- }
148
-
149
- .spinner-inner {
150
- position: absolute;
151
- top: 20%;
152
- left: 20%;
153
- transform: translate(-50%, -50%);
154
- width: 60%;
155
- height: 60%;
156
- border: 6rpx solid var(--loading-color);
157
- border-radius: 50%;
158
- border-top-color: transparent;
159
- animation: spin 0.6s linear infinite reverse;
160
- }
161
-
162
- .v-loading-text {
163
- color: var(--text-color);
164
- font-size: v-bind("config.fontSize.mediumText");
165
- }
166
-
167
- @keyframes spin {
168
- 0% {
169
- transform: rotate(0deg);
170
- }
171
- 100% {
172
- transform: rotate(360deg);
173
- }
174
- }
175
-
176
- &--small .v-loading-spinner {
177
- width: 60rpx;
178
- height: 60rpx;
179
- }
180
-
181
- &--small .spinner-outer {
182
- border-width: 4rpx;
183
- }
184
-
185
- &--small .spinner-inner {
186
- width: 70%;
187
- height: 70%;
188
- border-width: 4rpx;
189
- }
190
-
191
- &--large .v-loading-spinner {
192
- width: 100rpx;
193
- height: 100rpx;
194
- }
195
-
196
- &--large .spinner-outer {
197
- border-width: 8rpx;
198
- }
199
-
200
- &--large .spinner-inner {
201
- width: 50%;
202
- height: 50%;
203
- border-width: 8rpx;
204
- }
205
- }
206
- </style>
@@ -1,222 +0,0 @@
1
- <template>
2
- <view
3
- ref="rootRef"
4
- class="v-menu-container"
5
- :class="[`v-menu-container--position--${menuPosition}`, { 'v-slide-x': slideAxis === 'x' }, { 'v-slide-y': slideAxis === 'y' }]"
6
- @touchstart="onTouchStart"
7
- @touchmove="onTouchMove"
8
- @touchend="onTouchEnd"
9
- @mousedown="onMouseDown"
10
- @mousemove="onMouseMove"
11
- @mouseup="onMouseUp"
12
- >
13
- <!-- 菜单栏 -->
14
- <view class="v-menu">
15
- <view v-for="item in menuItems" :key="item.id" :class="['menu-item', { active: activeMenuId === item.id }]" @click="handleMenuItemClick(item.id, item)">
16
- {{ item.title }}
17
- </view>
18
- </view>
19
-
20
- <!-- 内容区 -->
21
- <view class="menu-content">
22
- <template v-for="(item, index) in menuItems" :key="item.id">
23
- <view v-show="activeMenuId === item.id">
24
- <slot :name="`content-${index}`" :item="item">
25
- </slot>
26
- </view>
27
- </template>
28
- </view>
29
- </view>
30
- </template>
31
-
32
- <script lang="ts" setup>
33
- import { ref, watch, inject, computed, getCurrentInstance, nextTick,provide } from 'vue';
34
-
35
-
36
- interface MenuItem {
37
- id: string;
38
- title: string;
39
- }
40
-
41
- /* ========= props ========= */
42
- const props = defineProps({
43
- menuPosition: {
44
- type: String,
45
- default: 'left',
46
- validator: (v: string) => ['left', 'right'].includes(v)
47
- },
48
- menuItems: {
49
- type: Array as () => MenuItem[],
50
- required: true
51
- },
52
- value: {
53
- type: String,
54
- default: ''
55
- },
56
- isSlide: {
57
- // 是否启用滑动
58
- type: Boolean,
59
- default: false
60
- },
61
- slideAxis: {
62
- // 滑动方向
63
- type: String as () => 'x' | 'y',
64
- default: 'x'
65
- }
66
- });
67
-
68
- const emit = defineEmits(['update:value', 'select']);
69
-
70
- const config = inject<any>('config');
71
- const activeMenuId = ref(props.value || props.menuItems[0]?.id || '');
72
-
73
- /* ========= 滑动核心 ========= */
74
- const rootRef = ref<HTMLElement>();
75
- const startX = ref(0);
76
- const startY = ref(0);
77
- const isTracking = ref(false);
78
- const SLIDE_THRESHOLD = 50;
79
-
80
- const currentIndex = computed(() => props.menuItems.findIndex((item) => item.id === activeMenuId.value));
81
-
82
- const next = () => {
83
- const len = props.menuItems.length;
84
- const idx = (currentIndex.value + 1 + len) % len;
85
- handleMenuItemClick(props.menuItems[idx].id, props.menuItems[idx]);
86
- };
87
-
88
- const prev = () => {
89
- const len = props.menuItems.length;
90
- const idx = (currentIndex.value - 1 + len) % len;
91
- handleMenuItemClick(props.menuItems[idx].id, props.menuItems[idx]);
92
- };
93
-
94
- const handleMenuItemClick = (id: string, row: MenuItem) => {
95
- activeMenuId.value = id;
96
- emit('update:value', id);
97
- emit('select', id, row);
98
- };
99
-
100
- /* 统一手势处理 */
101
- const onStart = (x: number, y: number) => {
102
- if (!props.isSlide) return;
103
- startX.value = x;
104
- startY.value = y;
105
- isTracking.value = true;
106
- };
107
-
108
- const onMove = (x: number, y: number) => {
109
- if (!isTracking.value) return;
110
- const dx = x - startX.value;
111
- const dy = y - startY.value;
112
- const dir = props.slideAxis === 'x' ? dx : dy;
113
- const orth = props.slideAxis === 'x' ? dy : dx;
114
- if (Math.abs(orth) > Math.abs(dir)) return; // 优先同轴
115
- };
116
-
117
- const onEnd = (x: number, y: number) => {
118
- if (!isTracking.value) return;
119
- isTracking.value = false;
120
- const delta = props.slideAxis === 'x' ? x - startX.value : y - startY.value;
121
- if (delta > SLIDE_THRESHOLD) prev();
122
- else if (delta < -SLIDE_THRESHOLD) next();
123
- };
124
-
125
- /* Touch 事件 */
126
- const onTouchStart = (e: TouchEvent) => onStart(e.touches[0].clientX, e.touches[0].clientY);
127
-
128
- const onTouchMove = (e: TouchEvent) => {
129
- if (!props.isSlide) return;
130
- onMove(e.touches[0].clientX, e.touches[0].clientY);
131
- e.preventDefault?.();
132
- };
133
-
134
- const onTouchEnd = (e: TouchEvent) => onEnd(e.changedTouches[0].clientX, e.changedTouches[0].clientY);
135
-
136
- /* Mouse 事件(PC H5) */
137
- const onMouseDown = (e: MouseEvent) => onStart(e.clientX, e.clientY);
138
- const onMouseMove = (e: MouseEvent) => {
139
- if (!isTracking.value) return;
140
- onMove(e.clientX, e.clientY);
141
- e.preventDefault?.();
142
- };
143
- const onMouseUp = (e: MouseEvent) => onEnd(e.clientX, e.clientY);
144
-
145
- /* 监听 v-model 外部更新 */
146
- watch(
147
- () => props.value,
148
- (newVal) => {
149
- if (newVal && newVal !== activeMenuId.value) {
150
- activeMenuId.value = newVal;
151
- }
152
- }
153
- );
154
-
155
- /* H5:禁止横向/纵向滚动冲突 */
156
- const isH5 = typeof plus === 'undefined';
157
- if (isH5) {
158
- nextTick(() => {
159
- const el = (getCurrentInstance()?.proxy as any)?.$el as HTMLElement;
160
- if (el) {
161
- el.style.overscrollBehaviorX = props.slideAxis === 'x' ? 'contain' : 'auto';
162
- el.style.overscrollBehaviorY = props.slideAxis === 'y' ? 'contain' : 'auto';
163
- }
164
- });
165
- }
166
- </script>
167
-
168
- <style lang="scss" scoped>
169
- .v-menu-container {
170
- display: flex;
171
- width: 100%;
172
- height: 100%;
173
- touch-action: pan-y; /* 允许垂直滚动,水平自己接管 */
174
-
175
-
176
-
177
- &--position--right {
178
- flex-direction: row-reverse;
179
- }
180
- }
181
-
182
- .v-menu {
183
- display: flex;
184
- flex-direction: column;
185
- background-color: v-bind('config.VMenu.backgroundColor');
186
- border-right: 1rpx solid v-bind('config.border.color');
187
- width: 200rpx;
188
- height: 100%;
189
- overflow-y: auto;
190
- transition: all 0.3s ease;
191
- border-radius: 6rpx 0 0 6rpx;
192
- }
193
-
194
- .menu-item {
195
- padding: 12rpx 16rpx;
196
- cursor: pointer;
197
- color: v-bind('config.fontColor.subTitle');
198
- transition: all 0.2s ease;
199
- border-bottom: 1rpx solid transparent;
200
-
201
- &:hover {
202
- background-color: v-bind('config.VMenu.highlightBackgroundColor');
203
- }
204
-
205
- &.active {
206
- background-color: v-bind('config.VMenu.highlightBackgroundColor');
207
- color: v-bind('config.fontColor.mainText');
208
- font-weight: bold;
209
- border-left: 6rpx solid v-bind('config.border.color');
210
- }
211
- }
212
-
213
- .menu-content {
214
- flex: 1;
215
- padding: 16rpx;
216
- background-color: v-bind('config.VMenu.reversal');
217
- min-height: 600rpx;
218
- overflow: auto;
219
- box-shadow: -2rpx 0 5px rgba(0, 0, 0, 0.05);
220
- }
221
-
222
- </style>