hy-app 0.2.18 → 0.3.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.
@@ -35,12 +35,8 @@ export default {
35
35
  </script>
36
36
 
37
37
  <script setup lang="ts">
38
- /**
39
- * 该组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。
40
- * @displayName hy-back-top
41
- */
42
- defineOptions({})
43
- import { computed, type CSSProperties, PropType, toRefs } from 'vue'
38
+ import { computed, toRefs } from 'vue'
39
+ import type { CSSProperties, PropType } from 'vue'
44
40
  import { addUnit, getPx } from '../../utils'
45
41
  import { IconConfig } from '../../config'
46
42
  import type { IBackTopEmit } from './typing'
@@ -49,6 +45,12 @@ import type HyIconProps from '../hy-icon/typing'
49
45
  import HyTransition from '../hy-transition/hy-transition.vue'
50
46
  import HyIcon from '../hy-icon/hy-icon.vue'
51
47
 
48
+ /**
49
+ * 该组件一个用于长页面,滑动一定距离后,出现返回顶部按钮,方便快速返回顶部的场景。
50
+ * @displayName hy-back-top
51
+ */
52
+ defineOptions({})
53
+
52
54
  // const props = withDefaults(defineProps<IProps>(), defaultProps)
53
55
  const props = defineProps({
54
56
  /**
@@ -49,7 +49,7 @@ const props = defineProps({
49
49
  customClass: String,
50
50
  /** 定义需要用到的外部样式 */
51
51
  customStyle: {
52
- type: Object as PropType<CSSProperties>,
52
+ type: [Object, Array] as PropType<CSSProperties | CSSProperties[]>,
53
53
  },
54
54
  })
55
55
  const { theme, themeColor, customClass, customStyle, padding } = toRefs(props)
@@ -0,0 +1,73 @@
1
+ <template>
2
+ <view :class="cls" :style="style">
3
+ <slot />
4
+ </view>
5
+ </template>
6
+
7
+ <script setup lang="ts">
8
+ import { computed, PropType } from 'vue'
9
+ import { FlexAlign, FlexDirection, FlexJustify, FlexWrap } from './typing'
10
+ import { addUnit, isArray } from '../../utils'
11
+
12
+ const props = defineProps({
13
+ /** flex 主轴的方向是否垂直,使用 flex-direction: column */
14
+ vertical: {
15
+ type: Boolean,
16
+ default: false,
17
+ },
18
+ /** 快捷设置 flex-direction */
19
+ direction: String as PropType<FlexDirection>,
20
+ /** 设置元素在主轴方向上的对齐方式 */
21
+ justify: {
22
+ type: String as PropType<FlexJustify>,
23
+ default: 'flex-start',
24
+ },
25
+ /** 设置元素在交叉轴方向上的对齐方式 */
26
+ align: {
27
+ type: String as PropType<FlexAlign>,
28
+ default: 'flex-start',
29
+ },
30
+ /** 设置元素单行显示还是多行显示 */
31
+ wrap: {
32
+ type: String as PropType<FlexWrap>,
33
+ default: 'nowrap',
34
+ },
35
+ /** flex 属性,支持数字或字符串。如 1 或 'none' */
36
+ flex: {
37
+ type: [String, Number],
38
+ default: 'initial',
39
+ },
40
+ /** 设置网格之间的间隙 */
41
+ gap: {
42
+ type: [String, Number, Array] as PropType<string | number | (string | number)[]>,
43
+ default: 0,
44
+ },
45
+ /** 快捷设置 */
46
+ basis: {
47
+ type: [String, Number],
48
+ default: 'auto',
49
+ },
50
+ })
51
+
52
+ // 计算 class
53
+ const cls = computed(() => ['hy-flex', props.vertical && 'hy-flex--vertical'])
54
+
55
+ // 计算 style
56
+ const style = computed(() => {
57
+ const gap = isArray(props.gap) ? props.gap : [props.gap, props.gap]
58
+ const [rowGap, colGap] = gap.map((v) => addUnit(v))
59
+
60
+ return {
61
+ display: 'flex',
62
+ 'justify-content': props.justify,
63
+ 'align-items': props.align,
64
+ 'flex-wrap': props.wrap,
65
+ flex: props.flex,
66
+ 'flex-basis': props.basis,
67
+ 'row-gap': colGap,
68
+ 'column-gap': rowGap,
69
+ }
70
+ })
71
+ </script>
72
+
73
+ <style scoped></style>
@@ -0,0 +1,8 @@
1
+ @use "../../libs/css/mixin.scss" as *;
2
+ @include b(flex) {
3
+ box-sizing: border-box;
4
+
5
+ @include m(vertical) {
6
+ flex-direction: column;
7
+ }
8
+ }
@@ -0,0 +1,23 @@
1
+ export type FlexAlign = 'flex-start' | 'center' | 'flex-end' | 'stretch' | 'baseline'
2
+
3
+ export type FlexJustify = HyApp.JustifyContentType
4
+ export type FlexDirection = 'row' | 'row-reverse' | 'column' | 'column-reverse'
5
+ export type FlexWrap = 'nowrap' | 'wrap' | 'wrap-reverse'
6
+
7
+ export interface FlexProps {
8
+ /** 主轴方向,等价于 flex-direction */
9
+ vertical?: boolean
10
+ direction?: FlexDirection
11
+ /** justify-content */
12
+ justify?: FlexJustify
13
+ /** align-items */
14
+ align?: FlexAlign
15
+ /** flex-wrap */
16
+ wrap?: FlexWrap
17
+ /** flex 属性,支持数字或字符串。如 1 或 'none' */
18
+ flex?: number | string
19
+ /** 子元素间距,支持数字(px)、字符串或数组 [row, column] */
20
+ gap?: number | string | [number | string, number | string]
21
+ /** flex-basis */
22
+ basis?: number | string
23
+ }
@@ -0,0 +1,301 @@
1
+ # 表单组件 (hy-form-simple)
2
+
3
+ 一个简单易用的表单组件,包含 `hy-form-simple` 和 `hy-form-item-simple` 两个组件,支持表单验证、数据绑定等功能。
4
+
5
+ ## 组件特性
6
+
7
+ - ✅ 表单数据双向绑定
8
+ - ✅ 表单验证(必填、长度、类型、自定义验证)
9
+ - ✅ 实时验证和失焦验证
10
+ - ✅ 支持多种表单控件
11
+ - ✅ 灵活的标签布局
12
+ - ✅ 错误信息显示
13
+ - ✅ 表单重置和清除验证
14
+
15
+ ## 基础用法
16
+
17
+ ```vue
18
+ <template>
19
+ <hy-form-simple
20
+ ref="formRef"
21
+ :model="formData"
22
+ :rules="rules"
23
+ label-width="80px"
24
+ @submit="handleSubmit"
25
+ >
26
+ <hy-form-item-simple label="用户名" prop="username" required>
27
+ <hy-input v-model="formData.username" placeholder="请输入用户名" />
28
+ </hy-form-item-simple>
29
+
30
+ <hy-form-item-simple label="手机号" prop="phone" required>
31
+ <hy-input v-model="formData.phone" type="number" placeholder="请输入手机号" />
32
+ </hy-form-item-simple>
33
+
34
+ <hy-form-item-simple label="性别" prop="gender">
35
+ <hy-radio v-model="formData.gender" :columns="genderOptions" />
36
+ </hy-form-item-simple>
37
+ </hy-form-simple>
38
+ </template>
39
+
40
+ <script setup lang="ts">
41
+ import { reactive, ref } from 'vue'
42
+
43
+ const formData = reactive({
44
+ username: '',
45
+ phone: '',
46
+ gender: ''
47
+ })
48
+
49
+ const rules = {
50
+ username: [
51
+ { required: true, message: '请输入用户名' },
52
+ { min: 2, max: 20, message: '用户名长度在 2 到 20 个字符' }
53
+ ],
54
+ phone: [
55
+ { required: true, message: '请输入手机号' },
56
+ { type: 'phone', message: '请输入正确的手机号' }
57
+ ]
58
+ }
59
+
60
+ const formRef = ref()
61
+
62
+ const handleSubmit = (data: any) => {
63
+ console.log('表单数据:', data)
64
+ }
65
+ </script>
66
+ ```
67
+
68
+ ## API
69
+
70
+ ### hy-form-simple Props
71
+
72
+ | 参数 | 说明 | 类型 | 默认值 |
73
+ |------|------|------|--------|
74
+ | model | 表单数据对象 | `Record<string, any>` | `{}` |
75
+ | rules | 验证规则 | `FormItemRule` | `{}` |
76
+ | labelWidth | 标签宽度 | `string \| number` | `'auto'` |
77
+ | labelPosition | 标签位置 | `'left' \| 'top'` | `'left'` |
78
+ | labelAlign | 标签对齐方式 | `'left' \| 'center' \| 'right'` | `'left'` |
79
+
80
+ ### hy-form-simple Events
81
+
82
+ | 事件名 | 说明 | 回调参数 |
83
+ |--------|------|----------|
84
+ | submit | 表单提交时触发 | `(data: Record<string, any>)` |
85
+ | validate | 表单验证时触发 | `(valid: boolean, errors: Record<string, string>)` |
86
+
87
+ ### hy-form-simple Methods
88
+
89
+ | 方法名 | 说明 | 参数 |
90
+ |--------|------|------|
91
+ | validate | 验证表单 | - |
92
+ | resetFields | 重置表单 | - |
93
+ | clearValidate | 清除验证 | `(fields?: string[])` |
94
+ | submit | 提交表单 | - |
95
+
96
+ ### hy-form-item-simple Props
97
+
98
+ | 参数 | 说明 | 类型 | 默认值 |
99
+ |------|------|------|--------|
100
+ | label | 标签文本 | `string` | `''` |
101
+ | prop | 表单字段名 | `string` | `''` |
102
+ | required | 是否必填 | `boolean` | `false` |
103
+ | rules | 验证规则 | `any` | `{}` |
104
+
105
+ ### hy-form-item-simple Events
106
+
107
+ | 事件名 | 说明 | 回调参数 |
108
+ |--------|------|----------|
109
+ | change | 值变化时触发 | `(value: any)` |
110
+ | blur | 失焦时触发 | `(value: any)` |
111
+
112
+ ### hy-form-item-simple Methods
113
+
114
+ | 方法名 | 说明 | 参数 |
115
+ |--------|------|------|
116
+ | validate | 验证字段 | `(trigger?: 'blur' \| 'change')` |
117
+ | resetField | 重置字段 | - |
118
+ | clearValidate | 清除验证 | - |
119
+
120
+ ## 验证规则
121
+
122
+ ### 基础验证
123
+
124
+ ```javascript
125
+ const rules = {
126
+ username: [
127
+ { required: true, message: '请输入用户名' },
128
+ { min: 2, max: 20, message: '用户名长度在 2 到 20 个字符' }
129
+ ]
130
+ }
131
+ ```
132
+
133
+ ### 类型验证
134
+
135
+ ```javascript
136
+ const rules = {
137
+ phone: [
138
+ { required: true, message: '请输入手机号' },
139
+ { type: 'phone', message: '请输入正确的手机号' }
140
+ ],
141
+ email: [
142
+ { type: 'email', message: '请输入正确的邮箱格式' }
143
+ ],
144
+ password: [
145
+ { type: 'password', message: '密码格式不正确' }
146
+ ]
147
+ }
148
+ ```
149
+
150
+ ### 自定义验证
151
+
152
+ ```javascript
153
+ const rules = {
154
+ confirmPassword: [
155
+ { required: true, message: '请确认密码' },
156
+ {
157
+ validator: (value: string) => {
158
+ if (value !== formData.password) {
159
+ return '两次输入的密码不一致'
160
+ }
161
+ return true
162
+ }
163
+ }
164
+ ]
165
+ }
166
+ ```
167
+
168
+ ### 触发时机
169
+
170
+ ```javascript
171
+ const rules = {
172
+ username: [
173
+ {
174
+ required: true,
175
+ message: '请输入用户名',
176
+ trigger: ['blur', 'change'] // 失焦和变化时都验证
177
+ }
178
+ ]
179
+ }
180
+ ```
181
+
182
+ ## 支持的表单控件
183
+
184
+ - `hy-input` - 输入框
185
+ - `hy-textarea` - 文本域
186
+ - `hy-radio` - 单选框
187
+ - `hy-check-button` - 选择按钮
188
+ - `hy-switch` - 开关
189
+ - `hy-picker` - 选择器
190
+ - `hy-datetime-picker` - 时间选择器
191
+ - `hy-address-picker` - 地址选择器
192
+ - 其他自定义组件
193
+
194
+ ## 完整示例
195
+
196
+ ```vue
197
+ <template>
198
+ <view class="form-demo">
199
+ <hy-form-simple
200
+ ref="formRef"
201
+ :model="formData"
202
+ :rules="rules"
203
+ label-width="100px"
204
+ label-position="left"
205
+ @submit="handleSubmit"
206
+ >
207
+ <hy-form-item-simple label="用户名" prop="username" required>
208
+ <hy-input v-model="formData.username" placeholder="请输入用户名" />
209
+ </hy-form-item-simple>
210
+
211
+ <hy-form-item-simple label="手机号" prop="phone" required>
212
+ <hy-input v-model="formData.phone" type="number" placeholder="请输入手机号" />
213
+ </hy-form-item-simple>
214
+
215
+ <hy-form-item-simple label="邮箱" prop="email">
216
+ <hy-input v-model="formData.email" placeholder="请输入邮箱" />
217
+ </hy-form-item-simple>
218
+
219
+ <hy-form-item-simple label="性别" prop="gender">
220
+ <hy-radio v-model="formData.gender" :columns="genderOptions" />
221
+ </hy-form-item-simple>
222
+
223
+ <hy-form-item-simple label="爱好" prop="hobbies">
224
+ <hy-check-button
225
+ v-model="formData.hobbies"
226
+ :columns="hobbyOptions"
227
+ select-type="multiple"
228
+ />
229
+ </hy-form-item-simple>
230
+
231
+ <hy-form-item-simple label="备注" prop="remark">
232
+ <hy-textarea v-model="formData.remark" placeholder="请输入备注" />
233
+ </hy-form-item-simple>
234
+ </hy-form-simple>
235
+
236
+ <view class="form-actions">
237
+ <hy-button type="primary" @click="handleSubmit">提交</hy-button>
238
+ <hy-button @click="handleReset">重置</hy-button>
239
+ </view>
240
+ </view>
241
+ </template>
242
+
243
+ <script setup lang="ts">
244
+ import { reactive, ref } from 'vue'
245
+
246
+ const formData = reactive({
247
+ username: '',
248
+ phone: '',
249
+ email: '',
250
+ gender: '',
251
+ hobbies: [],
252
+ remark: ''
253
+ })
254
+
255
+ const rules = {
256
+ username: [
257
+ { required: true, message: '请输入用户名' },
258
+ { min: 2, max: 20, message: '用户名长度在 2 到 20 个字符' }
259
+ ],
260
+ phone: [
261
+ { required: true, message: '请输入手机号' },
262
+ { type: 'phone', message: '请输入正确的手机号' }
263
+ ],
264
+ email: [
265
+ { type: 'email', message: '请输入正确的邮箱格式' }
266
+ ]
267
+ }
268
+
269
+ const genderOptions = [
270
+ { text: '男', value: 'male' },
271
+ { text: '女', value: 'female' }
272
+ ]
273
+
274
+ const hobbyOptions = [
275
+ { text: '阅读', value: 'reading' },
276
+ { text: '音乐', value: 'music' },
277
+ { text: '运动', value: 'sports' }
278
+ ]
279
+
280
+ const formRef = ref()
281
+
282
+ const handleSubmit = () => {
283
+ const result = formRef.value?.submit()
284
+ if (result) {
285
+ console.log('表单提交成功:', result)
286
+ }
287
+ }
288
+
289
+ const handleReset = () => {
290
+ formRef.value?.resetFields()
291
+ }
292
+ </script>
293
+ ```
294
+
295
+ ## 注意事项
296
+
297
+ 1. 表单组件使用 `provide/inject` 进行数据通信,确保 `hy-form-item-simple` 组件在 `hy-form-simple` 内部使用
298
+ 2. 验证规则支持数组形式,可以设置多个验证规则
299
+ 3. 自定义验证函数返回 `true` 表示验证通过,返回 `false` 或字符串表示验证失败
300
+ 4. 表单数据会自动双向绑定,无需手动处理数据同步
301
+ 5. 支持实时验证和失焦验证,可以通过 `trigger` 属性控制验证时机