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,175 @@
1
+ <template>
2
+ <view class="v-video-container">
3
+ <video
4
+ :id="videoId"
5
+ :src="videoContext.src"
6
+ :poster="poster"
7
+ :autoplay="autoplay"
8
+ :controls="controls"
9
+ :loop="loop"
10
+ :muted="muted"
11
+ :object-fit="objectFit"
12
+ :class="videoClass"
13
+ :style="videoStyle"
14
+ @play="handlePlay"
15
+ @pause="handlePause"
16
+ @ended="handleEnded"
17
+ @click="handleVideoClick"
18
+ @touchstart="handleTouchStart"
19
+ @touchmove="handleTouchMove"
20
+ @touchend="handleTouchEnd"
21
+ :error="handleError"
22
+ style="width: 100%; height: 100%"
23
+ ></video>
24
+ <!-- 加载插槽 -->
25
+ <slot name="loading" v-if="isLoading" />
26
+
27
+ <!-- 错误插槽 -->
28
+ <slot name="error" v-if="isError" />
29
+
30
+ <!-- 新增:暂停插槽(非 loading / 非 error / 已暂停 / 未结束) -->
31
+ <slot name="paused" v-if="!isLoading && !isError && isPaused && !hasEnded" />
32
+ </view>
33
+ </template>
34
+
35
+ <script setup lang="ts">
36
+ import { ref, onMounted, watch, reactive } from 'vue';
37
+
38
+ interface Props {
39
+ src: string;
40
+ poster?: string;
41
+ autoplay?: boolean;
42
+ controls?: boolean;
43
+ loop?: boolean;
44
+ muted?: boolean;
45
+ objectFit?: string;
46
+ width?: string;
47
+ height?: string;
48
+ videoClass?: string;
49
+ videoStyle?: string;
50
+ }
51
+
52
+ const props = withDefaults(defineProps<Props>(), {
53
+ poster: '',
54
+ autoplay: false,
55
+ controls: true,
56
+ loop: false,
57
+ muted: false,
58
+ objectFit: 'contain',
59
+ width: '100%',
60
+ height: '100%',
61
+ videoClass: '',
62
+ videoStyle: ''
63
+ });
64
+
65
+ const emit = defineEmits(['play', 'pause', 'ended', 'error']);
66
+
67
+ const videoId = ref('video_' + Date.now());
68
+ const isLoading = ref(true);
69
+ const isError = ref(false);
70
+ const videoContext = reactive({
71
+ src: props.src
72
+ });
73
+ const videoElement = ref(null);
74
+ const touchStartX = ref(0);
75
+ const touchStartTime = ref(0);
76
+ const isLongPress = ref(false);
77
+ const clickNumber = ref(0);
78
+ const isPaused = ref(true);
79
+ const hasEnded = ref(false);
80
+
81
+ onMounted(() => {
82
+ videoElement.value = uni.createVideoContext(videoId.value);
83
+ });
84
+
85
+ watch(
86
+ () => props.src,
87
+ (newValue) => {
88
+ isLoading.value = true;
89
+ if (newValue) {
90
+ videoContext.src = newValue;
91
+ }
92
+ },
93
+ { immediate: true }
94
+ );
95
+ watch(
96
+ () => props.src,
97
+ (newValue) => {
98
+ isLoading.value = true;
99
+ if (newValue) {
100
+ videoContext.src = newValue;
101
+ }
102
+ },
103
+ { immediate: true }
104
+ );
105
+
106
+ const handlePlay = () => {
107
+ isLoading.value = false;
108
+ isError.value = false;
109
+ isPaused.value = false;
110
+ hasEnded.value = false;
111
+ emit('play');
112
+ };
113
+
114
+ const handlePause = () => {
115
+ isPaused.value = true;
116
+ emit('pause');
117
+ };
118
+
119
+ const handleEnded = () => {
120
+ hasEnded.value = true;
121
+ isPaused.value = true;
122
+ emit('ended');
123
+ };
124
+
125
+ const handleError = (event: Event) => {
126
+ isLoading.value = false;
127
+ isError.value = true;
128
+ emit('error', event);
129
+ };
130
+
131
+ const handleVideoClick = () => {
132
+ if (!props.controls && videoElement.value) {
133
+ clickNumber.value++;
134
+ if (clickNumber.value % 2 == 0) {
135
+ videoElement.value.play();
136
+ } else {
137
+ videoElement.value.pause();
138
+ }
139
+ }
140
+ };
141
+
142
+ const handleTouchStart = (event) => {
143
+ touchStartX.value = event.touches[0].clientX;
144
+ touchStartTime.value = Date.now();
145
+ setTimeout(() => {
146
+ if (Date.now() - touchStartTime.value > 500 && !isLongPress.value) {
147
+ isLongPress.value = true;
148
+ }
149
+ }, 500);
150
+ };
151
+
152
+ const handleTouchMove = (event) => {
153
+ if (!props.controls && isLongPress.value && videoElement.value) {
154
+ const touchMoveX = event.touches[0].clientX;
155
+ const videoWidth = videoElement.value.videoWidth;
156
+ const seekTime = videoElement.value.currentTime;
157
+ const duration = videoElement.value.duration;
158
+ const moveDistance = touchMoveX - touchStartX.value;
159
+ const seekPercentage = moveDistance / videoWidth;
160
+ const newTime = Math.max(0, Math.min(duration, seekTime + seekPercentage * duration));
161
+ videoElement.value.currentTime = newTime;
162
+ }
163
+ };
164
+
165
+ const handleTouchEnd = () => {
166
+ isLongPress.value = false;
167
+ };
168
+ </script>
169
+
170
+ <style scoped>
171
+ .v-video-container {
172
+ width: 100%;
173
+ height: 100%;
174
+ }
175
+ </style>
@@ -0,0 +1,158 @@
1
+ <template>
2
+ <view v-show="show" :class="['v-window', `v-window--size-${size}`, { 'v-window--fullscreen': fullscreen }]" :style="windowStyle">
3
+ <view class="v-window-header" v-if="title">
4
+ <view class="v-window-title">{{ title }}</view>
5
+ <view class="v-window-actions" v-if="showActions">
6
+ <button class="v-window-action" @click="minimize">
7
+ <text class="icon-minimize">-</text>
8
+ </button>
9
+ <button class="v-window-action" @click="maximize">
10
+ <text class="icon-maximize">□</text>
11
+ </button>
12
+ <button class="v-window-action" @click="close">
13
+ <text class="icon-close">×</text>
14
+ </button>
15
+ </view>
16
+ </view>
17
+ <view class="v-window-content">
18
+ <slot></slot>
19
+ </view>
20
+ </view>
21
+ </template>
22
+
23
+ <script setup lang="ts">
24
+ import { ref, computed,inject,watch } from 'vue';
25
+
26
+ const props = defineProps({
27
+ title: {
28
+ type: String,
29
+ default: ''
30
+ },
31
+ fullscreen: {
32
+ type: Boolean,
33
+ default: false
34
+ },
35
+ showActions:{
36
+ type:Boolean,
37
+ default:true
38
+ },
39
+ show:{
40
+ type:Boolean,
41
+ default:true
42
+ }
43
+ });
44
+
45
+ const emit = defineEmits(['update:show','update:showActions','update:fullscreen','close', 'minimize', 'maximize']);
46
+ const config = inject<any>('config');
47
+ const windowStyle = computed(() => {
48
+ return {
49
+ width: props.fullscreen ? '100%' : undefined,
50
+ height: props.fullscreen ? '100%' : undefined,
51
+ '--window-title-color': '#333',
52
+ '--window-content-bg': '#fff',
53
+ '--window-border-color': '#e0e0e0'
54
+ };
55
+ });
56
+
57
+ const showActions = ref(props.showActions);
58
+ const show = ref(props.show);
59
+ const fullscreen = ref(props.fullscreen);
60
+
61
+ watch(()=>props.show,(newValue)=>{
62
+ show.value = newValue;
63
+ },{
64
+ immediate:true
65
+ })
66
+ watch(()=>props.showActions,(newValue)=>{
67
+ showActions.value = newValue;
68
+ },{
69
+ immediate:true
70
+ })
71
+ watch(()=>props.fullscreen,(newValue)=>{
72
+ fullscreen.value = newValue;
73
+ },{
74
+ immediate:true
75
+ })
76
+
77
+
78
+ const close = () => {
79
+ show.value = false;
80
+ emit('update:show',false)
81
+ emit('close');
82
+ };
83
+
84
+ const minimize = () => {
85
+ fullscreen.value = false;
86
+ emit('update:fullscreen',false);
87
+ emit('minimize');
88
+ };
89
+
90
+ const maximize = () => {
91
+ fullscreen.value = true;
92
+ emit('update:fullscreen',true);
93
+ emit('maximize');
94
+ };
95
+ </script>
96
+
97
+ <style lang="scss" scoped>
98
+ .v-window {
99
+ width: 80%;
100
+ height: 100%;
101
+ display: flex;
102
+ flex-direction: column;
103
+ border: 1rpx solid var(--window-border-color);
104
+ border-radius: 4rpx;
105
+ box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.15);
106
+ background-color: var(--window-content-bg);
107
+ overflow: hidden;
108
+ margin: auto;
109
+
110
+ &--fullscreen {
111
+ width: 100%;
112
+ height: 100%;
113
+ position: fixed;
114
+ top: 0;
115
+ left: 0;
116
+ right: 0;
117
+ bottom: 0;
118
+ z-index: 1000;
119
+ }
120
+
121
+ .v-window-header {
122
+ display: flex;
123
+ justify-content: space-between;
124
+ align-items: center;
125
+ padding: 8rpx 16rpx;
126
+ background-color: var(--window-content-bg);
127
+ border-bottom: 1rpx solid var(--window-border-color);
128
+
129
+ .v-window-title {
130
+ font-size: v-bind("config.fontSize.mediumTitle");
131
+ font-weight: bold;
132
+ color: var(--window-title-color);
133
+ }
134
+
135
+ .v-window-actions {
136
+ display: flex;
137
+ }
138
+
139
+ .v-window-action {
140
+ background: none;
141
+ border: none;
142
+ cursor: pointer;
143
+ font-size: v-bind("config.fontSize.smallText");
144
+ margin-left: 8rpx;
145
+
146
+ &:hover {
147
+ background-color: #f5f5f5;
148
+ }
149
+ }
150
+ }
151
+
152
+ .v-window-content {
153
+ flex: 1;
154
+ padding: 16rpx;
155
+ overflow: auto;
156
+ }
157
+ }
158
+ </style>
package/package.json CHANGED
@@ -1,108 +1,32 @@
1
1
  {
2
2
  "name": "v-uni-app-ui",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "uni-app 通用 UI 组件库",
5
5
  "main": "index.js",
6
+ "files": [
7
+ "components",
8
+ "index.js",
9
+ "README.md"
10
+ ],
6
11
  "keywords": [
7
- "plugin",
8
- "nodejs"
12
+ "uniapp",
13
+ "uni-app",
14
+ "vue",
15
+ "components",
16
+ "ui",
17
+ "小程序",
18
+ "移动端"
9
19
  ],
10
20
  "author": "FangBiShan",
11
21
  "license": "MIT",
22
+ "peerDependencies": {
23
+ "vue": "^2.6.0 || ^3.0.0"
24
+ },
12
25
  "devDependencies": {
13
26
  "@types/uni-app": "^1.4.8",
14
- "@typescript-eslint/eslint-plugin": "^8.50.1",
15
- "@typescript-eslint/parser": "^8.50.1",
16
- "sass": "^1.87.0",
17
- "scss": "^0.2.4"
18
- },
19
- "dependencies": {
20
- "acorn": "^8.15.0",
21
- "acorn-jsx": "^5.3.2",
22
- "ajv": "^6.12.6",
23
- "ansi-styles": "^4.3.0",
24
- "argparse": "^2.0.1",
25
- "balanced-match": "^1.0.2",
26
- "brace-expansion": "^2.0.2",
27
- "braces": "^3.0.3",
28
- "callsites": "^3.1.0",
29
- "chalk": "^4.1.2",
30
- "chokidar": "^4.0.3",
31
- "color-convert": "^2.0.1",
32
- "color-name": "^1.1.4",
33
- "concat-map": "^0.0.1",
34
- "cross-spawn": "^7.0.6",
35
- "debug": "^4.4.3",
36
- "deep-is": "^0.1.4",
37
- "detect-libc": "^1.0.3",
38
- "escape-string-regexp": "^4.0.0",
39
27
  "eslint": "^9.39.2",
40
- "eslint-scope": "^8.4.0",
41
- "eslint-visitor-keys": "^3.4.3",
42
- "espree": "^10.4.0",
43
- "esquery": "^1.6.0",
44
- "esrecurse": "^4.3.0",
45
- "estraverse": "^5.3.0",
46
- "esutils": "^2.0.3",
47
- "fast-deep-equal": "^3.1.3",
48
- "fast-json-stable-stringify": "^2.1.0",
49
- "fast-levenshtein": "^2.0.6",
50
- "file-entry-cache": "^8.0.0",
51
- "fill-range": "^7.1.1",
52
- "find-up": "^5.0.0",
53
- "flat-cache": "^4.0.1",
54
- "flatted": "^3.3.3",
55
- "glob-parent": "^6.0.2",
56
- "globals": "^14.0.0",
57
- "has-flag": "^4.0.0",
58
- "ignore": "^7.0.5",
59
- "immutable": "^5.1.2",
60
- "import-fresh": "^3.3.1",
61
- "imurmurhash": "^0.1.4",
62
- "is-extglob": "^2.1.1",
63
- "is-glob": "^4.0.3",
64
- "is-number": "^7.0.0",
65
- "isexe": "^2.0.0",
66
- "js-yaml": "^4.1.1",
67
- "json-buffer": "^3.0.1",
68
- "json-schema-traverse": "^0.4.1",
69
- "json-stable-stringify-without-jsonify": "^1.0.1",
70
- "keyv": "^4.5.4",
71
- "levn": "^0.4.1",
72
- "locate-path": "^6.0.0",
73
- "lodash.merge": "^4.6.2",
74
- "micromatch": "^4.0.8",
75
- "minimatch": "^9.0.5",
76
- "ms": "^2.1.3",
77
- "natural-compare": "^1.4.0",
78
- "node-addon-api": "^7.1.1",
79
- "ometa": "^0.2.2",
80
- "optionator": "^0.9.4",
81
- "p-limit": "^3.1.0",
82
- "p-locate": "^5.0.0",
83
- "parent-module": "^1.0.1",
84
- "path-exists": "^4.0.0",
85
- "path-key": "^3.1.1",
86
- "picomatch": "^2.3.1",
87
- "prelude-ls": "^1.2.1",
88
- "punycode": "^2.3.1",
89
- "readdirp": "^4.1.2",
90
- "resolve-from": "^4.0.0",
91
- "semver": "^7.7.3",
92
- "shebang-command": "^2.0.0",
93
- "shebang-regex": "^3.0.0",
94
- "source-map-js": "^1.2.1",
95
- "strip-json-comments": "^3.1.1",
96
- "supports-color": "^7.2.0",
97
- "tinyglobby": "^0.2.15",
98
- "to-regex-range": "^5.0.1",
99
- "ts-api-utils": "^2.1.0",
100
- "type-check": "^0.4.0",
101
- "typescript": "^5.9.3",
102
- "uri-js": "^4.4.1",
103
- "which": "^2.0.2",
104
- "word-wrap": "^1.2.5",
105
- "yocto-queue": "^0.1.0"
28
+ "sass": "^1.97.1",
29
+ "typescript": "^5.9.3"
106
30
  },
107
31
  "scripts": {
108
32
  "test": "echo \"Error: no test specified\" && exit 1"