v-uni-app-ui 1.0.0 → 1.0.2

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 (61) hide show
  1. package/components/config.js +123 -0
  2. package/components/layout/v-card/v-card.vue +108 -0
  3. package/components/layout/v-grid/v-grid.vue +162 -0
  4. package/components/layout/v-icon-grid/v-icon-grid.vue +195 -0
  5. package/components/layout/v-infinite-scroll/v-infinite-scroll.vue +172 -0
  6. package/components/layout/v-list/v-list.vue +43 -0
  7. package/components/layout/v-row/v-row.vue +142 -0
  8. package/components/layout/v-waterfall/v-waterfall.vue +79 -0
  9. package/components/model/compound/v-checkbox-group/v-checkbox-group.vue +96 -0
  10. package/components/model/compound/v-console/v-console.js +20 -0
  11. package/components/model/compound/v-console/v-console.vue +299 -0
  12. package/components/model/compound/v-date-time/v-date-time.vue +261 -0
  13. package/components/model/compound/v-dialog/v-dialog.vue +178 -0
  14. package/components/model/compound/v-drum-select-picker/v-drum-select-picker.vue +83 -0
  15. package/components/model/compound/v-form/v-form.vue +226 -0
  16. package/components/model/compound/v-form-item/v-form-item.vue +255 -0
  17. package/components/model/compound/v-image/v-image.vue +357 -0
  18. package/components/model/compound/v-input-desensitize/v-input-desensitize.vue +101 -0
  19. package/components/model/compound/v-page/v-page.vue +11 -0
  20. package/components/model/compound/v-pages/v-pages.vue +141 -0
  21. package/components/model/compound/v-picker-list/v-picker-list.vue +109 -0
  22. package/components/model/compound/v-popup/v-popup.vue +151 -0
  23. package/components/model/compound/v-radio-group/v-radio-group.vue +86 -0
  24. package/components/model/compound/v-select-picker/v-select-picker.vue +202 -0
  25. package/components/model/compound/v-series-picker-list/v-series-picker-list.vue +221 -0
  26. package/components/model/compound/v-series-select-picker/v-series-select-picker.vue +203 -0
  27. package/components/model/compound/v-switch/v-switch.vue +136 -0
  28. package/components/model/compound/v-tabs-page/v-tabs-page.vue +138 -0
  29. package/components/model/native/v-badge/v-badge.vue +143 -0
  30. package/components/model/native/v-button/v-button.vue +273 -0
  31. package/components/model/native/v-carousel/v-carousel.vue +138 -0
  32. package/components/model/native/v-checkbox/v-checkbox.vue +215 -0
  33. package/components/model/native/v-collapse/v-collapse.vue +190 -0
  34. package/components/model/native/v-header-navigation-bar/v-header-navigation-bar.vue +92 -0
  35. package/components/model/native/v-input/v-input.vue +352 -0
  36. package/components/model/native/v-input-code/v-input-code.vue +146 -0
  37. package/components/model/native/v-loading/v-loading.vue +206 -0
  38. package/components/model/native/v-menu/v-menu.vue +222 -0
  39. package/components/model/native/v-menu-slide/v-menu-slide.vue +364 -0
  40. package/components/model/native/v-min-loading/v-min-loading.vue +80 -0
  41. package/components/model/native/v-null/v-null.vue +97 -0
  42. package/components/model/native/v-overlay/v-overlay.vue +96 -0
  43. package/components/model/native/v-pull-up-refresh/v-pull-up-refresh.vue +157 -0
  44. package/components/model/native/v-radio/v-radio.vue +138 -0
  45. package/components/model/native/v-scroll-list/v-scroll-list.vue +169 -0
  46. package/components/model/native/v-steps/v-steps.vue +253 -0
  47. package/components/model/native/v-table/v-table.vue +203 -0
  48. package/components/model/native/v-tabs/v-tabs.vue +235 -0
  49. package/components/model/native/v-tag/v-tag.vue +206 -0
  50. package/components/model/native/v-text/v-text.vue +187 -0
  51. package/components/model/native/v-text-button/v-text-button.vue +139 -0
  52. package/components/model/native/v-textarea/v-textarea.vue +178 -0
  53. package/components/model/native/v-title/v-title.vue +91 -0
  54. package/components/model/native/v-toast/info.png +0 -0
  55. package/components/model/native/v-toast/success.png +0 -0
  56. package/components/model/native/v-toast/v-toast.vue +198 -0
  57. package/components/model/native/v-toast/warn.png +0 -0
  58. package/components/model/native/v-upload-file-button/v-upload-file-button.vue +296 -0
  59. package/components/model/native/v-video/v-video.vue +175 -0
  60. package/components/model/native/v-window/v-window.vue +158 -0
  61. package/package.json +18 -94
