@didaoktv/didaoui-uniapp 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.
- package/LICENSE +21 -0
- package/README.md +89 -0
- package/components/dd-action-sheet/dd-action-sheet.vue +207 -0
- package/components/dd-alert/dd-alert.vue +240 -0
- package/components/dd-avatar/dd-avatar.vue +168 -0
- package/components/dd-backtop/dd-backtop.vue +75 -0
- package/components/dd-badge/dd-badge.vue +150 -0
- package/components/dd-button/dd-button.vue +215 -0
- package/components/dd-capsule-button/dd-capsule-button.vue +109 -0
- package/components/dd-card/dd-card.vue +155 -0
- package/components/dd-cell/dd-cell.vue +201 -0
- package/components/dd-cell-group/dd-cell-group.vue +56 -0
- package/components/dd-champion-card/dd-champion-card.vue +258 -0
- package/components/dd-checkbox/dd-checkbox.vue +145 -0
- package/components/dd-collapse/dd-collapse.vue +63 -0
- package/components/dd-collapse-item/dd-collapse-item.vue +154 -0
- package/components/dd-count-down/dd-count-down.vue +163 -0
- package/components/dd-date-picker/dd-date-picker.vue +253 -0
- package/components/dd-dialog/dd-dialog.vue +264 -0
- package/components/dd-divider/dd-divider.vue +104 -0
- package/components/dd-drawer/dd-drawer.vue +214 -0
- package/components/dd-dropdown-item/dd-dropdown-item.vue +203 -0
- package/components/dd-dropdown-menu/dd-dropdown-menu.vue +177 -0
- package/components/dd-empty-state/dd-empty-state.vue +140 -0
- package/components/dd-feature-grid/dd-feature-grid.vue +139 -0
- package/components/dd-field/dd-field.vue +240 -0
- package/components/dd-icon/dd-icon.vue +464 -0
- package/components/dd-image/dd-image.vue +158 -0
- package/components/dd-input/dd-input.vue +172 -0
- package/components/dd-list-cell/dd-list-cell.vue +152 -0
- package/components/dd-loading/dd-loading.vue +187 -0
- package/components/dd-loadmore/dd-loadmore.vue +152 -0
- package/components/dd-mini-program-navbar/dd-mini-program-navbar.vue +245 -0
- package/components/dd-modal/dd-modal.vue +286 -0
- package/components/dd-navigation/dd-navigation.vue +134 -0
- package/components/dd-overlay/dd-overlay.vue +114 -0
- package/components/dd-picker/dd-picker.vue +203 -0
- package/components/dd-popover/dd-popover.vue +190 -0
- package/components/dd-popover-item/dd-popover-item.vue +88 -0
- package/components/dd-popup/dd-popup.vue +243 -0
- package/components/dd-progress/dd-progress.vue +255 -0
- package/components/dd-pull-refresh/dd-pull-refresh.vue +232 -0
- package/components/dd-radio/dd-radio.vue +129 -0
- package/components/dd-rate/dd-rate.vue +133 -0
- package/components/dd-room-card/dd-room-card.vue +309 -0
- package/components/dd-search-bar/dd-search-bar.vue +176 -0
- package/components/dd-segmented-tab/dd-segmented-tab.vue +187 -0
- package/components/dd-skeleton/dd-skeleton.vue +184 -0
- package/components/dd-slider/dd-slider.vue +227 -0
- package/components/dd-stat-card/dd-stat-card.vue +174 -0
- package/components/dd-step/dd-step.vue +188 -0
- package/components/dd-stepper/dd-stepper.vue +171 -0
- package/components/dd-steps/dd-steps.vue +61 -0
- package/components/dd-sticky/dd-sticky.vue +132 -0
- package/components/dd-swipe/dd-swipe.vue +146 -0
- package/components/dd-swipe-action/dd-swipe-action.vue +248 -0
- package/components/dd-swipe-item/dd-swipe-item.vue +27 -0
- package/components/dd-swipeable-tab/dd-swipeable-tab.vue +202 -0
- package/components/dd-switch/dd-switch.vue +106 -0
- package/components/dd-tabbar/dd-tabbar.vue +112 -0
- package/components/dd-tabbar-item/dd-tabbar-item.vue +122 -0
- package/components/dd-tag/dd-tag.vue +178 -0
- package/components/dd-toast/dd-toast.vue +195 -0
- package/components/dd-top-navbar/dd-top-navbar.vue +184 -0
- package/components/dd-upload/dd-upload.vue +187 -0
- package/index.ts +127 -0
- package/libs/utils.ts +106 -0
- package/package.json +58 -0
- package/scss/_functions.scss +68 -0
- package/scss/_mixins.scss +154 -0
- package/scss/_reset.scss +30 -0
- package/scss/_variables.scss +317 -0
- package/uni.scss +4 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="dd-upload" :class="{ 'dd-upload--disabled': disabled }">
|
|
3
|
+
<view
|
|
4
|
+
v-for="(file, index) in fileList"
|
|
5
|
+
:key="file.url || index"
|
|
6
|
+
class="dd-upload__item"
|
|
7
|
+
@click="onPreview(index)"
|
|
8
|
+
>
|
|
9
|
+
<image
|
|
10
|
+
class="dd-upload__img"
|
|
11
|
+
:src="file.url"
|
|
12
|
+
:mode="imageMode"
|
|
13
|
+
/>
|
|
14
|
+
<view
|
|
15
|
+
v-if="!disabled"
|
|
16
|
+
class="dd-upload__delete"
|
|
17
|
+
@click.stop="onDelete(index)"
|
|
18
|
+
>
|
|
19
|
+
<dd-icon name="cross" />
|
|
20
|
+
</view>
|
|
21
|
+
</view>
|
|
22
|
+
<view
|
|
23
|
+
v-if="showAdd"
|
|
24
|
+
class="dd-upload__add"
|
|
25
|
+
:hover-class="disabled ? '' : 'dd-upload__add--active'"
|
|
26
|
+
@click="onChoose"
|
|
27
|
+
>
|
|
28
|
+
<dd-icon name="plus" />
|
|
29
|
+
</view>
|
|
30
|
+
</view>
|
|
31
|
+
</template>
|
|
32
|
+
|
|
33
|
+
<script setup lang="ts">
|
|
34
|
+
import { computed } from 'vue'
|
|
35
|
+
import DdIcon from '../dd-icon/dd-icon.vue'
|
|
36
|
+
|
|
37
|
+
interface UploadFileItem {
|
|
38
|
+
url: string
|
|
39
|
+
[key: string]: any
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface Props {
|
|
43
|
+
fileList?: UploadFileItem[]
|
|
44
|
+
maxCount?: number
|
|
45
|
+
maxSize?: number
|
|
46
|
+
multiple?: boolean
|
|
47
|
+
disabled?: boolean
|
|
48
|
+
imageFit?: 'cover' | 'contain' | 'fill'
|
|
49
|
+
sourceType?: ('album' | 'camera')[]
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
53
|
+
fileList: () => [],
|
|
54
|
+
maxCount: 9,
|
|
55
|
+
maxSize: 0,
|
|
56
|
+
multiple: true,
|
|
57
|
+
disabled: false,
|
|
58
|
+
imageFit: 'cover',
|
|
59
|
+
sourceType: () => ['album', 'camera'],
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const emit = defineEmits<{
|
|
63
|
+
(e: 'update:fileList', val: UploadFileItem[]): void
|
|
64
|
+
(e: 'change', val: UploadFileItem[]): void
|
|
65
|
+
(e: 'oversize', val: UploadFileItem[]): void
|
|
66
|
+
(e: 'delete', val: { index: number; file: UploadFileItem }): void
|
|
67
|
+
(e: 'afterRead', val: UploadFileItem[]): void
|
|
68
|
+
}>()
|
|
69
|
+
|
|
70
|
+
const modeMap = {
|
|
71
|
+
cover: 'aspectFill',
|
|
72
|
+
contain: 'aspectFit',
|
|
73
|
+
fill: 'scaleToFill',
|
|
74
|
+
} as const
|
|
75
|
+
|
|
76
|
+
const imageMode = computed(() => modeMap[props.imageFit])
|
|
77
|
+
const showAdd = computed(
|
|
78
|
+
() => !props.disabled && props.fileList.length < props.maxCount
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
function onChoose() {
|
|
82
|
+
if (props.disabled) return
|
|
83
|
+
const remaining = props.maxCount - props.fileList.length
|
|
84
|
+
if (remaining <= 0) return
|
|
85
|
+
const count = props.multiple ? Math.min(remaining, 9) : 1
|
|
86
|
+
uni.chooseImage({
|
|
87
|
+
count,
|
|
88
|
+
sourceType: props.sourceType as any,
|
|
89
|
+
success: (res) => {
|
|
90
|
+
const paths = (res.tempFilePaths as string[]) || []
|
|
91
|
+
const sizes = (res.tempFiles as any[] | undefined)?.map((f: any) => f.size) || []
|
|
92
|
+
const accepted: UploadFileItem[] = []
|
|
93
|
+
const rejected: UploadFileItem[] = []
|
|
94
|
+
paths.forEach((p, i) => {
|
|
95
|
+
const item: UploadFileItem = { url: p }
|
|
96
|
+
if (props.maxSize && sizes[i] && sizes[i] > props.maxSize) {
|
|
97
|
+
rejected.push(item)
|
|
98
|
+
} else {
|
|
99
|
+
accepted.push(item)
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
if (rejected.length) emit('oversize', rejected)
|
|
103
|
+
if (accepted.length) {
|
|
104
|
+
const next = [...props.fileList, ...accepted]
|
|
105
|
+
emit('update:fileList', next)
|
|
106
|
+
emit('change', next)
|
|
107
|
+
emit('afterRead', accepted)
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
})
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function onDelete(index: number) {
|
|
114
|
+
const file = props.fileList[index]
|
|
115
|
+
const next = props.fileList.filter((_, i) => i !== index)
|
|
116
|
+
emit('update:fileList', next)
|
|
117
|
+
emit('change', next)
|
|
118
|
+
emit('delete', { index, file })
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function onPreview(index: number) {
|
|
122
|
+
if (props.disabled) return
|
|
123
|
+
const urls = props.fileList.map((f) => f.url).filter(Boolean)
|
|
124
|
+
if (!urls.length) return
|
|
125
|
+
uni.previewImage({ urls, current: urls[index] })
|
|
126
|
+
}
|
|
127
|
+
</script>
|
|
128
|
+
|
|
129
|
+
<style lang="scss" scoped>
|
|
130
|
+
@import '../../scss/variables';
|
|
131
|
+
@import '../../scss/mixins';
|
|
132
|
+
|
|
133
|
+
.dd-upload {
|
|
134
|
+
display: flex;
|
|
135
|
+
flex-wrap: wrap;
|
|
136
|
+
gap: 16rpx;
|
|
137
|
+
|
|
138
|
+
&__item {
|
|
139
|
+
position: relative;
|
|
140
|
+
width: 160rpx;
|
|
141
|
+
height: 160rpx;
|
|
142
|
+
border-radius: $dd-radius-md;
|
|
143
|
+
background: $dd-neutral-800;
|
|
144
|
+
overflow: hidden;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
&__img {
|
|
148
|
+
width: 100%;
|
|
149
|
+
height: 100%;
|
|
150
|
+
display: block;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
&__delete {
|
|
154
|
+
position: absolute;
|
|
155
|
+
top: 8rpx;
|
|
156
|
+
right: 8rpx;
|
|
157
|
+
width: 36rpx;
|
|
158
|
+
height: 36rpx;
|
|
159
|
+
border-radius: 50%;
|
|
160
|
+
background: $dd-error;
|
|
161
|
+
color: $dd-color-white;
|
|
162
|
+
font-size: $dd-font-size-caption;
|
|
163
|
+
@include dd-flex-center;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
&__add {
|
|
167
|
+
@include dd-flex-center;
|
|
168
|
+
width: 160rpx;
|
|
169
|
+
height: 160rpx;
|
|
170
|
+
border: 1px dashed $dd-border-default;
|
|
171
|
+
border-radius: $dd-radius-md;
|
|
172
|
+
background: $dd-neutral-800;
|
|
173
|
+
color: $dd-text-tertiary;
|
|
174
|
+
font-size: 48rpx;
|
|
175
|
+
box-sizing: border-box;
|
|
176
|
+
@include dd-transition(background 0.2s);
|
|
177
|
+
|
|
178
|
+
&--active {
|
|
179
|
+
background: $dd-border-default;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
&--disabled {
|
|
184
|
+
@include dd-no-touch;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
</style>
|
package/index.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { App } from 'vue'
|
|
2
|
+
|
|
3
|
+
// === Input (13) ===
|
|
4
|
+
import DdButton from './components/dd-button/dd-button.vue'
|
|
5
|
+
import DdInput from './components/dd-input/dd-input.vue'
|
|
6
|
+
import DdSwitch from './components/dd-switch/dd-switch.vue'
|
|
7
|
+
import DdCheckbox from './components/dd-checkbox/dd-checkbox.vue'
|
|
8
|
+
import DdRadio from './components/dd-radio/dd-radio.vue'
|
|
9
|
+
import DdSearchBar from './components/dd-search-bar/dd-search-bar.vue'
|
|
10
|
+
import DdSlider from './components/dd-slider/dd-slider.vue'
|
|
11
|
+
import DdStepper from './components/dd-stepper/dd-stepper.vue'
|
|
12
|
+
import DdDatePicker from './components/dd-date-picker/dd-date-picker.vue'
|
|
13
|
+
import DdField from './components/dd-field/dd-field.vue'
|
|
14
|
+
import DdPicker from './components/dd-picker/dd-picker.vue'
|
|
15
|
+
import DdRate from './components/dd-rate/dd-rate.vue'
|
|
16
|
+
import DdUpload from './components/dd-upload/dd-upload.vue'
|
|
17
|
+
import DdIcon from './components/dd-icon/dd-icon.vue'
|
|
18
|
+
|
|
19
|
+
// === Navigation (12) ===
|
|
20
|
+
import DdNavigation from './components/dd-navigation/dd-navigation.vue'
|
|
21
|
+
import DdTopNavbar from './components/dd-top-navbar/dd-top-navbar.vue'
|
|
22
|
+
import DdSegmentedTab from './components/dd-segmented-tab/dd-segmented-tab.vue'
|
|
23
|
+
import DdSwipeableTab from './components/dd-swipeable-tab/dd-swipeable-tab.vue'
|
|
24
|
+
import DdDrawer from './components/dd-drawer/dd-drawer.vue'
|
|
25
|
+
import DdTabbar from './components/dd-tabbar/dd-tabbar.vue'
|
|
26
|
+
import DdTabbarItem from './components/dd-tabbar-item/dd-tabbar-item.vue'
|
|
27
|
+
import DdBacktop from './components/dd-backtop/dd-backtop.vue'
|
|
28
|
+
import DdCollapse from './components/dd-collapse/dd-collapse.vue'
|
|
29
|
+
import DdCollapseItem from './components/dd-collapse-item/dd-collapse-item.vue'
|
|
30
|
+
import DdDropdownMenu from './components/dd-dropdown-menu/dd-dropdown-menu.vue'
|
|
31
|
+
import DdDropdownItem from './components/dd-dropdown-item/dd-dropdown-item.vue'
|
|
32
|
+
|
|
33
|
+
// === Layout (4) ===
|
|
34
|
+
import DdCard from './components/dd-card/dd-card.vue'
|
|
35
|
+
import DdRoomCard from './components/dd-room-card/dd-room-card.vue'
|
|
36
|
+
import DdFeatureGrid from './components/dd-feature-grid/dd-feature-grid.vue'
|
|
37
|
+
import DdSticky from './components/dd-sticky/dd-sticky.vue'
|
|
38
|
+
|
|
39
|
+
// === Display (16) ===
|
|
40
|
+
import DdTag from './components/dd-tag/dd-tag.vue'
|
|
41
|
+
import DdStatCard from './components/dd-stat-card/dd-stat-card.vue'
|
|
42
|
+
import DdChampionCard from './components/dd-champion-card/dd-champion-card.vue'
|
|
43
|
+
import DdAvatar from './components/dd-avatar/dd-avatar.vue'
|
|
44
|
+
import DdBadge from './components/dd-badge/dd-badge.vue'
|
|
45
|
+
import DdListCell from './components/dd-list-cell/dd-list-cell.vue'
|
|
46
|
+
import DdCell from './components/dd-cell/dd-cell.vue'
|
|
47
|
+
import DdCellGroup from './components/dd-cell-group/dd-cell-group.vue'
|
|
48
|
+
import DdCountDown from './components/dd-count-down/dd-count-down.vue'
|
|
49
|
+
import DdDivider from './components/dd-divider/dd-divider.vue'
|
|
50
|
+
import DdImage from './components/dd-image/dd-image.vue'
|
|
51
|
+
import DdProgress from './components/dd-progress/dd-progress.vue'
|
|
52
|
+
import DdSkeleton from './components/dd-skeleton/dd-skeleton.vue'
|
|
53
|
+
import DdEmptyState from './components/dd-empty-state/dd-empty-state.vue'
|
|
54
|
+
import DdStep from './components/dd-step/dd-step.vue'
|
|
55
|
+
import DdSteps from './components/dd-steps/dd-steps.vue'
|
|
56
|
+
|
|
57
|
+
// === Overlay (10) ===
|
|
58
|
+
import DdModal from './components/dd-modal/dd-modal.vue'
|
|
59
|
+
import DdActionSheet from './components/dd-action-sheet/dd-action-sheet.vue'
|
|
60
|
+
import DdToast from './components/dd-toast/dd-toast.vue'
|
|
61
|
+
import DdAlert from './components/dd-alert/dd-alert.vue'
|
|
62
|
+
import DdLoading from './components/dd-loading/dd-loading.vue'
|
|
63
|
+
import DdDialog from './components/dd-dialog/dd-dialog.vue'
|
|
64
|
+
import DdOverlay from './components/dd-overlay/dd-overlay.vue'
|
|
65
|
+
import DdPopup from './components/dd-popup/dd-popup.vue'
|
|
66
|
+
import DdPopover from './components/dd-popover/dd-popover.vue'
|
|
67
|
+
import DdPopoverItem from './components/dd-popover-item/dd-popover-item.vue'
|
|
68
|
+
|
|
69
|
+
// === Interaction (5) ===
|
|
70
|
+
import DdSwipeAction from './components/dd-swipe-action/dd-swipe-action.vue'
|
|
71
|
+
import DdSwipe from './components/dd-swipe/dd-swipe.vue'
|
|
72
|
+
import DdSwipeItem from './components/dd-swipe-item/dd-swipe-item.vue'
|
|
73
|
+
import DdPullRefresh from './components/dd-pull-refresh/dd-pull-refresh.vue'
|
|
74
|
+
import DdLoadmore from './components/dd-loadmore/dd-loadmore.vue'
|
|
75
|
+
|
|
76
|
+
// === Mini Program (2) ===
|
|
77
|
+
import DdCapsuleButton from './components/dd-capsule-button/dd-capsule-button.vue'
|
|
78
|
+
import DdMiniProgramNavbar from './components/dd-mini-program-navbar/dd-mini-program-navbar.vue'
|
|
79
|
+
|
|
80
|
+
const components = {
|
|
81
|
+
DdButton, DdInput, DdSwitch, DdCheckbox, DdRadio,
|
|
82
|
+
DdSearchBar, DdSlider, DdStepper, DdDatePicker, DdField,
|
|
83
|
+
DdPicker, DdRate, DdUpload, DdIcon,
|
|
84
|
+
DdNavigation, DdTopNavbar, DdSegmentedTab, DdSwipeableTab,
|
|
85
|
+
DdDrawer, DdTabbar, DdTabbarItem, DdBacktop,
|
|
86
|
+
DdCollapse, DdCollapseItem, DdDropdownMenu, DdDropdownItem,
|
|
87
|
+
DdCard, DdRoomCard, DdFeatureGrid, DdSticky,
|
|
88
|
+
DdTag, DdStatCard, DdChampionCard, DdAvatar, DdBadge,
|
|
89
|
+
DdListCell, DdCell, DdCellGroup, DdCountDown, DdDivider,
|
|
90
|
+
DdImage, DdProgress, DdSkeleton, DdEmptyState, DdStep, DdSteps,
|
|
91
|
+
DdModal, DdActionSheet, DdToast, DdAlert, DdLoading,
|
|
92
|
+
DdDialog, DdOverlay, DdPopup, DdPopover, DdPopoverItem,
|
|
93
|
+
DdSwipeAction, DdSwipe, DdSwipeItem, DdPullRefresh, DdLoadmore,
|
|
94
|
+
DdCapsuleButton, DdMiniProgramNavbar,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function install(app: App) {
|
|
98
|
+
Object.entries(components).forEach(([name, comp]) => {
|
|
99
|
+
app.component(name, comp)
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export default { install }
|
|
104
|
+
|
|
105
|
+
// 全量具名导出
|
|
106
|
+
export {
|
|
107
|
+
components,
|
|
108
|
+
DdButton, DdInput, DdSwitch, DdCheckbox, DdRadio,
|
|
109
|
+
DdSearchBar, DdSlider, DdStepper, DdDatePicker, DdField,
|
|
110
|
+
DdPicker, DdRate, DdUpload, DdIcon,
|
|
111
|
+
DdNavigation, DdTopNavbar, DdSegmentedTab, DdSwipeableTab,
|
|
112
|
+
DdDrawer, DdTabbar, DdTabbarItem, DdBacktop,
|
|
113
|
+
DdCollapse, DdCollapseItem, DdDropdownMenu, DdDropdownItem,
|
|
114
|
+
DdCard, DdRoomCard, DdFeatureGrid, DdSticky,
|
|
115
|
+
DdTag, DdStatCard, DdChampionCard, DdAvatar, DdBadge,
|
|
116
|
+
DdListCell, DdCell, DdCellGroup, DdCountDown, DdDivider,
|
|
117
|
+
DdImage, DdProgress, DdSkeleton, DdEmptyState, DdStep, DdSteps,
|
|
118
|
+
DdModal, DdActionSheet, DdToast, DdAlert, DdLoading,
|
|
119
|
+
DdDialog, DdOverlay, DdPopup, DdPopover, DdPopoverItem,
|
|
120
|
+
DdSwipeAction, DdSwipe, DdSwipeItem, DdPullRefresh, DdLoadmore,
|
|
121
|
+
DdCapsuleButton, DdMiniProgramNavbar,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export * from './libs/utils'
|
|
125
|
+
|
|
126
|
+
// 图标元数据(供 demo/文档消费,与 dd-icon.vue 内 SCSS &-- 规则保持一致)
|
|
127
|
+
export { iconNames, iconGroups } from './components/dd-icon/dd-icon.vue'
|
package/libs/utils.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// DidaoUI-uniapp Utility Functions
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
// 平台检测
|
|
6
|
+
// ponytail: vue-tsc 不识别 #ifdef 注释,四个 const 块会被视为重复声明,
|
|
7
|
+
// 故改为单次 let 声明 + 条件编译赋值。代价:失去编译期常量的 tree-shake
|
|
8
|
+
// (升级路径:改用 process.env.UNI_PLATFORM 判定)。
|
|
9
|
+
export let isH5 = false
|
|
10
|
+
export let isMP = false
|
|
11
|
+
export let isMPWeixin = false
|
|
12
|
+
export let isMPToutiao = false
|
|
13
|
+
export let isApp = false
|
|
14
|
+
|
|
15
|
+
// #ifdef H5
|
|
16
|
+
isH5 = true
|
|
17
|
+
// #endif
|
|
18
|
+
// #ifdef MP-WEIXIN
|
|
19
|
+
isMP = true
|
|
20
|
+
isMPWeixin = true
|
|
21
|
+
// #endif
|
|
22
|
+
// #ifdef MP-TOUTIAO
|
|
23
|
+
isMP = true
|
|
24
|
+
isMPToutiao = true
|
|
25
|
+
// #endif
|
|
26
|
+
// #ifdef APP-PLUS
|
|
27
|
+
isApp = true
|
|
28
|
+
// #endif
|
|
29
|
+
|
|
30
|
+
// 防抖
|
|
31
|
+
export function debounce<T extends (...args: any[]) => any>(
|
|
32
|
+
fn: T,
|
|
33
|
+
delay = 300
|
|
34
|
+
): (...args: Parameters<T>) => void {
|
|
35
|
+
let timer: ReturnType<typeof setTimeout> | null = null
|
|
36
|
+
return (...args: Parameters<T>) => {
|
|
37
|
+
if (timer) clearTimeout(timer)
|
|
38
|
+
timer = setTimeout(() => fn(...args), delay)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// 节流
|
|
43
|
+
export function throttle<T extends (...args: any[]) => any>(
|
|
44
|
+
fn: T,
|
|
45
|
+
delay = 300
|
|
46
|
+
): (...args: Parameters<T>) => void {
|
|
47
|
+
let last = 0
|
|
48
|
+
return (...args: Parameters<T>) => {
|
|
49
|
+
const now = Date.now()
|
|
50
|
+
if (now - last >= delay) {
|
|
51
|
+
last = now
|
|
52
|
+
fn(...args)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// rpx → px (仅 H5 需要)
|
|
58
|
+
export function rpx2px(rpx: number): number {
|
|
59
|
+
// #ifdef H5
|
|
60
|
+
const screenWidth = window.screen.width
|
|
61
|
+
return (rpx / 750) * screenWidth
|
|
62
|
+
// #endif
|
|
63
|
+
// #ifndef H5
|
|
64
|
+
return rpx
|
|
65
|
+
// #endif
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 获取状态栏高度
|
|
69
|
+
export function getStatusBarHeight(): number {
|
|
70
|
+
// #ifdef H5
|
|
71
|
+
return 0
|
|
72
|
+
// #endif
|
|
73
|
+
// ponytail: 运行时兜底 —— 条件编译失效时(如 H5 构建配置错误),
|
|
74
|
+
// 防止走到 MP/APP 分支拿到非零 statusBarHeight
|
|
75
|
+
// #ifndef H5
|
|
76
|
+
const sysInfo = uni.getWindowInfo()
|
|
77
|
+
return sysInfo.statusBarHeight || 20
|
|
78
|
+
// #endif
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 获取胶囊按钮位置信息 (仅微信小程序)
|
|
82
|
+
export function getMenuButtonBoundingClientRect() {
|
|
83
|
+
// #ifdef MP-WEIXIN
|
|
84
|
+
return uni.getMenuButtonBoundingClientRect()
|
|
85
|
+
// #endif
|
|
86
|
+
// #ifndef MP-WEIXIN
|
|
87
|
+
return null
|
|
88
|
+
// #endif
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// 查询节点尺寸
|
|
92
|
+
export function getRect(selector: string): Promise<UniApp.NodeInfo> {
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
uni.createSelectorQuery()
|
|
95
|
+
.select(selector)
|
|
96
|
+
.boundingClientRect((rect) => {
|
|
97
|
+
resolve(rect as UniApp.NodeInfo)
|
|
98
|
+
})
|
|
99
|
+
.exec()
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// 获取事件值 (跨端兼容)
|
|
104
|
+
export function getEventValue(e: any): string {
|
|
105
|
+
return e?.detail?.value ?? e?.target?.value ?? ''
|
|
106
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@didaoktv/didaoui-uniapp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "帝到KTV UniApp 组件库",
|
|
5
|
+
"main": "index.ts",
|
|
6
|
+
"types": "index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./index.ts",
|
|
9
|
+
"./uni.scss": "./uni.scss",
|
|
10
|
+
"./scss/variables": "./scss/_variables.scss",
|
|
11
|
+
"./scss/mixins": "./scss/_mixins.scss",
|
|
12
|
+
"./scss/functions": "./scss/_functions.scss",
|
|
13
|
+
"./components/*": "./components/*"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"components/",
|
|
17
|
+
"scss/",
|
|
18
|
+
"libs/",
|
|
19
|
+
"index.ts",
|
|
20
|
+
"uni.scss"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"dev:h5": "cd ../DidaoUI-uniapp-docs/h5-demo && npm run dev:h5",
|
|
24
|
+
"build:docs": "cd ../DidaoUI-uniapp-docs && npm run build",
|
|
25
|
+
"type-check": "vue-tsc --noEmit",
|
|
26
|
+
"prepublishOnly": "node -e \"const p=require('./package.json');if(p.publishConfig&&p.publishConfig.access==='public'){process.exit(0)}console.error('publishConfig.access must be public');process.exit(1)\""
|
|
27
|
+
},
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"vue": "^3.4.0"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"vue": "^3.4.0",
|
|
36
|
+
"vue-tsc": "^2.0.0",
|
|
37
|
+
"typescript": "^5.4.0",
|
|
38
|
+
"sass": "^1.70.0",
|
|
39
|
+
"@dcloudio/types": "^3.4.8"
|
|
40
|
+
},
|
|
41
|
+
"keywords": [
|
|
42
|
+
"uniapp",
|
|
43
|
+
"vue3",
|
|
44
|
+
"ui",
|
|
45
|
+
"component-library",
|
|
46
|
+
"typescript",
|
|
47
|
+
"didaoktv"
|
|
48
|
+
],
|
|
49
|
+
"license": "MIT",
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "https://github.com/didaoktv/didaoui-uniapp"
|
|
53
|
+
},
|
|
54
|
+
"sideEffects": [
|
|
55
|
+
"*.scss",
|
|
56
|
+
"*.css"
|
|
57
|
+
]
|
|
58
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// DidaoUI-uniapp SCSS Functions
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
// px → rpx 转换 (750rpx = 375px 屏幕宽度)
|
|
6
|
+
@function dd-px-to-rpx($px) {
|
|
7
|
+
@return $px * 2rpx;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// 颜色变暗
|
|
11
|
+
@function dd-darken($color, $amount) {
|
|
12
|
+
@return darken($color, $amount);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// 颜色变亮
|
|
16
|
+
@function dd-lighten($color, $amount) {
|
|
17
|
+
@return lighten($color, $amount);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 色阶获取
|
|
21
|
+
@function dd-color($name, $level: 500) {
|
|
22
|
+
$map: (
|
|
23
|
+
primary: (
|
|
24
|
+
50: $dd-primary-50, 100: $dd-primary-100, 200: $dd-primary-200,
|
|
25
|
+
300: $dd-primary-300, 400: $dd-primary-400, 500: $dd-primary-500,
|
|
26
|
+
600: $dd-primary-600, 700: $dd-primary-700, 800: $dd-primary-800,
|
|
27
|
+
900: $dd-primary-900,
|
|
28
|
+
),
|
|
29
|
+
accent: (
|
|
30
|
+
50: $dd-accent-50, 100: $dd-accent-100, 200: $dd-accent-200,
|
|
31
|
+
300: $dd-accent-300, 400: $dd-accent-400, 500: $dd-accent-500,
|
|
32
|
+
600: $dd-accent-600, 700: $dd-accent-700, 800: $dd-accent-800,
|
|
33
|
+
900: $dd-accent-900,
|
|
34
|
+
),
|
|
35
|
+
neutral: (
|
|
36
|
+
50: $dd-neutral-50, 100: $dd-neutral-100, 200: $dd-neutral-200,
|
|
37
|
+
300: $dd-neutral-300, 400: $dd-neutral-400, 500: $dd-neutral-500,
|
|
38
|
+
600: $dd-neutral-600, 700: $dd-neutral-700, 800: $dd-neutral-800,
|
|
39
|
+
900: $dd-neutral-900,
|
|
40
|
+
),
|
|
41
|
+
success: (
|
|
42
|
+
50: $dd-success-50, 100: $dd-success-100, 200: $dd-success-200,
|
|
43
|
+
300: $dd-success-300, 400: $dd-success-400, 500: $dd-success-500,
|
|
44
|
+
600: $dd-success-600, 700: $dd-success-700, 800: $dd-success-800,
|
|
45
|
+
900: $dd-success-900,
|
|
46
|
+
),
|
|
47
|
+
warning: (
|
|
48
|
+
50: $dd-warning-50, 100: $dd-warning-100, 200: $dd-warning-200,
|
|
49
|
+
300: $dd-warning-300, 400: $dd-warning-400, 500: $dd-warning-500,
|
|
50
|
+
600: $dd-warning-600, 700: $dd-warning-700, 800: $dd-warning-800,
|
|
51
|
+
900: $dd-warning-900,
|
|
52
|
+
),
|
|
53
|
+
error: (
|
|
54
|
+
50: $dd-error-50, 100: $dd-error-100, 200: $dd-error-200,
|
|
55
|
+
300: $dd-error-300, 400: $dd-error-400, 500: $dd-error-500,
|
|
56
|
+
600: $dd-error-600, 700: $dd-error-700, 800: $dd-error-800,
|
|
57
|
+
900: $dd-error-900,
|
|
58
|
+
),
|
|
59
|
+
info: (
|
|
60
|
+
50: $dd-info-50, 100: $dd-info-100, 200: $dd-info-200,
|
|
61
|
+
300: $dd-info-300, 400: $dd-info-400, 500: $dd-info-500,
|
|
62
|
+
600: $dd-info-600, 700: $dd-info-700, 800: $dd-info-800,
|
|
63
|
+
900: $dd-info-900,
|
|
64
|
+
),
|
|
65
|
+
);
|
|
66
|
+
$group: map-get($map, $name);
|
|
67
|
+
@return map-get($group, $level);
|
|
68
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// DidaoUI-uniapp SCSS Mixins
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
// 玻璃拟态 (H5: backdrop-filter; MP: 降级为 solid bg)
|
|
6
|
+
@mixin dd-glass($intensity: default) {
|
|
7
|
+
$blur: $dd-glass-blur;
|
|
8
|
+
@if $intensity == sm { $blur: $dd-glass-blur-sm; }
|
|
9
|
+
@else if $intensity == md { $blur: $dd-glass-blur-md; }
|
|
10
|
+
@else if $intensity == lg { $blur: $dd-glass-blur-lg; }
|
|
11
|
+
background: $dd-glass-bg;
|
|
12
|
+
border: 1px solid $dd-glass-border;
|
|
13
|
+
/* #ifdef H5 */
|
|
14
|
+
backdrop-filter: blur($blur);
|
|
15
|
+
-webkit-backdrop-filter: blur($blur);
|
|
16
|
+
/* #endif */
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@mixin dd-glass-strong {
|
|
20
|
+
background: $dd-glass-bg-strong;
|
|
21
|
+
border: 1px solid $dd-glass-border;
|
|
22
|
+
/* #ifdef H5 */
|
|
23
|
+
backdrop-filter: blur($dd-glass-blur);
|
|
24
|
+
-webkit-backdrop-filter: blur($dd-glass-blur);
|
|
25
|
+
/* #endif */
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// 发光阴影 — 支持 size: sm / md / lg
|
|
29
|
+
@mixin dd-glow($color: gold, $size: md) {
|
|
30
|
+
$shadows: (
|
|
31
|
+
gold-sm: $dd-shadow-glow-gold-sm,
|
|
32
|
+
gold-md: $dd-shadow-glow-gold-md,
|
|
33
|
+
gold-lg: $dd-shadow-glow-gold-lg,
|
|
34
|
+
blue-sm: $dd-shadow-glow-blue-sm,
|
|
35
|
+
blue-md: $dd-shadow-glow-blue-md,
|
|
36
|
+
blue-lg: $dd-shadow-glow-blue-lg,
|
|
37
|
+
success-sm: $dd-shadow-glow-success-sm,
|
|
38
|
+
success-md: $dd-shadow-glow-success-md,
|
|
39
|
+
success-lg: $dd-shadow-glow-success-lg,
|
|
40
|
+
warning-sm: $dd-shadow-glow-warning-sm,
|
|
41
|
+
warning-md: $dd-shadow-glow-warning-md,
|
|
42
|
+
warning-lg: $dd-shadow-glow-warning-lg,
|
|
43
|
+
error-sm: $dd-shadow-glow-error-sm,
|
|
44
|
+
error-md: $dd-shadow-glow-error-md,
|
|
45
|
+
error-lg: $dd-shadow-glow-error-lg,
|
|
46
|
+
info-sm: $dd-shadow-glow-info-sm,
|
|
47
|
+
info-md: $dd-shadow-glow-info-md,
|
|
48
|
+
info-lg: $dd-shadow-glow-info-lg,
|
|
49
|
+
vip-sm: $dd-shadow-glow-vip-sm,
|
|
50
|
+
vip-md: $dd-shadow-glow-vip-md,
|
|
51
|
+
vip-lg: $dd-shadow-glow-vip-lg,
|
|
52
|
+
);
|
|
53
|
+
$key: $color + '-' + $size;
|
|
54
|
+
box-shadow: map-get($shadows, $key);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 文字渐变
|
|
58
|
+
@mixin dd-text-gradient($color: gold) {
|
|
59
|
+
$gradients: (
|
|
60
|
+
gold: $dd-gradient-text-gold,
|
|
61
|
+
'gold-light': $dd-gradient-text-gold-light,
|
|
62
|
+
blue: $dd-gradient-text-blue,
|
|
63
|
+
);
|
|
64
|
+
background: map-get($gradients, $color);
|
|
65
|
+
-webkit-background-clip: text;
|
|
66
|
+
-webkit-text-fill-color: transparent;
|
|
67
|
+
background-clip: text;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// 文本溢出省略
|
|
71
|
+
@mixin dd-ellipsis($lines: 1) {
|
|
72
|
+
@if $lines == 1 {
|
|
73
|
+
overflow: hidden;
|
|
74
|
+
text-overflow: ellipsis;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
} @else {
|
|
77
|
+
display: -webkit-box;
|
|
78
|
+
-webkit-box-orient: vertical;
|
|
79
|
+
-webkit-line-clamp: $lines;
|
|
80
|
+
overflow: hidden;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 安全区域
|
|
85
|
+
@mixin dd-safe-area-top {
|
|
86
|
+
padding-top: var(--status-bar-height, 20px);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@mixin dd-safe-area-bottom {
|
|
90
|
+
padding-bottom: constant(safe-area-inset-bottom);
|
|
91
|
+
padding-bottom: env(safe-area-inset-bottom);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 1px 边框 (retina)
|
|
95
|
+
@mixin dd-hairline-bottom($color: $dd-border-default) {
|
|
96
|
+
position: relative;
|
|
97
|
+
&::after {
|
|
98
|
+
content: '';
|
|
99
|
+
position: absolute;
|
|
100
|
+
left: 0;
|
|
101
|
+
right: 0;
|
|
102
|
+
bottom: 0;
|
|
103
|
+
height: 1px;
|
|
104
|
+
background: $color;
|
|
105
|
+
transform: scaleY(0.5);
|
|
106
|
+
transform-origin: 0 100%;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@mixin dd-hairline-top($color: $dd-border-default) {
|
|
111
|
+
position: relative;
|
|
112
|
+
&::before {
|
|
113
|
+
content: '';
|
|
114
|
+
position: absolute;
|
|
115
|
+
left: 0;
|
|
116
|
+
right: 0;
|
|
117
|
+
top: 0;
|
|
118
|
+
height: 1px;
|
|
119
|
+
background: $color;
|
|
120
|
+
transform: scaleY(0.5);
|
|
121
|
+
transform-origin: 0 0;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// flex 居中
|
|
126
|
+
@mixin dd-flex-center {
|
|
127
|
+
display: flex;
|
|
128
|
+
align-items: center;
|
|
129
|
+
justify-content: center;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
@mixin dd-flex-between {
|
|
133
|
+
display: flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
justify-content: space-between;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 过渡:arglist 直传
|
|
139
|
+
// 支持单属性 dd-transition(transform 0.3s ease) 与多属性
|
|
140
|
+
// dd-transition(opacity 0.3s, transform 0.3s);旧的位置参数写法
|
|
141
|
+
// (transform, 0.3s, ease) 会把第二段时间值当成 CSS delay,造成隐性延时
|
|
142
|
+
@mixin dd-transition($args...) {
|
|
143
|
+
@if length($args) == 0 {
|
|
144
|
+
transition: all 0.3s linear;
|
|
145
|
+
} @else {
|
|
146
|
+
transition: $args;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 禁止点击
|
|
151
|
+
@mixin dd-no-touch {
|
|
152
|
+
pointer-events: none;
|
|
153
|
+
user-select: none;
|
|
154
|
+
}
|