hy-app 0.3.1 → 0.3.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.
- package/README.md +6 -3
- package/common/shakeService.ts +31 -29
- package/components/avatar.zip +0 -0
- package/components/hy-action-sheet/hy-action-sheet.vue +71 -46
- package/components/hy-address-picker/hy-address-picker.vue +94 -83
- package/components/hy-avatar/hy-avatar.vue +84 -85
- package/components/hy-badge/hy-badge.vue +47 -46
- package/components/hy-button/hy-button.vue +117 -93
- package/components/hy-calendar/hy-calendar.vue +168 -160
- package/components/hy-card/hy-card.vue +50 -43
- package/components/hy-card/typing.d.ts +33 -32
- package/components/hy-cell/hy-cell.vue +73 -51
- package/components/hy-check-button/hy-check-button.vue +54 -47
- package/components/hy-checkbox/hy-checkbox.vue +97 -105
- package/components/hy-code-input/hy-code-input.vue +80 -89
- package/components/hy-config-provider/hy-config-provider.vue +19 -20
- package/components/hy-count-down/hy-count-down.vue +66 -67
- package/components/hy-count-to/hy-count-to.vue +105 -99
- package/components/hy-count-to/typing.d.ts +13 -12
- package/components/hy-datetime-picker/hy-datetime-picker.vue +261 -253
- package/components/hy-datetime-picker/typing.d.ts +42 -40
- package/components/hy-divider/hy-divider.vue +68 -73
- package/components/hy-dropdown/hy-dropdown.vue +20 -19
- package/components/hy-dropdown-item/hy-dropdown-item.vue +66 -61
- package/components/hy-dropdown-item/typing.d.ts +9 -9
- package/components/hy-empty/hy-empty.vue +42 -42
- package/components/hy-flex/hy-flex.vue +52 -26
- package/components/hy-float-button/hy-float-button.vue +218 -210
- package/components/hy-folding-panel/hy-folding-panel.vue +32 -33
- package/components/hy-form/hy-form.vue +264 -259
- package/components/hy-grid/hy-grid.vue +44 -43
- package/components/hy-icon/hy-icon.vue +61 -67
- package/components/hy-image/hy-image.vue +112 -88
- package/components/hy-image/typing.d.ts +27 -23
- package/components/hy-input/hy-input.vue +157 -127
- package/components/hy-input/typing.d.ts +53 -47
- package/components/hy-line/hy-line.vue +26 -26
- package/components/hy-line-progress/hy-line-progress.vue +42 -35
- package/components/hy-list/hy-list.vue +76 -85
- package/components/hy-loading/hy-loading.vue +26 -23
- package/components/hy-menu/hy-menu.vue +48 -43
- package/components/hy-menu/typing.d.ts +18 -17
- package/components/hy-modal/hy-modal.vue +39 -35
- package/components/hy-navbar/hy-navbar.vue +25 -25
- package/components/hy-navbar/typing.d.ts +24 -22
- package/components/hy-notice-bar/hy-notice-bar.vue +26 -27
- package/components/hy-notify/hy-notify.vue +53 -53
- package/components/hy-number-step/hy-number-step.vue +134 -146
- package/components/hy-number-step/typing.d.ts +35 -35
- package/components/hy-overlay/hy-overlay.vue +23 -21
- package/components/hy-pagination/hy-pagination.vue +41 -36
- package/components/hy-picker/hy-picker.vue +184 -154
- package/components/hy-picker/typing.d.ts +39 -39
- package/components/hy-popover/hy-popover.vue +97 -77
- package/components/hy-popup/hy-popup.vue +107 -98
- package/components/hy-price/hy-price.vue +38 -34
- package/components/hy-qrcode/hy-qrcode.vue +50 -51
- package/components/hy-radio/hy-radio.vue +101 -113
- package/components/hy-rate/hy-rate.vue +107 -88
- package/components/hy-read-more/hy-read-more.vue +64 -49
- package/components/hy-scroll-list/hy-scroll-list.vue +45 -48
- package/components/hy-search/hy-search.vue +73 -66
- package/components/hy-search/typing.d.ts +36 -35
- package/components/hy-signature/hy-signature.vue +282 -240
- package/components/hy-slider/hy-slider.vue +195 -153
- package/components/hy-slider/typing.d.ts +21 -21
- package/components/hy-steps/hy-steps.vue +118 -90
- package/components/hy-steps/index.scss +31 -21
- package/components/hy-submit-bar/hy-submit-bar.vue +61 -70
- package/components/hy-subsection/hy-subsection.vue +99 -102
- package/components/hy-subsection/typing.d.ts +19 -19
- package/components/hy-swipe-action/hy-swipe-action.vue +131 -118
- package/components/hy-swiper/hy-swiper.vue +85 -71
- package/components/hy-switch/hy-switch.vue +67 -72
- package/components/hy-switch/typing.d.ts +21 -19
- package/components/hy-tabs/hy-tabs.vue +168 -113
- package/components/hy-tag/hy-tag.vue +90 -86
- package/components/hy-tag/typing.d.ts +26 -21
- package/components/hy-text/hy-text.vue +119 -111
- package/components/hy-textarea/hy-textarea.vue +100 -93
- package/components/hy-textarea/typing.d.ts +36 -31
- package/components/hy-toast/hy-toast.vue +77 -67
- package/components/hy-tooltip/hy-tooltip.vue +109 -91
- package/components/hy-transition/hy-transition.vue +62 -66
- package/components/hy-upload/hy-upload.vue +294 -152
- package/components/hy-upload/typing.d.ts +41 -36
- package/components/hy-warn/hy-warn.vue +34 -27
- package/components/hy-waterfall/hy-waterfall.vue +83 -74
- package/components/hy-watermark/hy-watermark.vue +134 -115
- package/composables/usePopover.ts +236 -221
- package/composables/useQueue.ts +53 -52
- package/package.json +2 -2
- package/store/index.ts +9 -1
- package/typing/index.ts +0 -1
- package/typing/modules/common.d.ts +0 -2
- package/web-types.json +1 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<view
|
|
2
|
+
<view
|
|
3
|
+
:class="['hy-text', customClass]"
|
|
4
|
+
v-if="show"
|
|
5
|
+
:style="wrapStyle"
|
|
6
|
+
@tap="clickHandler"
|
|
7
|
+
>
|
|
3
8
|
<text
|
|
4
9
|
:class="['hy-text__price', type && `hy-text__value--${type}`]"
|
|
5
10
|
v-if="mode === 'price'"
|
|
@@ -53,34 +58,46 @@
|
|
|
53
58
|
|
|
54
59
|
<script lang="ts">
|
|
55
60
|
export default {
|
|
56
|
-
name:
|
|
61
|
+
name: "hy-text",
|
|
57
62
|
options: {
|
|
58
63
|
addGlobalClass: true,
|
|
59
64
|
virtualHost: true,
|
|
60
|
-
styleIsolation:
|
|
65
|
+
styleIsolation: "shared",
|
|
61
66
|
},
|
|
62
|
-
}
|
|
67
|
+
};
|
|
63
68
|
</script>
|
|
64
69
|
|
|
65
70
|
<script setup lang="ts">
|
|
66
|
-
import { computed, nextTick
|
|
67
|
-
import type { CSSProperties, PropType } from
|
|
68
|
-
import type { ITextEmits } from
|
|
69
|
-
import {
|
|
71
|
+
import { computed, nextTick } from "vue";
|
|
72
|
+
import type { CSSProperties, PropType } from "vue";
|
|
73
|
+
import type { ITextEmits } from "./typing";
|
|
74
|
+
import {
|
|
75
|
+
addUnit,
|
|
76
|
+
error,
|
|
77
|
+
formatName,
|
|
78
|
+
formatTime,
|
|
79
|
+
isDate,
|
|
80
|
+
priceFormat,
|
|
81
|
+
} from "../../utils";
|
|
70
82
|
|
|
71
83
|
// 组件
|
|
72
|
-
import HyIcon from
|
|
84
|
+
import HyIcon from "../hy-icon/hy-icon.vue";
|
|
85
|
+
import type { InputOnConfirmEvent } from "@uni-helper/uni-types";
|
|
73
86
|
|
|
74
87
|
/**
|
|
75
88
|
* 此组件集成了文本类在项目中的常用功能,包括状态,拨打电话,格式化日期,*替换,超链接...等功能。 您大可不必在使用特殊文本时自己定义,text组件几乎涵盖您能使用的大部分场景。
|
|
76
89
|
* @displayName hy-text
|
|
77
90
|
*/
|
|
78
|
-
defineOptions({})
|
|
91
|
+
defineOptions({});
|
|
79
92
|
|
|
80
93
|
// const props = withDefaults(defineProps<IProps>(), defaultProps)
|
|
81
94
|
const props = defineProps({
|
|
82
95
|
/** 显示的值 */
|
|
83
|
-
text:
|
|
96
|
+
text: {
|
|
97
|
+
type: [String, Number] as PropType<string | number>,
|
|
98
|
+
default: "",
|
|
99
|
+
required: true,
|
|
100
|
+
},
|
|
84
101
|
/** 主题颜色 */
|
|
85
102
|
type: String,
|
|
86
103
|
/** 是否显示 */
|
|
@@ -98,12 +115,15 @@ const props = defineProps({
|
|
|
98
115
|
* */
|
|
99
116
|
mode: {
|
|
100
117
|
type: String,
|
|
101
|
-
default:
|
|
118
|
+
default: "text",
|
|
102
119
|
},
|
|
103
120
|
/** mode=link下,配置的链接 */
|
|
104
|
-
href:
|
|
121
|
+
href: {
|
|
122
|
+
type: String,
|
|
123
|
+
default: "",
|
|
124
|
+
},
|
|
105
125
|
/** 格式化规则 */
|
|
106
|
-
format: String,
|
|
126
|
+
format: [Function, String],
|
|
107
127
|
/** mode=phone时,点击文本是否拨打电话 */
|
|
108
128
|
call: {
|
|
109
129
|
type: Boolean,
|
|
@@ -133,7 +153,7 @@ const props = defineProps({
|
|
|
133
153
|
/** 图标的样式 */
|
|
134
154
|
iconStyle: {
|
|
135
155
|
type: Object as unknown as PropType<CSSProperties>,
|
|
136
|
-
default: () => ({ fontSize:
|
|
156
|
+
default: () => ({ fontSize: "15px" }),
|
|
137
157
|
},
|
|
138
158
|
/**
|
|
139
159
|
* 文字装饰,下划线,中划线等,可选值
|
|
@@ -150,7 +170,7 @@ const props = defineProps({
|
|
|
150
170
|
* */
|
|
151
171
|
align: {
|
|
152
172
|
type: String,
|
|
153
|
-
default:
|
|
173
|
+
default: "left",
|
|
154
174
|
},
|
|
155
175
|
/**
|
|
156
176
|
* 文字换行
|
|
@@ -158,7 +178,7 @@ const props = defineProps({
|
|
|
158
178
|
* */
|
|
159
179
|
wordWrap: {
|
|
160
180
|
type: String,
|
|
161
|
-
default:
|
|
181
|
+
default: "normal",
|
|
162
182
|
},
|
|
163
183
|
/** 是否占满剩余空间 */
|
|
164
184
|
flex: {
|
|
@@ -166,170 +186,158 @@ const props = defineProps({
|
|
|
166
186
|
default: true,
|
|
167
187
|
},
|
|
168
188
|
/** 定义需要用到的外部样式 */
|
|
169
|
-
customStyle:
|
|
189
|
+
customStyle: {
|
|
190
|
+
type: Object as PropType<CSSProperties>,
|
|
191
|
+
default: () => {},
|
|
192
|
+
},
|
|
170
193
|
/** 自定义外部类名 */
|
|
171
194
|
customClass: String,
|
|
172
|
-
})
|
|
173
|
-
const
|
|
174
|
-
type,
|
|
175
|
-
show,
|
|
176
|
-
text,
|
|
177
|
-
mode,
|
|
178
|
-
call,
|
|
179
|
-
bold,
|
|
180
|
-
block,
|
|
181
|
-
color,
|
|
182
|
-
size,
|
|
183
|
-
decoration,
|
|
184
|
-
margin,
|
|
185
|
-
lines,
|
|
186
|
-
lineHeight,
|
|
187
|
-
align,
|
|
188
|
-
flex,
|
|
189
|
-
href,
|
|
190
|
-
format,
|
|
191
|
-
customStyle,
|
|
192
|
-
} = toRefs(props)
|
|
193
|
-
const emit = defineEmits<ITextEmits>()
|
|
195
|
+
});
|
|
196
|
+
const emit = defineEmits<ITextEmits>();
|
|
194
197
|
|
|
195
198
|
const wrapStyle = computed(() => {
|
|
196
199
|
const style: CSSProperties = {
|
|
197
|
-
margin: margin
|
|
200
|
+
margin: props.margin,
|
|
198
201
|
justifyContent:
|
|
199
|
-
align
|
|
200
|
-
|
|
202
|
+
props.align === "left"
|
|
203
|
+
? "flex-start"
|
|
204
|
+
: props.align === "center"
|
|
205
|
+
? "center"
|
|
206
|
+
: "flex-end",
|
|
207
|
+
};
|
|
201
208
|
// 占满剩余空间
|
|
202
|
-
if (flex
|
|
203
|
-
style.flex = 1
|
|
209
|
+
if (props.flex) {
|
|
210
|
+
style.flex = 1;
|
|
204
211
|
// #ifndef APP-NVUE
|
|
205
|
-
style.width =
|
|
212
|
+
style.width = "100%";
|
|
206
213
|
// #endif
|
|
207
214
|
}
|
|
208
|
-
return style
|
|
209
|
-
})
|
|
215
|
+
return style;
|
|
216
|
+
});
|
|
210
217
|
const valueStyle = computed(() => {
|
|
211
218
|
const style: CSSProperties = {
|
|
212
|
-
textDecoration: decoration
|
|
213
|
-
fontWeight: bold
|
|
214
|
-
fontSize: addUnit(size
|
|
215
|
-
}
|
|
216
|
-
!type
|
|
217
|
-
lineHeight
|
|
218
|
-
block
|
|
219
|
-
return Object.assign(style, customStyle
|
|
220
|
-
})
|
|
219
|
+
textDecoration: props.decoration,
|
|
220
|
+
fontWeight: props.bold ? "bold" : "normal",
|
|
221
|
+
fontSize: addUnit(props.size),
|
|
222
|
+
};
|
|
223
|
+
!props.type && (style.color = props.color);
|
|
224
|
+
props.lineHeight && (style.lineHeight = addUnit(props.lineHeight));
|
|
225
|
+
props.block && (style.display = "block");
|
|
226
|
+
return Object.assign(style, props.customStyle);
|
|
227
|
+
});
|
|
221
228
|
|
|
222
229
|
/**
|
|
223
230
|
* @description 格式化值
|
|
224
231
|
* */
|
|
225
232
|
const value = computed(() => {
|
|
226
|
-
switch (mode
|
|
227
|
-
case
|
|
233
|
+
switch (props.mode) {
|
|
234
|
+
case "price":
|
|
228
235
|
// 如果text不为金额进行提示
|
|
229
|
-
if (!/^\d+(\.\d+)?$/.test(text
|
|
230
|
-
error(
|
|
236
|
+
if (!/^\d+(\.\d+)?$/.test(props.text?.toString())) {
|
|
237
|
+
error("金额模式下,text参数需要为金额格式");
|
|
231
238
|
}
|
|
232
239
|
// 进行格式化,判断用户传入的format参数为正则,或者函数,如果没有传入format,则使用默认的金额格式化处理
|
|
233
|
-
if (typeof format
|
|
240
|
+
if (typeof props.format === "function") {
|
|
234
241
|
// 如果用户传入的是函数,使用函数格式化
|
|
235
|
-
return format.
|
|
242
|
+
return props.format(props.text);
|
|
236
243
|
}
|
|
237
244
|
// 如果format非正则,非函数,则使用默认的金额格式化方法进行操作
|
|
238
|
-
return priceFormat(text
|
|
239
|
-
case
|
|
245
|
+
return priceFormat(props.text, 2);
|
|
246
|
+
case "date":
|
|
240
247
|
// 判断是否合法的日期或者时间戳
|
|
241
|
-
!isDate(text
|
|
248
|
+
!isDate(props.text) &&
|
|
249
|
+
error("日期模式下,text参数需要为日期或时间戳格式");
|
|
242
250
|
// 进行格式化,判断用户传入的format参数为正则,或者函数,如果没有传入format,则使用默认的格式化处理
|
|
243
|
-
if (typeof format
|
|
251
|
+
if (typeof props.format === "function") {
|
|
244
252
|
// 如果用户传入的是函数,使用函数格式化
|
|
245
|
-
return format.
|
|
253
|
+
return props.format(props.text);
|
|
246
254
|
}
|
|
247
|
-
if (format
|
|
255
|
+
if (props.format) {
|
|
248
256
|
// 如果format非正则,非函数,则使用默认的时间格式化方法进行操作
|
|
249
|
-
return formatTime(text
|
|
257
|
+
return formatTime(props.text, props.format);
|
|
250
258
|
}
|
|
251
259
|
// 如果没有设置format,则设置为默认的时间格式化形式
|
|
252
|
-
return formatTime(text
|
|
253
|
-
case
|
|
260
|
+
return formatTime(props.text, "yyyy-MM-dd");
|
|
261
|
+
case "phone":
|
|
254
262
|
// 判断是否合法的手机号
|
|
255
263
|
// !test.mobile(text) && error('手机号模式下,text参数需要为手机号码格式')
|
|
256
|
-
if (typeof format
|
|
264
|
+
if (typeof props.format === "function") {
|
|
257
265
|
// 如果用户传入的是函数,使用函数格式化
|
|
258
|
-
return format.
|
|
266
|
+
return props.format(props.text);
|
|
259
267
|
}
|
|
260
|
-
if (format
|
|
268
|
+
if (props.format === "encrypt") {
|
|
261
269
|
// 如果format为encrypt,则将手机号进行星号加密处理
|
|
262
|
-
return `${text.
|
|
270
|
+
return `${props.text.toString().substring(0, 3)}****${props.text.toString().substring(7)}`;
|
|
263
271
|
}
|
|
264
|
-
return text
|
|
265
|
-
case
|
|
272
|
+
return props.text;
|
|
273
|
+
case "name":
|
|
266
274
|
// 判断是否合法的字符粗
|
|
267
|
-
if (typeof text
|
|
268
|
-
error(
|
|
275
|
+
if (typeof props.text !== "string") {
|
|
276
|
+
error("姓名模式下,text参数需要为字符串格式");
|
|
269
277
|
} else {
|
|
270
|
-
if (typeof format
|
|
278
|
+
if (typeof props.format === "function") {
|
|
271
279
|
// 如果用户传入的是函数,使用函数格式化
|
|
272
|
-
return format.
|
|
280
|
+
return props.format(props.text);
|
|
273
281
|
}
|
|
274
|
-
if (format
|
|
282
|
+
if (props.format === "encrypt") {
|
|
275
283
|
// 如果format为encrypt,则将姓名进行星号加密处理
|
|
276
|
-
return formatName(text
|
|
284
|
+
return formatName(props.text);
|
|
277
285
|
}
|
|
278
286
|
}
|
|
279
|
-
return text
|
|
280
|
-
case
|
|
281
|
-
return text
|
|
287
|
+
return props.text;
|
|
288
|
+
case "link":
|
|
289
|
+
return props.text;
|
|
282
290
|
default:
|
|
283
|
-
return text
|
|
291
|
+
return props.text;
|
|
284
292
|
}
|
|
285
|
-
})
|
|
293
|
+
});
|
|
286
294
|
|
|
287
295
|
const isMp = computed(() => {
|
|
288
|
-
let mp
|
|
296
|
+
let mp;
|
|
289
297
|
// #ifdef MP
|
|
290
|
-
mp = true
|
|
298
|
+
mp = true;
|
|
291
299
|
// #endif
|
|
292
|
-
return mp
|
|
293
|
-
})
|
|
300
|
+
return mp;
|
|
301
|
+
});
|
|
294
302
|
|
|
295
|
-
const clickHandler = (e) => {
|
|
303
|
+
const clickHandler = (e: InputOnConfirmEvent) => {
|
|
296
304
|
// 如果为手机号模式,拨打电话
|
|
297
|
-
if (call
|
|
305
|
+
if (props.call && props.mode === "phone") {
|
|
298
306
|
uni.makePhoneCall({
|
|
299
|
-
phoneNumber: text
|
|
300
|
-
})
|
|
307
|
+
phoneNumber: props.text as string,
|
|
308
|
+
});
|
|
301
309
|
}
|
|
302
310
|
// 如果是有链接跳转
|
|
303
|
-
if (href
|
|
304
|
-
toLink()
|
|
311
|
+
if (props.href && props.mode === "link") {
|
|
312
|
+
toLink();
|
|
305
313
|
}
|
|
306
|
-
emit(
|
|
307
|
-
}
|
|
314
|
+
emit("click", e);
|
|
315
|
+
};
|
|
308
316
|
|
|
309
317
|
const toLink = () => {
|
|
310
318
|
// #ifdef APP-PLUS
|
|
311
|
-
plus.runtime.openURL(href
|
|
319
|
+
plus.runtime.openURL(props.href);
|
|
312
320
|
// #endif
|
|
313
321
|
// #ifdef H5
|
|
314
|
-
window.open(href
|
|
322
|
+
window.open(props.href);
|
|
315
323
|
// #endif
|
|
316
324
|
// #ifdef MP
|
|
317
325
|
uni.setClipboardData({
|
|
318
|
-
data: href
|
|
326
|
+
data: props.href,
|
|
319
327
|
success: () => {
|
|
320
|
-
uni.hideToast()
|
|
328
|
+
uni.hideToast();
|
|
321
329
|
nextTick(() => {
|
|
322
|
-
uni.showToast({ title:
|
|
323
|
-
})
|
|
330
|
+
uni.showToast({ title: "链接已复制,请在浏览器打开" });
|
|
331
|
+
});
|
|
324
332
|
},
|
|
325
|
-
})
|
|
333
|
+
});
|
|
326
334
|
// #endif
|
|
327
|
-
}
|
|
335
|
+
};
|
|
328
336
|
</script>
|
|
329
337
|
|
|
330
338
|
<style scoped lang="scss">
|
|
331
|
-
@import
|
|
332
|
-
@import
|
|
339
|
+
@import "./index.scss";
|
|
340
|
+
@import "../../libs/css/mixin.scss";
|
|
333
341
|
/*超出出现省略号*/
|
|
334
342
|
.hy-text__value--lines {
|
|
335
343
|
@include multiEllipsis(v-bind(lines));
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
2
|
+
<View
|
|
3
3
|
:class="['hy-textarea', customClass, textareaClass]"
|
|
4
4
|
:style="[textareaStyle, borderStyle(isFocus)]"
|
|
5
5
|
>
|
|
6
|
-
<
|
|
6
|
+
<Textarea
|
|
7
7
|
class="hy-textarea--field"
|
|
8
8
|
:value="innerValue"
|
|
9
9
|
:style="{ height: autoHeight ? 'auto' : addUnit(height) }"
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
:confirm-type="confirmType"
|
|
27
27
|
@focus="onFocus"
|
|
28
28
|
@blur="onBlur"
|
|
29
|
-
@linechange="
|
|
29
|
+
@linechange="onLineChange"
|
|
30
30
|
@input="onInput"
|
|
31
31
|
@confirm="onConfirm"
|
|
32
32
|
@keyboardheightchange="onKeyboardheightchange"
|
|
33
|
-
></
|
|
33
|
+
></Textarea>
|
|
34
34
|
<!-- #ifndef MP-ALIPAY -->
|
|
35
|
-
<
|
|
35
|
+
<Text
|
|
36
36
|
class="hy-textarea--count"
|
|
37
37
|
:style="{
|
|
38
38
|
'background-color': disabled ? 'transparent' : '',
|
|
@@ -40,45 +40,54 @@
|
|
|
40
40
|
v-if="count"
|
|
41
41
|
>
|
|
42
42
|
{{ innerValue.length }}/{{ maxlength }}
|
|
43
|
-
</
|
|
43
|
+
</Text>
|
|
44
44
|
<!-- #endif -->
|
|
45
|
-
</
|
|
45
|
+
</View>
|
|
46
46
|
</template>
|
|
47
47
|
|
|
48
48
|
<script lang="ts">
|
|
49
49
|
export default {
|
|
50
|
-
name:
|
|
50
|
+
name: "hy-textarea",
|
|
51
51
|
options: {
|
|
52
52
|
addGlobalClass: true,
|
|
53
53
|
virtualHost: true,
|
|
54
|
-
styleIsolation:
|
|
54
|
+
styleIsolation: "shared",
|
|
55
55
|
},
|
|
56
|
-
}
|
|
56
|
+
};
|
|
57
57
|
</script>
|
|
58
58
|
|
|
59
59
|
<script setup lang="ts">
|
|
60
|
-
import { computed, ref,
|
|
61
|
-
import type { CSSProperties, PropType } from
|
|
62
|
-
import type { ITextareaEmits } from
|
|
63
|
-
import { addUnit } from
|
|
64
|
-
import { FormItemContext } from
|
|
60
|
+
import { computed, ref, watch, nextTick, inject } from "vue";
|
|
61
|
+
import type { CSSProperties, PropType } from "vue";
|
|
62
|
+
import type { ITextareaEmits } from "./typing";
|
|
63
|
+
import { addUnit } from "../../utils";
|
|
64
|
+
import type { FormItemContext } from "../hy-form-item/typing";
|
|
65
|
+
import type {
|
|
66
|
+
InputOnBlurEvent,
|
|
67
|
+
InputOnConfirmEvent,
|
|
68
|
+
InputOnFocusEvent,
|
|
69
|
+
InputOnKeyboardheightchangeEvent,
|
|
70
|
+
} from "@uni-helper/uni-types";
|
|
65
71
|
|
|
66
72
|
/**
|
|
67
73
|
* 用于输入多行文本信息,聊天输入框等。
|
|
68
74
|
* @displayName hy-textarea
|
|
69
75
|
*/
|
|
70
|
-
defineOptions({})
|
|
76
|
+
defineOptions({});
|
|
71
77
|
|
|
72
78
|
// const props = withDefaults(defineProps<IProps>(), defaultProps);
|
|
73
79
|
const props = defineProps({
|
|
74
80
|
/** 输入框的内容 */
|
|
75
|
-
modelValue:
|
|
81
|
+
modelValue: {
|
|
82
|
+
type: String,
|
|
83
|
+
default: "",
|
|
84
|
+
},
|
|
76
85
|
/** 输入框为空时占位符 */
|
|
77
86
|
placeholder: String,
|
|
78
87
|
/** 指定placeholder的样式类,注意页面或组件的style中写了scoped时,需要在类名前写/deep/ */
|
|
79
88
|
placeholderClass: {
|
|
80
89
|
type: String,
|
|
81
|
-
default:
|
|
90
|
+
default: "textarea-placeholder",
|
|
82
91
|
},
|
|
83
92
|
/** 指定placeholder的样式,对象形式 */
|
|
84
93
|
placeholderStyle: Object as PropType<CSSProperties>,
|
|
@@ -90,7 +99,7 @@ const props = defineProps({
|
|
|
90
99
|
/** 设置键盘右下角按钮的文字,仅微信小程序,App-vue和H5有效 */
|
|
91
100
|
confirmType: {
|
|
92
101
|
type: String,
|
|
93
|
-
default:
|
|
102
|
+
default: "done",
|
|
94
103
|
},
|
|
95
104
|
/** 是否禁用 */
|
|
96
105
|
disabled: {
|
|
@@ -165,7 +174,7 @@ const props = defineProps({
|
|
|
165
174
|
* */
|
|
166
175
|
border: {
|
|
167
176
|
type: String,
|
|
168
|
-
default:
|
|
177
|
+
default: "surround",
|
|
169
178
|
},
|
|
170
179
|
/** 内容式化函数 */
|
|
171
180
|
formatter: Function,
|
|
@@ -175,125 +184,123 @@ const props = defineProps({
|
|
|
175
184
|
},
|
|
176
185
|
/** 自定义外部类名 */
|
|
177
186
|
customClass: String,
|
|
178
|
-
})
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
const formItem = inject<FormItemContext>('formItem')
|
|
187
|
+
});
|
|
188
|
+
const emit = defineEmits<ITextareaEmits>();
|
|
189
|
+
const formItem = inject<FormItemContext>("formItem");
|
|
182
190
|
|
|
183
191
|
// 输入框的值
|
|
184
|
-
const innerValue = ref<string>(
|
|
185
|
-
// 是否处于获得焦点状态
|
|
186
|
-
const focused = ref<boolean>(false)
|
|
192
|
+
const innerValue = ref<string>("");
|
|
187
193
|
// value是否第一次变化,在watch中,由于加入immediate属性,会在第一次触发,此时不应该认为value发生了变化
|
|
188
|
-
const firstChange = ref<boolean>(true)
|
|
194
|
+
const firstChange = ref<boolean>(true);
|
|
189
195
|
// value绑定值的变化是由内部还是外部引起的
|
|
190
|
-
const changeFromInner = ref<boolean>(false)
|
|
196
|
+
const changeFromInner = ref<boolean>(false);
|
|
191
197
|
// 是否获取焦点
|
|
192
|
-
const isFocus = ref<boolean>(false)
|
|
198
|
+
const isFocus = ref<boolean>(false);
|
|
193
199
|
// 过滤处理方法
|
|
194
|
-
let innerFormatter = (value: string) => value
|
|
200
|
+
let innerFormatter = (value: string) => value;
|
|
195
201
|
|
|
196
202
|
watch(
|
|
197
|
-
() => modelValue
|
|
203
|
+
() => props.modelValue,
|
|
198
204
|
(newVal) => {
|
|
199
|
-
innerValue.value = newVal
|
|
205
|
+
innerValue.value = newVal;
|
|
200
206
|
/* #ifdef H5 */
|
|
201
207
|
// 在H5中,外部value变化后,修改input中的值,不会触发@input事件,此时手动调用值变化方法
|
|
202
208
|
if (firstChange.value === false && changeFromInner.value === false) {
|
|
203
|
-
valueChange()
|
|
209
|
+
valueChange();
|
|
204
210
|
}
|
|
205
211
|
/* #endif */
|
|
206
|
-
firstChange.value = false
|
|
212
|
+
firstChange.value = false;
|
|
207
213
|
// 重置changeFromInner的值为false,标识下一次引起默认为外部引起的
|
|
208
|
-
changeFromInner.value = false
|
|
214
|
+
changeFromInner.value = false;
|
|
209
215
|
},
|
|
210
216
|
{ immediate: true },
|
|
211
|
-
)
|
|
217
|
+
);
|
|
212
218
|
|
|
213
219
|
// 组件的类名
|
|
214
220
|
const textareaClass = computed(() => {
|
|
215
|
-
let classes: string[] = []
|
|
216
|
-
border
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
221
|
+
let classes: string[] = [];
|
|
222
|
+
props.border === "surround" &&
|
|
223
|
+
(classes = classes.concat(["hy-border", "hy-textarea--radius"]));
|
|
224
|
+
props.border === "bottom" &&
|
|
225
|
+
(classes = classes.concat(["hy-border__bottom", "hy-textarea--no-radius"]));
|
|
226
|
+
props.disabled && classes.push("hy-textarea--disabled");
|
|
227
|
+
return classes.join(" ");
|
|
228
|
+
});
|
|
222
229
|
// 组件的样式
|
|
223
230
|
const textareaStyle = computed(() => {
|
|
224
|
-
const style: CSSProperties = {}
|
|
231
|
+
const style: CSSProperties = {};
|
|
225
232
|
|
|
226
|
-
return Object.assign(style, customStyle
|
|
227
|
-
})
|
|
233
|
+
return Object.assign(style, props.customStyle);
|
|
234
|
+
});
|
|
228
235
|
/**
|
|
229
236
|
* @description 边框颜色
|
|
230
237
|
* */
|
|
231
238
|
const borderStyle = computed(() => {
|
|
232
239
|
return (isFocus: boolean) => {
|
|
233
|
-
let style: CSSProperties = {}
|
|
240
|
+
let style: CSSProperties = {};
|
|
234
241
|
if (isFocus) {
|
|
235
|
-
switch (border
|
|
236
|
-
case
|
|
237
|
-
style = { border: `1px solid var(--hy-theme-color, #3c9cff)` }
|
|
238
|
-
break
|
|
239
|
-
case
|
|
240
|
-
style = { borderBottom: `1px solid var(--hy-theme-color, #3c9cff)` }
|
|
241
|
-
break
|
|
242
|
+
switch (props.border) {
|
|
243
|
+
case "surround":
|
|
244
|
+
style = { border: `1px solid var(--hy-theme-color, #3c9cff)` };
|
|
245
|
+
break;
|
|
246
|
+
case "bottom":
|
|
247
|
+
style = { borderBottom: `1px solid var(--hy-theme-color, #3c9cff)` };
|
|
248
|
+
break;
|
|
242
249
|
default:
|
|
243
|
-
break
|
|
250
|
+
break;
|
|
244
251
|
}
|
|
245
252
|
}
|
|
246
|
-
return style
|
|
247
|
-
}
|
|
248
|
-
})
|
|
253
|
+
return style;
|
|
254
|
+
};
|
|
255
|
+
});
|
|
249
256
|
|
|
250
|
-
const onFocus = (e:
|
|
251
|
-
isFocus.value = true
|
|
252
|
-
emit(
|
|
253
|
-
}
|
|
254
|
-
const onBlur = (e:
|
|
255
|
-
isFocus.value = false
|
|
256
|
-
emit(
|
|
257
|
-
formItem.handleBlur(e.detail.value)
|
|
257
|
+
const onFocus = (e: InputOnFocusEvent) => {
|
|
258
|
+
isFocus.value = true;
|
|
259
|
+
emit("focus", e);
|
|
260
|
+
};
|
|
261
|
+
const onBlur = (e: InputOnBlurEvent) => {
|
|
262
|
+
isFocus.value = false;
|
|
263
|
+
emit("blur", e);
|
|
264
|
+
if (formItem) formItem.handleBlur(e.detail.value);
|
|
258
265
|
// 尝试调用u-form的验证方法
|
|
259
266
|
// formValidate(this, "blur");
|
|
260
|
-
}
|
|
261
|
-
const
|
|
262
|
-
emit(
|
|
263
|
-
}
|
|
267
|
+
};
|
|
268
|
+
const onLineChange = (e: any) => {
|
|
269
|
+
emit("lineChange", e);
|
|
270
|
+
};
|
|
264
271
|
const onInput = (e: any) => {
|
|
265
|
-
let { value } = e?.detail
|
|
272
|
+
let { value } = e?.detail;
|
|
266
273
|
// 格式化过滤方法
|
|
267
|
-
const format = formatter
|
|
268
|
-
const formatValue = format(value)
|
|
274
|
+
const format = props.formatter || innerFormatter;
|
|
275
|
+
const formatValue = format(value);
|
|
269
276
|
// 为了避免props的单向数据流特性,需要先将innerValue值设置为当前值,再在$nextTick中重新赋予设置后的值才有效
|
|
270
|
-
innerValue.value = value
|
|
277
|
+
innerValue.value = value;
|
|
271
278
|
nextTick(() => {
|
|
272
|
-
innerValue.value = formatValue
|
|
273
|
-
valueChange()
|
|
274
|
-
})
|
|
275
|
-
}
|
|
279
|
+
innerValue.value = formatValue;
|
|
280
|
+
valueChange();
|
|
281
|
+
});
|
|
282
|
+
};
|
|
276
283
|
/**
|
|
277
284
|
* @description 内容发生变化,进行处理
|
|
278
285
|
* */
|
|
279
286
|
const valueChange = () => {
|
|
280
|
-
const value = innerValue.value
|
|
287
|
+
const value = innerValue.value;
|
|
281
288
|
nextTick(() => {
|
|
282
|
-
emit(
|
|
289
|
+
emit("update:modelValue", value);
|
|
283
290
|
// 标识value值的变化是由内部引起的
|
|
284
|
-
changeFromInner.value = true
|
|
285
|
-
emit(
|
|
286
|
-
formItem.handleChange(value)
|
|
287
|
-
})
|
|
288
|
-
}
|
|
289
|
-
const onConfirm = (e:
|
|
290
|
-
emit(
|
|
291
|
-
}
|
|
292
|
-
const onKeyboardheightchange = (e:
|
|
293
|
-
emit(
|
|
294
|
-
}
|
|
291
|
+
changeFromInner.value = true;
|
|
292
|
+
emit("change", value);
|
|
293
|
+
if (formItem) formItem.handleChange(value);
|
|
294
|
+
});
|
|
295
|
+
};
|
|
296
|
+
const onConfirm = (e: InputOnConfirmEvent) => {
|
|
297
|
+
emit("confirm", e);
|
|
298
|
+
};
|
|
299
|
+
const onKeyboardheightchange = (e: InputOnKeyboardheightchangeEvent) => {
|
|
300
|
+
emit("keyboardheightchange", e);
|
|
301
|
+
};
|
|
295
302
|
</script>
|
|
296
303
|
|
|
297
304
|
<style lang="scss" scoped>
|
|
298
|
-
@import
|
|
305
|
+
@import "./index.scss";
|
|
299
306
|
</style>
|