@@ -0,0 +1,221 @@
1
+ <template>
2
+ <v-popup v-model:value="isShow" :title="title" :scrollHeight="scrollHeight" @close="handleClose" @confirm="handleConfirm">
3
+ <view class="series-picker-content">
4
+ <view v-for="(column, columnIndex) in currentList" :key="columnIndex" class="series-picker-column">
5
+ <scroll-view class="series-picker-scroll" scroll-y :style="{ height: scrollHeight + 'rpx' }">
6
+ <view
7
+ v-for="(item, index) in column"
8
+ :key="index"
9
+ class="series-picker-item"
10
+ :class="{ active: item.value === selectedValues[columnIndex] }"
11
+ @click="handleSelect(item, columnIndex)"
12
+ >
13
+ {{ item.label }}
14
+ </view>
15
+ </scroll-view>
16
+ </view>
17
+ <view v-show="safeList.length === 0">
18
+ <slot name="is-null">
19
+ <v-null text="暂无数据"></v-null>
20
+ </slot>
21
+ </view>
22
+ </view>
23
+ </v-popup>
24
+ </template>
25
+
26
+ <script setup lang="ts">
27
+ import { ref, computed, watch, onMounted,inject } from 'vue';
28
+
29
+ interface PickerItem {
30
+ label: string;
31
+ value: string;
32
+ children?: PickerItem[];
33
+ }
34
+
35
+ /**
36
+ * v-series-picker 拾取器
37
+ * value 是否显示拾取器 默认值:false 可选值true显示、false隐藏
38
+ * list 拾取器数据列表
39
+ * title 拾取器标题
40
+ * selected 默认选中项 默认值:null
41
+ * scrollHeight 拾取器滚动区域高度 默认值:400
42
+ * 相关事件:confirm选中事件、select选择事件
43
+ */
44
+ const props = defineProps({
45
+ value: {
46
+ type: Boolean,
47
+ default: false,
48
+ required: true
49
+ },
50
+ list: {
51
+ type: Array as () => PickerItem[],
52
+ default: () => [],
53
+ required: true
54
+ },
55
+ title: {
56
+ type: String,
57
+ default: ''
58
+ },
59
+ selected: {
60
+ type: Array as () => string[],
61
+ default: () => []
62
+ },
63
+ scrollHeight: {
64
+ type: Number,
65
+ default: 400
66
+ }
67
+ });
68
+
69
+ const emit = defineEmits(['update:value','close', 'confirm', 'select']);
70
+ const config = inject<any>('config');
71
+ const isShow = ref(props.value);
72
+ const isActive = ref(false);
73
+ const selectedValues = ref(props.selected || []);
74
+ const currentList = ref<PickerItem[][]>([]);
75
+ const safeList = computed(() => props.list || []);
76
+
77
+ const initializeSelectedValues = () => {
78
+ selectedValues.value = safeList.value.map((_, index) => {
79
+ if (index === 0) return safeList.value[0].value;
80
+ return '';
81
+ });
82
+ };
83
+ const updateCurrentList = () => {
84
+ const newList: PickerItem[][] = [];
85
+ let currentItems: PickerItem[] = [...safeList.value];
86
+
87
+ for (let i = 0; i < selectedValues.value.length; i++) {
88
+ const selectedValue = selectedValues.value[i];
89
+
90
+ if (i === 0) {
91
+ newList.push(currentItems);
92
+ } else if (newList[i - 1] && newList[i - 1].length > 0) {
93
+ const prevItems = newList[i - 1];
94
+ const prevSelectedIndex = prevItems.findIndex((item) => item.value === selectedValues.value[i - 1]);
95
+
96
+ if (prevSelectedIndex !== -1 && prevItems[prevSelectedIndex].children) {
97
+ currentItems = prevItems[prevSelectedIndex].children;
98
+ newList.push(currentItems);
99
+ } else {
100
+ break;
101
+ }
102
+ } else {
103
+ break;
104
+ }
105
+
106
+ if (selectedValue && currentItems.length) {
107
+ const currentIndex = currentItems.findIndex((item) => item.value === selectedValue);
108
+ if (currentIndex === -1) {
109
+ selectedValues.value = selectedValues.value.map((_, idx) => (idx <= i ? selectedValues.value[idx] : ''));
110
+ break;
111
+ }
112
+ }
113
+ }
114
+
115
+ currentList.value = newList;
116
+ };
117
+
118
+ watch(
119
+ () => safeList.value,
120
+ (newList: any) => {
121
+ initializeSelectedValues();
122
+ updateCurrentList();
123
+ },
124
+ { deep: true, immediate: true }
125
+ );
126
+
127
+ watch(
128
+ () => props.list,
129
+ (newList: any) => {
130
+ console.log(newList);
131
+ initializeSelectedValues();
132
+ updateCurrentList();
133
+ },
134
+ { deep: true, immediate: true }
135
+ );
136
+
137
+ watch(
138
+ () => props.value,
139
+ (newValue) => {
140
+ isShow.value = newValue;
141
+ isActive.value = newValue;
142
+
143
+ if (newValue) {
144
+ initializeSelectedValues();
145
+ updateCurrentList();
146
+ }
147
+ }
148
+ );
149
+
150
+ const handleClose = () => {
151
+ isShow.value = false;
152
+ isActive.value = false;
153
+ emit('update:value', false);
154
+ emit('close', false);
155
+ };
156
+
157
+ const handleSelect = (item: PickerItem, columnIndex: number) => {
158
+ const newSelectedValues = [...selectedValues.value];
159
+ newSelectedValues[columnIndex] = item.value;
160
+
161
+ if (columnIndex < newSelectedValues.length - 1) {
162
+ for (let i = columnIndex + 1; i < newSelectedValues.length; i++) {
163
+ newSelectedValues[i] = '';
164
+ }
165
+ }
166
+
167
+ selectedValues.value = newSelectedValues;
168
+ emit('select', newSelectedValues[columnIndex]);
169
+ updateCurrentList();
170
+ };
171
+
172
+ const handleConfirm = () => {
173
+ const result: any[] = [];
174
+
175
+ currentList.value.forEach((column, index) => {
176
+ const selectedValue = selectedValues.value[index];
177
+ const selectedItem = column.find((item) => item.value === selectedValue);
178
+ if (selectedItem) {
179
+ result.push(selectedItem);
180
+ }
181
+ });
182
+ isShow.value = false;
183
+ isShow.value = false;
184
+ isActive.value = false;
185
+ emit('update:value', false);
186
+ emit('confirm', result);
187
+ };
188
+ </script>
189
+
190
+ <style lang="scss" scoped>
191
+ .series-picker-content {
192
+ display: flex;
193
+ max-height: 500rpx;
194
+ overflow: hidden;
195
+ }
196
+
197
+ .series-picker-column {
198
+ flex: 1;
199
+ border-right: 1rpx solid v-bind("config.border.color");
200
+ }
201
+
202
+ .series-picker-column:last-child {
203
+ border-right: none;
204
+ }
205
+
206
+ .series-picker-scroll {
207
+ height: 100%;
208
+ }
209
+
210
+ .series-picker-item {
211
+ padding: 20rpx 30rpx;
212
+ font-size: v-bind("config.fontSize.mediumText");
213
+ color: v-bind("config.fontColor.mainText");
214
+ border-bottom: 1rpx solid v-bind("config.border.color");
215
+ }
216
+
217
+ .series-picker-item.active {
218
+ color: v-bind("config.fontColor.default");
219
+ font-weight: 500;
220
+ }
221
+ </style>
@@ -0,0 +1,203 @@
1
+ <template>
2
+ <view class="select-picker">
3
+ <view :class="['select-input', `select-input--border-${borderModel}`, { 'select-input--disabled': disabled }]" @click="handleClick">
4
+ <slot :placeholder="placeholder" :row="row" >
5
+ <view class="input">
6
+ {{ row.label !== null ? row.label : props.placeholder }}
7
+ </view>
8
+ </slot>
9
+ </view>
10
+
11
+ <v-series-picker-list
12
+ v-model:value="showPicker"
13
+ :list="props.options"
14
+ :title="props.title"
15
+ @confirm="handleConfirm"
16
+ @select="handleSelect"
17
+ :scroll-height="scrollHeight"
18
+ :selected="value"
19
+ ></v-series-picker-list>
20
+ </view>
21
+ </template>
22
+
23
+ <script setup lang="ts">
24
+ import { ref, watch, onMounted, reactive,inject } from 'vue';
25
+
26
+ interface PickerItem {
27
+ label: string;
28
+ value: string;
29
+ children?: PickerItem[];
30
+ }
31
+
32
+ /**
33
+ * v-series-select-picker 多选下拉框
34
+ * value 双向绑定
35
+ * placeholder 提示语
36
+ * title 标题
37
+ * options 选择值
38
+ * initializeCustomizeFunction 自定义初始函数
39
+ * borderModel 边框模式 默认:all 可选值:all普通边框 nont无边框模式 bottom底部边框模式 top上边框模式 left左边框模式 right右边框模式 ends左右两端边框模式 up-down上下边框模式
40
+ * disabled 是否禁用 默认:false 可选值:true禁用 false不禁用
41
+ * 相关事件:confirm、select
42
+ */
43
+ const props = defineProps({
44
+ value: {
45
+ type: [String, Number, Array],
46
+ required: true
47
+ },
48
+ placeholder: {
49
+ type: String,
50
+ default: null
51
+ },
52
+ title: {
53
+ type: String,
54
+ required: true
55
+ },
56
+ options: {
57
+ type: Array as () => PickerItem[],
58
+ required: true
59
+ },
60
+ isInputBoder: {
61
+ type: Boolean,
62
+ default: true
63
+ },
64
+ initializeCustomizeFunction: {
65
+ type: Function,
66
+ default: () => {
67
+ return () => {};
68
+ }
69
+ },
70
+ borderModel: {
71
+ type: String,
72
+ default: 'all',
73
+ validator: (value: any) => {
74
+ return ['all', 'none', 'bottom', 'top', 'left', 'right', 'ends', 'up-down'].includes(value);
75
+ }
76
+ },
77
+ disabled: {
78
+ type: Boolean,
79
+ default: false
80
+ },
81
+ scrollHeight: {
82
+ type: Number,
83
+ default: 400
84
+ }
85
+ });
86
+
87
+ let row = reactive({
88
+ label: null,
89
+ value: null
90
+ });
91
+
92
+ const emit = defineEmits(['update:value', 'confirm', 'select']);
93
+
94
+ const config = inject<any>('config');
95
+ onMounted(async () => {
96
+ await props.initializeCustomizeFunction(props.value);
97
+ matchingData(props.value);
98
+ });
99
+
100
+ watch(
101
+ () => props.value,
102
+ (newValue: any) => {
103
+ matchingData(newValue);
104
+ }
105
+ );
106
+ watch(
107
+ () => props.options,
108
+ (newValue: any) => {
109
+ matchingData(props.value);
110
+ }
111
+ );
112
+
113
+ function matchingData(value: any) {
114
+ const result = props.options
115
+ .filter((option) => {
116
+ return option.children && Array.isArray(option.children) && option.children.some((child) => child.value === value);
117
+ })
118
+ .map((option) => {
119
+ return option.children && Array.isArray(option.children) ? option.children.find((child) => child.value === value) : undefined;
120
+ })
121
+ .filter(Boolean);
122
+
123
+ if (result.length > 0) {
124
+ Object.assign(row, result[0]);
125
+ }
126
+ }
127
+
128
+ const showPicker = ref(false);
129
+
130
+ function handleClick() {
131
+ if (!props.disabled) {
132
+ showPicker.value = true;
133
+ }
134
+ }
135
+
136
+ function handleConfirm(result: any) {
137
+ Object.assign(row, result[result.length - 1]);
138
+ emit('update:value', row.value);
139
+ emit('confirm', row);
140
+ showPicker.value = false;
141
+ }
142
+
143
+ function handleSelect(selected: any) {
144
+ emit('select', selected);
145
+ }
146
+ </script>
147
+
148
+ <style lang="scss" scoped>
149
+ .select-input {
150
+ width: 100%;
151
+ height: 72rpx;
152
+ line-height: 72rpx;
153
+ background-color: v-bind("config.backgroundColor.reversal");
154
+ border-radius: 10rpx;
155
+ box-sizing: border-box;
156
+
157
+ &--border-all {
158
+ border: 1rpx solid v-bind("config.border.color");
159
+ }
160
+
161
+ &--border-none {
162
+ border: none;
163
+ }
164
+
165
+ &--border-bottom {
166
+ border-bottom: 1rpx solid v-bind("config.border.color");
167
+ }
168
+
169
+ &--border-top {
170
+ border-top: 1rpx solid v-bind("config.border.color");
171
+ }
172
+
173
+ &--border-left {
174
+ border-left: 1rpx solid v-bind("config.border.color");
175
+ }
176
+
177
+ &--border-right {
178
+ border-right: 1rpx solid v-bind("config.border.color");
179
+ }
180
+
181
+ &--border-ends {
182
+ border-left: 1rpx solid v-bind("config.border.color");
183
+ border-right: 1rpx solid v-bind("config.border.color");
184
+ }
185
+
186
+ &--border-up-down {
187
+ border-top: 1rpx solid v-bind("config.border.color");
188
+ border-bottom: 1rpx solid v-bind("config.border.color");
189
+ }
190
+
191
+ &--disabled {
192
+ background-color: v-bind("config.backgroundColor.disabled");
193
+ color: v-bind("config.fontColor.mainText");
194
+ opacity: v-bind("config.opacity.disabled");
195
+ cursor: not-allowed;
196
+ }
197
+
198
+ .input {
199
+ width: 100%;
200
+ font-size: v-bind("config.fontSize.mediumText");
201
+ }
202
+ }
203
+ </style>
@@ -0,0 +1,136 @@
1
+ <template>
2
+ <view class="v-switch" :class="{ 'is-disabled': disabled }" @click="toggleSwitch" :style="{ width: trackWidth, height: trackHeight }">
3
+ <view class="switch-track" :style="trackStyle">
4
+ <view class="switch-thumb" :style="thumbStyle">
5
+ <v-min-loading
6
+ v-model:value="props.loading"
7
+ type="customize"
8
+ :customize-color="props.loadingCustomizeColor"
9
+ :vacancy-color="props.loadingVacancyColor"
10
+ ></v-min-loading>
11
+ </view>
12
+ </view>
13
+ </view>
14
+ </template>
15
+
16
+ <script lang="ts" setup>
17
+ import { computed,inject } from 'vue';
18
+
19
+ /**
20
+ * v-switch 开关
21
+ * value 默认值:false 可选值:false关、true开
22
+ * disabled 默认值:false 可选值:false不禁用、true禁用
23
+ * activeColor 开启颜色
24
+ * inactiveColor 关闭颜色
25
+ * size 大小
26
+ * loading 是否加载
27
+ * loadingCustomizeColor 加载圈自定义颜色
28
+ * loadingVacancyColor 加载圈缺口自定义颜色
29
+ */
30
+ const props = defineProps({
31
+ value: {
32
+ type: Boolean,
33
+ default: false
34
+ },
35
+ disabled: {
36
+ type: Boolean,
37
+ default: false
38
+ },
39
+ activeColor: {
40
+ type: String,
41
+ default: '#4cd964'
42
+ },
43
+ inactiveColor: {
44
+ type: String,
45
+ default: '#ebedf0'
46
+ },
47
+ size: {
48
+ type: [String, Number],
49
+ default: 'medium'
50
+ },
51
+ loading: {
52
+ type: Boolean,
53
+ default: false
54
+ },
55
+ loadingCustomizeColor: {
56
+ type: String,
57
+ default: "#969696"
58
+ },
59
+ loadingVacancyColor: {
60
+ type: String,
61
+ default: '#fff'
62
+ }
63
+ });
64
+
65
+ const emit = defineEmits(['update:value']);
66
+ const config = inject<any>('config');
67
+ // 尺寸计算
68
+ const sizeMap = {
69
+ small: 40,
70
+ medium: 50,
71
+ large: 60
72
+ };
73
+
74
+ const trackWidth = computed(() => {
75
+ if (typeof props.size === 'number') return `${props.size}px`;
76
+ return `${sizeMap[props.size] || sizeMap.medium}px`;
77
+ });
78
+
79
+ const trackHeight = computed(() => {
80
+ const baseSize = typeof props.size === 'number' ? props.size : sizeMap[props.size] || sizeMap.medium;
81
+ return `${baseSize * 0.5}px`;
82
+ });
83
+
84
+ // 滑块样式
85
+ const thumbStyle = computed(() => ({
86
+ transform: `translateX(${props.value ? 'calc(100% - -5rpx)' : '4rpx'})`,
87
+ width: `calc(${trackHeight.value} - 8rpx)`,
88
+ height: `calc(${trackHeight.value} - 8rpx)`
89
+ }));
90
+
91
+ // 轨道样式
92
+ const trackStyle = computed(() => ({
93
+ backgroundColor: props.value ? props.activeColor : props.inactiveColor,
94
+ opacity: props.disabled ? 0.6 : 1
95
+ }));
96
+
97
+ // 切换状态
98
+ const toggleSwitch = () => {
99
+ if (props.disabled) return;
100
+ emit('update:value', !props.value);
101
+ };
102
+ </script>
103
+
104
+ <style lang="scss">
105
+ .v-switch {
106
+ position: relative;
107
+ display: inline-block;
108
+ vertical-align: middle;
109
+ cursor: pointer;
110
+ transition: all 0.3s;
111
+
112
+ &.is-disabled {
113
+ cursor: not-allowed;
114
+ opacity: v-bind("config.opacity.disabled");
115
+ }
116
+
117
+ .switch-track {
118
+ position: relative;
119
+ width: 100%;
120
+ height: 100%;
121
+ border-radius: 100px;
122
+ background-color: v-bind("config.VSwitch.backgroundColor");
123
+ transition: all 0.3s;
124
+ }
125
+
126
+ .switch-thumb {
127
+ display: flex;
128
+ position: absolute;
129
+ top: 4rpx;
130
+ background-color: v-bind("config.backgroundColor.reversal");
131
+ border-radius: 50%;
132
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.2);
133
+ transition: all 0.3s cubic-bezier(0.3, 0.85, 0.5, 1);
134
+ }
135
+ }
136
+ </style>
@@ -0,0 +1,138 @@
1
+ <template>
2
+ <view class="v-tabs-page">
3
+ <v-tabs
4
+ v-model:value="activeIndex"
5
+ :tabs="items"
6
+ :activeColor="activeColor"
7
+ :inactiveColor="inactiveColor"
8
+ @change="onTabChange"
9
+ :is-line="isLine"
10
+ :line-height="lineHeight"
11
+ :line-width="lineWidth"
12
+ :line-offset="lineOffset"
13
+ :min-tab-width="minTabWidth"
14
+ :item-padding="itemPadding"
15
+ :hover-class="hoverClass"
16
+ />
17
+
18
+ <v-carousel v-model:current="activeIndex" :items="items" :indicator-dots="false" :autoplay="false" :isEndsButton="false" :box-height="boxHeight" @change="onCarouselChange">
19
+ <template v-for="(item, index) in items" #[`item-${index}`]>
20
+ <slot :name="`content-${index}`" :item="item" :index="index">
21
+ <view class="default-content">
22
+ <v-loading text="加载中..." :show="true" />
23
+ </view>
24
+ </slot>
25
+ </template>
26
+ </v-carousel>
27
+ </view>
28
+ </template>
29
+
30
+ <script lang="ts" setup>
31
+ import { ref, watch, inject } from 'vue';
32
+
33
+ interface ContentList {
34
+ title: string;
35
+ content?: any;
36
+ key?: string;
37
+ }
38
+
39
+ /**
40
+ * v-tabs-page 标签页
41
+ * items 标签标题
42
+ * value 目前显示标签页内容
43
+ * activeColor 标签标题高亮颜色
44
+ * inactiveColor 标签标题颜色
45
+ * isLine 是否显示下划线
46
+ */
47
+ const props = defineProps({
48
+ items: {
49
+ type: Array as () => ContentList[],
50
+ required: true,
51
+ default: () => []
52
+ },
53
+ value: {
54
+ type: Number,
55
+ default: 0
56
+ },
57
+ activeColor: {
58
+ type: String,
59
+ default: '#287afa'
60
+ },
61
+ inactiveColor: {
62
+ type: String,
63
+ default: '#666'
64
+ },
65
+ isLine: {
66
+ type: Boolean,
67
+ default: true
68
+ },
69
+ lineHeight: {
70
+ type: String,
71
+ default: '5'
72
+ },
73
+ lineWidth: {
74
+ type: Number,
75
+ default: 0
76
+ },
77
+ lineOffset: {
78
+ type: Number,
79
+ default: 8
80
+ },
81
+ minTabWidth: {
82
+ type: Number,
83
+ default: 120
84
+ },
85
+ itemPadding: {
86
+ type: Number,
87
+ default: 32
88
+ },
89
+ hoverClass: {
90
+ type: String,
91
+ default: 'tabs-hover'
92
+ },
93
+ boxHeight: {
94
+ type: String,
95
+ default: '400rpx'
96
+ }
97
+ });
98
+
99
+ const emit = defineEmits(['update:value', 'change']);
100
+ const config = inject<any>('config');
101
+ const activeIndex = ref(props.value);
102
+
103
+ watch(
104
+ () => props.value,
105
+ (val) => {
106
+ activeIndex.value = val;
107
+ emit('update:value', val);
108
+ },
109
+ { immediate: true }
110
+ );
111
+
112
+ const onTabChange = (index: number) => {
113
+ activeIndex.value = index;
114
+ emit('update:value', index);
115
+ emit('change', index);
116
+ };
117
+ const onCarouselChange = (index: number) => {
118
+ activeIndex.value = index;
119
+ emit('update:value', index);
120
+ emit('change', index);
121
+ };
122
+ </script>
123
+
124
+ <style lang="scss" scoped>
125
+ .v-tabs-page {
126
+ display: flex;
127
+ flex-direction: column;
128
+ height: 100%;
129
+ }
130
+
131
+ .default-content {
132
+ width: 100%;
133
+ padding: 20rpx;
134
+ font-size: v-bind('config.fontSize.mediumText');
135
+ color: v-bind('config.fontColor.mainText');
136
+ min-height: 400rpx;
137
+ }
138
+ </style>