uview-pro 0.0.1
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/changelog.md +6 -0
- package/components/u-action-sheet/u-action-sheet.vue +205 -0
- package/components/u-alert-tips/u-alert-tips.vue +241 -0
- package/components/u-avatar/u-avatar.vue +220 -0
- package/components/u-avatar-cropper/u-avatar-cropper.vue +329 -0
- package/components/u-avatar-cropper/weCropper.d.ts +54 -0
- package/components/u-avatar-cropper/weCropper.js +1267 -0
- package/components/u-avatar-cropper/weCropper.ts +1254 -0
- package/components/u-back-top/u-back-top.vue +156 -0
- package/components/u-badge/u-badge.vue +189 -0
- package/components/u-button/u-button.vue +562 -0
- package/components/u-calendar/u-calendar.vue +725 -0
- package/components/u-car-keyboard/u-car-keyboard.vue +236 -0
- package/components/u-card/u-card.vue +240 -0
- package/components/u-cell-group/u-cell-group.vue +56 -0
- package/components/u-cell-item/u-cell-item.vue +245 -0
- package/components/u-checkbox/u-checkbox.vue +310 -0
- package/components/u-checkbox-group/u-checkbox-group.vue +134 -0
- package/components/u-circle-progress/u-circle-progress.vue +210 -0
- package/components/u-col/u-col.vue +135 -0
- package/components/u-collapse/u-collapse.vue +82 -0
- package/components/u-collapse-item/u-collapse-item.vue +190 -0
- package/components/u-column-notice/u-column-notice.vue +264 -0
- package/components/u-count-down/u-count-down.vue +333 -0
- package/components/u-count-to/u-count-to.vue +297 -0
- package/components/u-divider/u-divider.vue +141 -0
- package/components/u-dropdown/u-dropdown.vue +311 -0
- package/components/u-dropdown-item/u-dropdown-item.vue +135 -0
- package/components/u-empty/u-empty.vue +111 -0
- package/components/u-field/u-field.vue +469 -0
- package/components/u-form/u-form.vue +162 -0
- package/components/u-form-item/u-form-item.vue +476 -0
- package/components/u-full-screen/u-full-screen.vue +80 -0
- package/components/u-gap/u-gap.vue +48 -0
- package/components/u-grid/u-grid.vue +101 -0
- package/components/u-grid-item/u-grid-item.vue +136 -0
- package/components/u-icon/u-icon.vue +389 -0
- package/components/u-image/types.ts +48 -0
- package/components/u-image/u-image.vue +218 -0
- package/components/u-index-anchor/u-index-anchor.vue +101 -0
- package/components/u-index-list/u-index-list.vue +376 -0
- package/components/u-input/u-input.vue +462 -0
- package/components/u-keyboard/u-keyboard.vue +188 -0
- package/components/u-lazy-load/u-lazy-load.vue +288 -0
- package/components/u-line/u-line.vue +71 -0
- package/components/u-line-progress/u-line-progress.vue +128 -0
- package/components/u-link/u-link.vue +87 -0
- package/components/u-loading/u-loading.vue +111 -0
- package/components/u-loadmore/u-loadmore.vue +205 -0
- package/components/u-mask/u-mask.vue +137 -0
- package/components/u-message-input/u-message-input.vue +315 -0
- package/components/u-modal/u-modal.vue +284 -0
- package/components/u-navbar/u-navbar.vue +314 -0
- package/components/u-no-network/image.ts +2 -0
- package/components/u-no-network/u-no-network.vue +311 -0
- package/components/u-notice-bar/u-notice-bar.vue +274 -0
- package/components/u-number-box/u-number-box.vue +344 -0
- package/components/u-number-keyboard/u-number-keyboard.vue +170 -0
- package/components/u-parse/libs/CssHandler.js +100 -0
- package/components/u-parse/libs/MpHtmlParser.js +580 -0
- package/components/u-parse/libs/config.js +80 -0
- package/components/u-parse/libs/handler.wxs +22 -0
- package/components/u-parse/libs/trees.vue +505 -0
- package/components/u-parse/u-parse.vue +645 -0
- package/components/u-picker/u-picker.vue +808 -0
- package/components/u-popup/u-popup.vue +404 -0
- package/components/u-radio/u-radio.vue +272 -0
- package/components/u-radio-group/u-radio-group.vue +116 -0
- package/components/u-rate/u-rate.vue +349 -0
- package/components/u-read-more/u-read-more.vue +199 -0
- package/components/u-row/u-row.vue +95 -0
- package/components/u-row-notice/u-row-notice.vue +273 -0
- package/components/u-search/u-search.vue +298 -0
- package/components/u-section/u-section.vue +175 -0
- package/components/u-select/u-select.vue +387 -0
- package/components/u-skeleton/u-skeleton.vue +230 -0
- package/components/u-slider/u-slider.vue +293 -0
- package/components/u-steps/u-steps.vue +200 -0
- package/components/u-sticky/u-sticky.vue +189 -0
- package/components/u-subsection/u-subsection.vue +388 -0
- package/components/u-swipe-action/u-swipe-action.vue +289 -0
- package/components/u-swiper/u-swiper.vue +305 -0
- package/components/u-switch/u-switch.vue +146 -0
- package/components/u-tabbar/u-tabbar.vue +347 -0
- package/components/u-table/u-table.vue +104 -0
- package/components/u-tabs/u-tabs.vue +322 -0
- package/components/u-tabs-swiper/u-tabs-swiper.vue +426 -0
- package/components/u-tag/u-tag.vue +270 -0
- package/components/u-td/u-td.vue +76 -0
- package/components/u-th/u-th.vue +70 -0
- package/components/u-time-line/u-time-line.vue +39 -0
- package/components/u-time-line-item/u-time-line-item.vue +88 -0
- package/components/u-toast/types.ts +4 -0
- package/components/u-toast/u-toast.vue +238 -0
- package/components/u-top-tips/u-top-tips.vue +118 -0
- package/components/u-tr/u-tr.vue +24 -0
- package/components/u-upload/u-upload.vue +600 -0
- package/components/u-verification-code/u-verification-code.vue +194 -0
- package/components/u-waterfall/u-waterfall.vue +186 -0
- package/iconfont.css +910 -0
- package/index.scss +23 -0
- package/index.ts +166 -0
- package/libs/config/config.ts +26 -0
- package/libs/config/zIndex.ts +37 -0
- package/libs/css/color.scss +155 -0
- package/libs/css/common.scss +176 -0
- package/libs/css/style.components.scss +7 -0
- package/libs/css/style.h5.scss +8 -0
- package/libs/css/style.mp.scss +72 -0
- package/libs/css/style.nvue.scss +3 -0
- package/libs/css/style.vue.scss +175 -0
- package/libs/function/$parent.ts +22 -0
- package/libs/function/addUnit.ts +13 -0
- package/libs/function/color.ts +37 -0
- package/libs/function/colorGradient.ts +123 -0
- package/libs/function/debounce.ts +28 -0
- package/libs/function/deepClone.ts +39 -0
- package/libs/function/deepMerge.ts +34 -0
- package/libs/function/getParent.ts +59 -0
- package/libs/function/getRect.ts +26 -0
- package/libs/function/guid.ts +42 -0
- package/libs/function/md5.ts +397 -0
- package/libs/function/parent.ts +21 -0
- package/libs/function/queryParams.ts +60 -0
- package/libs/function/random.ts +16 -0
- package/libs/function/randomArray.ts +11 -0
- package/libs/function/route.ts +118 -0
- package/libs/function/sys.ts +15 -0
- package/libs/function/test.ts +229 -0
- package/libs/function/throttle.ts +31 -0
- package/libs/function/timeFormat.ts +54 -0
- package/libs/function/timeFrom.ts +48 -0
- package/libs/function/toast.ts +14 -0
- package/libs/function/trim.ts +21 -0
- package/libs/function/type2icon.ts +36 -0
- package/libs/hooks/useEmitter.ts +77 -0
- package/libs/hooks/useParent.ts +29 -0
- package/libs/request/index.ts +237 -0
- package/libs/store/index.ts +88 -0
- package/libs/util/area.ts +1 -0
- package/libs/util/async-validator.js +1356 -0
- package/libs/util/city.ts +1 -0
- package/libs/util/emitter.ts +112 -0
- package/libs/util/mitt.ts +118 -0
- package/libs/util/parent.ts +20 -0
- package/libs/util/province.ts +1 -0
- package/package.json +98 -0
- package/readme.md +165 -0
- package/theme.scss +38 -0
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="u-dropdown">
|
|
3
|
+
<view class="u-dropdown__menu" :style="{ height: $u.addUnit(height) }" :class="{ 'u-border-bottom': borderBottom }">
|
|
4
|
+
<view class="u-dropdown__menu__item" v-for="(item, index) in menuList" :key="index" @tap.stop="menuClick(index)">
|
|
5
|
+
<view class="u-flex">
|
|
6
|
+
<text
|
|
7
|
+
class="u-dropdown__menu__item__text"
|
|
8
|
+
:style="{
|
|
9
|
+
color: item.disabled ? '#c0c4cc' : index === current || highlightIndex == index ? activeColor : inactiveColor,
|
|
10
|
+
fontSize: $u.addUnit(titleSize)
|
|
11
|
+
}"
|
|
12
|
+
>{{ item.title }}</text
|
|
13
|
+
>
|
|
14
|
+
<view
|
|
15
|
+
class="u-dropdown__menu__item__arrow"
|
|
16
|
+
:class="{
|
|
17
|
+
'u-dropdown__menu__item__arrow--rotate': index === current
|
|
18
|
+
}"
|
|
19
|
+
>
|
|
20
|
+
<u-icon
|
|
21
|
+
:custom-style="{ display: 'flex' }"
|
|
22
|
+
:name="menuIcon"
|
|
23
|
+
:size="$u.addUnit(menuIconSize)"
|
|
24
|
+
:color="index === current || highlightIndex == index ? activeColor : '#c0c4cc'"
|
|
25
|
+
></u-icon>
|
|
26
|
+
</view>
|
|
27
|
+
</view>
|
|
28
|
+
</view>
|
|
29
|
+
</view>
|
|
30
|
+
<view
|
|
31
|
+
class="u-dropdown__content"
|
|
32
|
+
:style="[
|
|
33
|
+
contentStyle,
|
|
34
|
+
{
|
|
35
|
+
transition: `opacity ${Number(duration) / 1000}s linear`,
|
|
36
|
+
top: $u.addUnit(height),
|
|
37
|
+
height: contentHeight + 'px'
|
|
38
|
+
}
|
|
39
|
+
]"
|
|
40
|
+
@tap="maskClick"
|
|
41
|
+
@touchmove.stop.prevent
|
|
42
|
+
>
|
|
43
|
+
<view @tap.stop.prevent class="u-dropdown__content__popup" :style="[popupStyle]">
|
|
44
|
+
<slot></slot>
|
|
45
|
+
</view>
|
|
46
|
+
<view class="u-dropdown__content__mask"></view>
|
|
47
|
+
</view>
|
|
48
|
+
</view>
|
|
49
|
+
</template>
|
|
50
|
+
|
|
51
|
+
<script setup lang="ts">
|
|
52
|
+
import { ref, computed, onMounted, getCurrentInstance } from 'vue';
|
|
53
|
+
import { $u } from '../..';
|
|
54
|
+
|
|
55
|
+
defineOptions({ name: 'u-dropdown' });
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* dropdown 下拉菜单
|
|
59
|
+
* @description 该组件一般用于向下展开菜单,同时可切换多个选项卡的场景
|
|
60
|
+
* @tutorial http://uviewui.com/components/dropdown.html
|
|
61
|
+
* @property {String} active-color 标题和选项卡选中的颜色(默认#2979ff)
|
|
62
|
+
* @property {String} inactive-color 标题和选项卡未选中的颜色(默认#606266)
|
|
63
|
+
* @property {Boolean} close-on-click-mask 点击遮罩是否关闭菜单(默认true)
|
|
64
|
+
* @property {Boolean} close-on-click-self 点击当前激活项标题是否关闭菜单(默认true)
|
|
65
|
+
* @property {String | Number} duration 选项卡展开和收起的过渡时间,单位ms(默认300)
|
|
66
|
+
* @property {String | Number} height 标题菜单的高度,单位任意(默认80)
|
|
67
|
+
* @property {String | Number} border-radius 菜单展开内容下方的圆角值,单位任意(默认0)
|
|
68
|
+
* @property {Boolean} border-bottom 标题菜单是否显示下边框(默认false)
|
|
69
|
+
* @property {String | Number} title-size 标题的字体大小,单位任意,数值默认为rpx单位(默认28)
|
|
70
|
+
* @event {Function} open 下拉菜单被打开时触发
|
|
71
|
+
* @event {Function} close 下拉菜单被关闭时触发
|
|
72
|
+
* @example <u-dropdown></u-dropdown>
|
|
73
|
+
*/
|
|
74
|
+
|
|
75
|
+
const props = defineProps({
|
|
76
|
+
/** 菜单标题和选项的激活态颜色 */
|
|
77
|
+
activeColor: { type: String, default: '#2979ff' },
|
|
78
|
+
/** 菜单标题和选项的未激活态颜色 */
|
|
79
|
+
inactiveColor: { type: String, default: '#606266' },
|
|
80
|
+
/** 点击遮罩是否关闭菜单 */
|
|
81
|
+
closeOnClickMask: { type: Boolean, default: true },
|
|
82
|
+
/** 点击当前激活项标题是否关闭菜单 */
|
|
83
|
+
closeOnClickSelf: { type: Boolean, default: true },
|
|
84
|
+
/** 过渡时间 */
|
|
85
|
+
duration: { type: [Number, String], default: 300 },
|
|
86
|
+
/** 标题菜单的高度,单位任意,数值默认为rpx单位 */
|
|
87
|
+
height: { type: [Number, String], default: 80 },
|
|
88
|
+
/** 是否显示下边框 */
|
|
89
|
+
borderBottom: { type: Boolean, default: false },
|
|
90
|
+
/** 标题的字体大小 */
|
|
91
|
+
titleSize: { type: [Number, String], default: 28 },
|
|
92
|
+
/** 下拉出来的内容部分的圆角值 */
|
|
93
|
+
borderRadius: { type: [Number, String], default: 0 },
|
|
94
|
+
/** 菜单右侧的icon图标 */
|
|
95
|
+
menuIcon: { type: String, default: 'arrow-down' },
|
|
96
|
+
/** 菜单右侧图标的大小 */
|
|
97
|
+
menuIconSize: { type: [Number, String], default: 26 }
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// emits 定义
|
|
101
|
+
const emit = defineEmits(['open', 'close']);
|
|
102
|
+
|
|
103
|
+
// 菜单列表
|
|
104
|
+
const menuList = ref<any[]>([]);
|
|
105
|
+
// 是否打开下拉菜单
|
|
106
|
+
const showDropdown = ref(true);
|
|
107
|
+
// 下拉菜单的状态
|
|
108
|
+
const active = ref(false);
|
|
109
|
+
// 当前激活菜单索引
|
|
110
|
+
// 当前是第几个菜单处于激活状态,小程序中此处不能写成false或者"",否则后续将current赋值为0,
|
|
111
|
+
// 无能的TX没有使用===而是使用==判断,导致程序认为前后二者没有变化,从而不会触发视图更新
|
|
112
|
+
const current = ref<number>(99999);
|
|
113
|
+
// 外层内容样式
|
|
114
|
+
const contentStyle = ref<any>({ zIndex: -1, opacity: 0 });
|
|
115
|
+
// 高亮菜单索引
|
|
116
|
+
const highlightIndex = ref<number>(99999);
|
|
117
|
+
// 下拉内容高度
|
|
118
|
+
const contentHeight = ref<number>(0);
|
|
119
|
+
// 子组件引用
|
|
120
|
+
// 引用所有子组件(u-dropdown-item)的this,不能在data中声明变量,否则在微信小程序会造成循环引用而报错
|
|
121
|
+
const children = ref<any[]>([]);
|
|
122
|
+
const instance = getCurrentInstance();
|
|
123
|
+
|
|
124
|
+
// 下拉出来部分的样式
|
|
125
|
+
const popupStyle = computed<any>(() => {
|
|
126
|
+
const style: any = {};
|
|
127
|
+
// 进行Y轴位移,展开状态时,恢复原位。收齐状态时,往上位移100%,进行隐藏
|
|
128
|
+
style.transform = `translateY(${active.value ? 0 : '-100%'})`;
|
|
129
|
+
style['transition-duration'] = Number(props.duration) / 1000 + 's';
|
|
130
|
+
style.borderRadius = `0 0 ${$u.addUnit(props.borderRadius)} ${$u.addUnit(props.borderRadius)}`;
|
|
131
|
+
return style;
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// 生命周期
|
|
135
|
+
onMounted(() => {
|
|
136
|
+
getContentHeight();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// 引用所有子组件(u-dropdown-item)的this,不能在data中声明变量,否则在微信小程序会造成循环引用而报错
|
|
140
|
+
children.value = [];
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 初始化所有子组件
|
|
144
|
+
* 当某个子组件内容变化时,触发父组件的init,父组件再让每一个子组件重新初始化一遍
|
|
145
|
+
* 以保证数据的正确性
|
|
146
|
+
*/
|
|
147
|
+
function init() {
|
|
148
|
+
menuList.value = [];
|
|
149
|
+
children.value.forEach(child => {
|
|
150
|
+
child.init && child.init();
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* 点击菜单
|
|
156
|
+
* @param index 菜单索引
|
|
157
|
+
*/
|
|
158
|
+
function menuClick(index: number) {
|
|
159
|
+
// 判断是否被禁用
|
|
160
|
+
if (menuList.value[index]?.disabled) return;
|
|
161
|
+
// 如果点击时的索引和当前激活项索引相同,意味着点击了激活项,需要收起下拉菜单
|
|
162
|
+
if (index === current.value && props.closeOnClickSelf) {
|
|
163
|
+
close();
|
|
164
|
+
// 等动画结束后,再移除下拉菜单中的内容,否则直接移除,也就没有下拉菜单收起的效果了
|
|
165
|
+
setTimeout(() => {
|
|
166
|
+
if (children.value[index]) children.value[index].active = false;
|
|
167
|
+
}, Number(props.duration));
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
open(index);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 打开下拉菜单
|
|
175
|
+
* @param index 菜单索引
|
|
176
|
+
*/
|
|
177
|
+
function open(index: number) {
|
|
178
|
+
// 嵌套popup使用时可能获取不到正确的高度,重新计算
|
|
179
|
+
if (contentHeight.value < 1) getContentHeight();
|
|
180
|
+
// 重置高亮索引,否则会造成多个菜单同时高亮
|
|
181
|
+
// highlightIndex.value = 9999;
|
|
182
|
+
// 展开时,设置下拉内容的样式
|
|
183
|
+
contentStyle.value = { zIndex: 11 };
|
|
184
|
+
// 标记展开状态以及当前展开项的索引
|
|
185
|
+
active.value = true;
|
|
186
|
+
current.value = index;
|
|
187
|
+
// 历遍所有的子元素,将索引匹配的项标记为激活状态,因为子元素是通过v-if控制切换的
|
|
188
|
+
// 之所以不是因display: none,是因为nvue没有display这个属性
|
|
189
|
+
children.value.forEach((val, idx) => {
|
|
190
|
+
val.exposed.setActive && val.exposed.setActive(index == idx ? true : false);
|
|
191
|
+
});
|
|
192
|
+
emit('open', current.value);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* 设置下拉菜单处于收起状态
|
|
197
|
+
*/
|
|
198
|
+
function close() {
|
|
199
|
+
emit('close', current.value);
|
|
200
|
+
// 设置为收起状态,同时current归位,设置为空字符串
|
|
201
|
+
active.value = false;
|
|
202
|
+
current.value = 99999;
|
|
203
|
+
// 下拉内容的样式进行调整,不透明度设置为0
|
|
204
|
+
contentStyle.value = { zIndex: -1, opacity: 0 };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* 点击遮罩
|
|
209
|
+
*/
|
|
210
|
+
function maskClick() {
|
|
211
|
+
// 如果不允许点击遮罩,直接返回
|
|
212
|
+
if (!props.closeOnClickMask) return;
|
|
213
|
+
close();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* 外部手动设置某个菜单高亮
|
|
218
|
+
* @param index 菜单索引
|
|
219
|
+
*/
|
|
220
|
+
function highlight(index?: number) {
|
|
221
|
+
highlightIndex.value = index !== undefined ? index : 99999;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* 获取下拉菜单内容的高度
|
|
226
|
+
* 这里的原理为,因为dropdown组件是相对定位的,它的下拉出来的内容,必须给定一个高度
|
|
227
|
+
* 才能让遮罩占满菜单一下,直到屏幕底部的高度
|
|
228
|
+
* this.$u.sys()为uView封装的获取设备信息的方法
|
|
229
|
+
*/
|
|
230
|
+
function getContentHeight() {
|
|
231
|
+
const windowHeight = $u.sys().windowHeight;
|
|
232
|
+
|
|
233
|
+
$u.getRect('.u-dropdown__menu', instance).then((res: any) => {
|
|
234
|
+
// 这里获取的是dropdown的尺寸,在H5上,uniapp获取尺寸是有bug的(以前提出修复过,后来又出现了此bug,目前hx2.8.11版本)
|
|
235
|
+
// H5端bug表现为元素尺寸的top值为导航栏底部到到元素的上边沿的距离,但是元素的bottom值确是导航栏顶部到元素底部的距离
|
|
236
|
+
// 二者是互相矛盾的,本质原因是H5端导航栏非原生,uni的开发者大意造成
|
|
237
|
+
// 这里取菜单栏的botton值合理的,不能用res.top,否则页面会造成滚动
|
|
238
|
+
contentHeight.value = windowHeight - res.bottom;
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// 暴露方法
|
|
243
|
+
defineExpose({ init, close, open, highlight, getContentHeight, children, menuList });
|
|
244
|
+
</script>
|
|
245
|
+
|
|
246
|
+
<style scoped lang="scss">
|
|
247
|
+
@import '../../libs/css/style.components.scss';
|
|
248
|
+
|
|
249
|
+
.u-dropdown {
|
|
250
|
+
flex: 1;
|
|
251
|
+
width: 100%;
|
|
252
|
+
position: relative;
|
|
253
|
+
|
|
254
|
+
&__menu {
|
|
255
|
+
@include vue-flex;
|
|
256
|
+
position: relative;
|
|
257
|
+
z-index: 11;
|
|
258
|
+
height: 80rpx;
|
|
259
|
+
|
|
260
|
+
&__item {
|
|
261
|
+
flex: 1;
|
|
262
|
+
@include vue-flex;
|
|
263
|
+
justify-content: center;
|
|
264
|
+
align-items: center;
|
|
265
|
+
|
|
266
|
+
&__text {
|
|
267
|
+
font-size: 28rpx;
|
|
268
|
+
color: $u-content-color;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
&__arrow {
|
|
272
|
+
margin-left: 6rpx;
|
|
273
|
+
transition: transform 0.3s;
|
|
274
|
+
align-items: center;
|
|
275
|
+
@include vue-flex;
|
|
276
|
+
|
|
277
|
+
&--rotate {
|
|
278
|
+
transform: rotate(180deg);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
&__content {
|
|
285
|
+
position: absolute;
|
|
286
|
+
z-index: 8;
|
|
287
|
+
width: 100%;
|
|
288
|
+
left: 0px;
|
|
289
|
+
bottom: 0;
|
|
290
|
+
overflow: hidden;
|
|
291
|
+
|
|
292
|
+
&__mask {
|
|
293
|
+
position: absolute;
|
|
294
|
+
z-index: 9;
|
|
295
|
+
background: rgba(0, 0, 0, 0.3);
|
|
296
|
+
width: 100%;
|
|
297
|
+
left: 0;
|
|
298
|
+
top: 0;
|
|
299
|
+
bottom: 0;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
&__popup {
|
|
303
|
+
position: relative;
|
|
304
|
+
z-index: 10;
|
|
305
|
+
transition: all 0.3s;
|
|
306
|
+
transform: translate3D(0, -100%, 0);
|
|
307
|
+
overflow: hidden;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
</style>
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="u-dropdown-item" v-if="active" @touchmove.stop.prevent @tap.stop.prevent>
|
|
3
|
+
<block v-if="!slots.default && !slots.$default">
|
|
4
|
+
<scroll-view scroll-y="true" :style="{ height: $u.addUnit(height) }">
|
|
5
|
+
<view class="u-dropdown-item__options">
|
|
6
|
+
<u-cell-group>
|
|
7
|
+
<u-cell-item
|
|
8
|
+
@click="cellClick(item.value)"
|
|
9
|
+
:arrow="false"
|
|
10
|
+
:title="item.label"
|
|
11
|
+
v-for="(item, index) in options"
|
|
12
|
+
:key="index"
|
|
13
|
+
:title-style="{ color: modelValue == item.value ? activeColor : inactiveColor }"
|
|
14
|
+
>
|
|
15
|
+
<u-icon v-if="modelValue == item.value" name="checkbox-mark" :color="activeColor" size="32"></u-icon>
|
|
16
|
+
</u-cell-item>
|
|
17
|
+
</u-cell-group>
|
|
18
|
+
</view>
|
|
19
|
+
</scroll-view>
|
|
20
|
+
</block>
|
|
21
|
+
<slot v-else />
|
|
22
|
+
</view>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { ref, computed, onMounted, getCurrentInstance, useSlots, watch } from 'vue';
|
|
27
|
+
import { $u } from '../..'; // 工具函数路径
|
|
28
|
+
|
|
29
|
+
defineOptions({ name: 'u-dropdown-item' });
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* dropdown-item 下拉菜单
|
|
33
|
+
* @description 该组件一般用于向下展开菜单,同时可切换多个选项卡的场景
|
|
34
|
+
* @tutorial http://uviewui.com/components/dropdown.html
|
|
35
|
+
* @property {String | Number} v-model 双向绑定选项卡选择值
|
|
36
|
+
* @property {String} title 菜单项标题
|
|
37
|
+
* @property {Array[Object]} options 选项数据,如果传入了默认slot,此参数无效
|
|
38
|
+
* @property {Boolean} disabled 是否禁用此选项卡(默认false)
|
|
39
|
+
* @property {String | Number} duration 选项卡展开和收起的过渡时间,单位ms(默认300)
|
|
40
|
+
* @property {String | Number} height 弹窗下拉内容的高度(内容超出将会滚动)(默认auto)
|
|
41
|
+
* @example <u-dropdown-item title="标题"></u-dropdown-item>
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
type OptionType = { label: string; value: any };
|
|
45
|
+
|
|
46
|
+
// props 定义,保留参数注释
|
|
47
|
+
const props = defineProps({
|
|
48
|
+
/** 当前选中项的value值 */
|
|
49
|
+
modelValue: { type: [Number, String, Array], default: '' },
|
|
50
|
+
/** 菜单项标题 */
|
|
51
|
+
title: { type: [String, Number], default: '' },
|
|
52
|
+
/** 选项数据,如果传入了默认slot,此参数无效 */
|
|
53
|
+
options: { type: Array as () => OptionType[], default: () => [] },
|
|
54
|
+
/** 是否禁用此菜单项 */
|
|
55
|
+
disabled: { type: Boolean, default: false },
|
|
56
|
+
/** 下拉弹窗的高度 */
|
|
57
|
+
height: { type: [Number, String], default: 'auto' }
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// emits 定义
|
|
61
|
+
const emit = defineEmits(['update:modelValue', 'change']);
|
|
62
|
+
|
|
63
|
+
// 插槽
|
|
64
|
+
const slots = useSlots();
|
|
65
|
+
|
|
66
|
+
// 当前项是否处于展开状态
|
|
67
|
+
const active = ref(false);
|
|
68
|
+
// 激活时左边文字和右边对勾图标的颜色
|
|
69
|
+
const activeColor = ref<string>('#2979ff');
|
|
70
|
+
// 未激活时左边文字和右边对勾图标的颜色
|
|
71
|
+
const inactiveColor = ref<string>('#606266');
|
|
72
|
+
// 父组件实例
|
|
73
|
+
const parent = ref<any>(null);
|
|
74
|
+
|
|
75
|
+
// 监听props变化,通知父组件重新初始化
|
|
76
|
+
const propsChange = computed(() => `${props.title}-${props.disabled}`);
|
|
77
|
+
|
|
78
|
+
// 监听propsChange变化,通知父组件重新init
|
|
79
|
+
watch(propsChange, () => {
|
|
80
|
+
if (parent.value && parent.value.init) parent.value.init();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* 初始化本组件,注册到父组件
|
|
85
|
+
*/
|
|
86
|
+
function init() {
|
|
87
|
+
// 获取父组件u-dropdown
|
|
88
|
+
const instance = getCurrentInstance();
|
|
89
|
+
if (!instance) return;
|
|
90
|
+
const parentComp = $u.$parent('u-dropdown');
|
|
91
|
+
if (parentComp && parentComp.proxy) {
|
|
92
|
+
const parentProxy = parentComp.proxy as any;
|
|
93
|
+
parent.value = parentComp;
|
|
94
|
+
// 继承父组件的激活/未激活颜色
|
|
95
|
+
activeColor.value = parentProxy.activeColor;
|
|
96
|
+
inactiveColor.value = parentProxy.inactiveColor;
|
|
97
|
+
// 注册到父组件children
|
|
98
|
+
// 将本组件的this,放入到父组件的children数组中,让父组件可以操作本(子)组件的方法和属性
|
|
99
|
+
// push进去前,显判断是否已经存在了本实例,因为在子组件内部数据变化时,会通过父组件重新初始化子组件
|
|
100
|
+
const exist = parentComp?.exposed?.children.value.find((val: any) => val === instance);
|
|
101
|
+
if (!exist) parentComp?.exposed?.children.value.push(instance);
|
|
102
|
+
if (parentComp?.exposed?.children.value.length === 1) active.value = true;
|
|
103
|
+
// 向父组件menuList注册本项
|
|
104
|
+
// 父组件无法监听children的变化,故将子组件的title,传入父组件的menuList数组中
|
|
105
|
+
parentComp?.exposed?.menuList.value.push({ title: props.title, disabled: props.disabled });
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* cell被点击
|
|
111
|
+
* @param value 选中值
|
|
112
|
+
*/
|
|
113
|
+
function cellClick(value: string | number | any) {
|
|
114
|
+
// 修改通过v-model绑定的值
|
|
115
|
+
emit('update:modelValue', value);
|
|
116
|
+
// 通知父组件(u-dropdown)收起菜单
|
|
117
|
+
parent.value?.exposed?.close();
|
|
118
|
+
// 发出事件,抛出当前勾选项的value
|
|
119
|
+
emit('change', value);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function setActive(value: boolean) {
|
|
123
|
+
active.value = value;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
onMounted(() => {
|
|
127
|
+
init();
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
defineExpose({ init, cellClick, setActive });
|
|
131
|
+
</script>
|
|
132
|
+
|
|
133
|
+
<style scoped lang="scss">
|
|
134
|
+
@import '../../libs/css/style.components.scss';
|
|
135
|
+
</style>
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<view class="u-empty" v-if="show" :style="{ marginTop: marginTop + 'rpx' }">
|
|
3
|
+
<u-icon
|
|
4
|
+
:name="src ? src : 'empty-' + mode"
|
|
5
|
+
:custom-style="iconStyle"
|
|
6
|
+
:label="text ? text : icons[mode]"
|
|
7
|
+
label-pos="bottom"
|
|
8
|
+
:label-color="color"
|
|
9
|
+
:label-size="fontSize"
|
|
10
|
+
:size="iconSize"
|
|
11
|
+
:color="iconColor"
|
|
12
|
+
margin-top="14"
|
|
13
|
+
></u-icon>
|
|
14
|
+
<view class="u-slot-wrap">
|
|
15
|
+
<slot name="bottom"></slot>
|
|
16
|
+
</view>
|
|
17
|
+
</view>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script setup lang="ts">
|
|
21
|
+
defineOptions({
|
|
22
|
+
name: 'u-empty'
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* empty 内容为空
|
|
27
|
+
* @description 该组件用于需要加载内容,但是加载的第一页数据就为空,提示一个"没有内容"的场景, 我们精心挑选了十几个场景的图标,方便您使用。
|
|
28
|
+
* @tutorial https://www.uviewui.com/components/empty.html
|
|
29
|
+
* @property {String} color 文字颜色(默认#c0c4cc)
|
|
30
|
+
* @property {String} text 文字提示(默认“无内容”)
|
|
31
|
+
* @property {String} src 自定义图标路径,如定义,mode参数会失效
|
|
32
|
+
* @property {String Number} font-size 提示文字的大小,单位rpx(默认28)
|
|
33
|
+
* @property {String} mode 内置的图标,见官网说明(默认data)
|
|
34
|
+
* @property {String Number} img-width 图标的宽度,单位rpx(默认240)
|
|
35
|
+
* @property {String} img-height 图标的高度,单位rpx(默认auto)
|
|
36
|
+
* @property {String Number} margin-top 组件距离上一个元素之间的距离(默认0)
|
|
37
|
+
* @property {Boolean} show 是否显示组件(默认true)
|
|
38
|
+
* @event {Function} click 点击组件时触发
|
|
39
|
+
* @event {Function} close 点击关闭按钮时触发
|
|
40
|
+
* @example <u-empty text="所谓伊人,在水一方" mode="list"></u-empty>
|
|
41
|
+
*/
|
|
42
|
+
const props = defineProps({
|
|
43
|
+
/** 图标路径 */
|
|
44
|
+
src: { type: String, default: '' },
|
|
45
|
+
/** 提示文字 */
|
|
46
|
+
text: { type: String, default: '' },
|
|
47
|
+
/** 文字颜色 */
|
|
48
|
+
color: { type: String, default: '#c0c4cc' },
|
|
49
|
+
/** 图标的颜色 */
|
|
50
|
+
iconColor: { type: String, default: '#c0c4cc' },
|
|
51
|
+
/** 图标的大小 */
|
|
52
|
+
iconSize: { type: [String, Number], default: 120 },
|
|
53
|
+
/** 文字大小,单位rpx */
|
|
54
|
+
fontSize: { type: [String, Number], default: 26 },
|
|
55
|
+
/** 选择预置的图标类型 */
|
|
56
|
+
mode: { type: String, default: 'data' },
|
|
57
|
+
/** 图标宽度,单位rpx */
|
|
58
|
+
imgWidth: { type: [String, Number], default: 120 },
|
|
59
|
+
/** 图标高度,单位rpx */
|
|
60
|
+
imgHeight: { type: [String, Number], default: 'auto' },
|
|
61
|
+
/** 是否显示组件 */
|
|
62
|
+
show: { type: Boolean, default: true },
|
|
63
|
+
/** 组件距离上一个元素之间的距离 */
|
|
64
|
+
marginTop: { type: [String, Number], default: 0 },
|
|
65
|
+
/** 图标自定义样式 */
|
|
66
|
+
iconStyle: { type: Object, default: () => ({}) }
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* 预置图标对应的提示文字
|
|
71
|
+
*/
|
|
72
|
+
const icons: Record<string, string> = {
|
|
73
|
+
car: '购物车为空',
|
|
74
|
+
page: '页面不存在',
|
|
75
|
+
search: '没有搜索结果',
|
|
76
|
+
address: '没有收货地址',
|
|
77
|
+
wifi: '没有WiFi',
|
|
78
|
+
order: '订单为空',
|
|
79
|
+
coupon: '没有优惠券',
|
|
80
|
+
favor: '暂无收藏',
|
|
81
|
+
permission: '无权限',
|
|
82
|
+
history: '无历史记录',
|
|
83
|
+
news: '无新闻列表',
|
|
84
|
+
message: '消息列表为空',
|
|
85
|
+
list: '列表为空',
|
|
86
|
+
data: '数据为空'
|
|
87
|
+
};
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<style scoped lang="scss">
|
|
91
|
+
@import '../../libs/css/style.components.scss';
|
|
92
|
+
|
|
93
|
+
.u-empty {
|
|
94
|
+
@include vue-flex;
|
|
95
|
+
flex-direction: column;
|
|
96
|
+
justify-content: center;
|
|
97
|
+
align-items: center;
|
|
98
|
+
height: 100%;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.u-image {
|
|
102
|
+
margin-bottom: 20rpx;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.u-slot-wrap {
|
|
106
|
+
@include vue-flex;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
align-items: center;
|
|
109
|
+
margin-top: 20rpx;
|
|
110
|
+
}
|
|
111
|
+
</style>
|