Skip to content

Commit 9a6a06a

Browse files
kagolgitee-org
authored andcommitted
!309 【Form】完成messageShowType的popover提示
Merge pull request !309 from AlanLee/dev
2 parents ca21fab + 5e7d379 commit 9a6a06a

File tree

5 files changed

+113
-26
lines changed

5 files changed

+113
-26
lines changed

packages/devui-vue/devui/form/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export { Form, FormLabel, FormItem, FormControl, FormOperation }
3232
export default {
3333
title: 'Form 表单',
3434
category: '数据录入',
35-
status: '70%',
35+
status: '75%',
3636
install(app: App): void {
3737
app.use(Form as any);
3838
app.use(FormLabel as any);

packages/devui-vue/devui/form/src/directive/d-validate-rules.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ interface ValidateFnParam {
1212
isFormTag: boolean
1313
message: string
1414
messageShowType: MessageShowType
15+
dfcUID: string
16+
popPosition: PopPosition | Array<BasePopPosition>
1517
}
1618

1719
interface CustomValidatorRuleObject {
@@ -24,6 +26,7 @@ interface DirectiveValidateRuleOptions {
2426
updateOn?: UpdateOn
2527
errorStrategy?: ErrorStrategy
2628
asyncDebounceTime?: number
29+
popPosition?: PopPosition | Array<BasePopPosition>
2730
}
2831

2932
interface DirectiveBindingValue {
@@ -38,9 +41,18 @@ interface DirectiveCustomRuleItem extends RuleItem {
3841
asyncValidators: CustomValidatorRuleObject[]
3942
}
4043

44+
export interface ShowPopoverErrorMessageEventData {
45+
showPopover?: boolean
46+
message?: string
47+
uid?: string,
48+
popPosition?: PopPosition
49+
}
50+
4151
type MessageShowType = 'popover' | 'text' | 'none' | 'toast';
4252
type UpdateOn = 'input' | 'focus' | 'change' | 'blur' | 'submit';
4353
type ErrorStrategy = 'dirty' | 'pristine';
54+
type BasePopPosition = 'left' | 'right' | 'top' | 'bottom';
55+
type PopPosition = BasePopPosition | 'left-top' | 'left-bottom' | 'top-left' | 'top-right' | 'right-top' | 'right-bottom' | 'bottom-left' | 'bottom-right';
4456

4557
enum ErrorStrategyEnum {
4658
dirty = 'dirty',
@@ -198,14 +210,20 @@ function handleErrorStrategyPass(el: HTMLElement): void {
198210
el.setAttribute('class', classList.join(' '));
199211
}
200212

201-
function handleValidateError({el, tipEl, message, isFormTag, messageShowType}: Partial<ValidateFnParam>): void {
213+
function handleValidateError({el, tipEl, message, isFormTag, messageShowType, dfcUID, popPosition = 'right-bottom'}: Partial<ValidateFnParam>): void {
202214
// 如果该指令用在form标签上,这里做特殊处理
203215
if(isFormTag && messageShowType === MessageShowTypeEnum.toast) {
204216
// todo:待替换为toast
205217
alert(message);
206218
return;
207219
}
208220

221+
// messageShowType为popover时,设置popover
222+
if(MessageShowTypeEnum.popover === messageShowType) {
223+
EventBus.emit("showPopoverErrorMessage", {showPopover: true, message, uid: dfcUID, popPosition} as ShowPopoverErrorMessageEventData);
224+
return;
225+
}
226+
209227
tipEl.innerText = '' + message;
210228
tipEl.style.display = 'inline-flex';
211229
tipEl.setAttribute('class', 'd-validate-tip');
@@ -225,7 +243,7 @@ function getFormName(binding: DirectiveBinding): string {
225243
}
226244

227245
// 校验处理函数
228-
function validateFn({validator, modelValue, el, tipEl, isFormTag, messageShowType}: Partial<ValidateFnParam>) {
246+
function validateFn({validator, modelValue, el, tipEl, isFormTag, messageShowType, dfcUID, popPosition}: Partial<ValidateFnParam>) {
229247
validator.validate({modelName: modelValue}).then(() => {
230248
handleValidatePass(el, tipEl);
231249
}).catch((err) => {
@@ -240,13 +258,22 @@ function validateFn({validator, modelValue, el, tipEl, isFormTag, messageShowTyp
240258
msg = errors[0].message;
241259
}
242260

243-
handleValidateError({el, tipEl, message: msg, isFormTag, messageShowType});
261+
handleValidateError({el, tipEl, message: msg, isFormTag, messageShowType, dfcUID, popPosition});
244262
})
245263
}
246264

265+
// 检测popover的position是否是正确值
266+
function checkValidPopsition(positionStr: string): boolean {
267+
const validPosition = ['left', 'right', 'top', 'bottom', 'left-top', 'left-bottom', 'top-left', 'top-right', 'right-top', 'right-bottom', 'bottom-left', 'bottom-right'];
268+
const isValid = validPosition.includes(positionStr);
269+
!isValid && console.warn(`invalid popPosition value '${positionStr}'.`);
270+
return isValid
271+
}
272+
247273
export default {
248274
mounted(el: HTMLElement, binding: DirectiveBinding, vnode: VNode): void {
249275
const isFormTag = el.tagName === 'FORM';
276+
const dfcUID = el.parentNode.parentNode.parentElement.dataset.uid;
250277

251278
const hasOptions = isObject(binding.value) && hasKey(binding.value, 'options');
252279

@@ -259,12 +286,25 @@ export default {
259286
let { errorStrategy }: DirectiveBindingValue = binding.value;
260287

261288
// errorStrategy可配置在options对象中
262-
const {
289+
let {
263290
updateOn = UpdateOnEnum.change,
264291
errorStrategy: ErrorStrategy = ErrorStrategyEnum.dirty,
265-
asyncDebounceTime = 300
292+
asyncDebounceTime = 300,
293+
popPosition = ['right', 'bottom']
266294
}: DirectiveValidateRuleOptions = options;
267295

296+
// 设置popover的位置
297+
if(messageShowType === MessageShowTypeEnum.popover) {
298+
if(Array.isArray(popPosition)) {
299+
popPosition = (popPosition.length > 1 ? popPosition.join('-') : popPosition[0]) as PopPosition;
300+
if(!checkValidPopsition(popPosition)) {
301+
popPosition = 'right-bottom';
302+
}
303+
}else if(!checkValidPopsition(popPosition)) {
304+
popPosition = 'right-bottom';
305+
}
306+
}
307+
268308
if(!errorStrategy) {
269309
errorStrategy = ErrorStrategy;
270310
}
@@ -340,7 +380,10 @@ export default {
340380

341381
const htmlEventValidateHandler = (e) => {
342382
const modelValue = e.target.value;
343-
validateFn({validator, modelValue, el, tipEl, isFormTag: false, messageShowType});
383+
if(messageShowType === MessageShowTypeEnum.popover) {
384+
EventBus.emit("showPopoverErrorMessage", {showPopover: false, message: "", uid: dfcUID} as ShowPopoverErrorMessageEventData);
385+
}
386+
validateFn({validator, modelValue, el, tipEl, isFormTag: false, messageShowType, dfcUID, popPosition});
344387
}
345388

346389
// 监听事件验证

packages/devui-vue/devui/form/src/form-control/form-control.scss

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,29 @@
6060
}
6161
}
6262

63+
64+
.devui-control-content-wrapper {
65+
position: relative;
66+
& > div {
67+
z-index: 10;
68+
}
69+
.devui-popover-wrapper {
70+
position: absolute;
71+
width: 100%;
72+
height: 100%;
73+
left: 0;
74+
top: 0;
75+
z-index: 9;
76+
77+
& > div {
78+
width: inherit;
79+
height: 100%;
80+
}
81+
}
82+
}
83+
84+
85+
6386
.has-feedback {
6487
display: flex;
6588
align-items: center;

packages/devui-vue/devui/form/src/form-control/form-control.tsx

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
import { defineComponent, inject, ref, computed, reactive } from 'vue';
1+
import { defineComponent, inject, ref, computed, reactive, onMounted } from 'vue';
2+
import { uniqueId } from 'lodash-es';
23
import {IForm, formControlProps, formInjectionKey} from '../form-types';
4+
import { ShowPopoverErrorMessageEventData } from '../directive/d-validate-rules'
5+
import { EventBus } from '../util';
36
import Icon from '../../../icon/src/icon';
7+
import Popover from '../../../popover/src/popover';
48
import './form-control.scss';
59

10+
type positionType = 'top' | 'right' | 'bottom' | 'left';
11+
612
export default defineComponent({
713
name: 'DFormControl',
814
props: formControlProps,
@@ -11,6 +17,20 @@ export default defineComponent({
1117
const dForm = reactive(inject(formInjectionKey, {} as IForm));
1218
const labelData = reactive(dForm.labelData);
1319
const isHorizontal = labelData.layout === 'horizontal';
20+
const uid = uniqueId("dfc-");
21+
const showPopover = ref(false);
22+
const tipMessage = ref("");
23+
const popPosition = ref<positionType>("bottom");
24+
25+
onMounted(() => {
26+
EventBus.on("showPopoverErrorMessage", (data: ShowPopoverErrorMessageEventData) => {
27+
if(uid === data.uid) {
28+
showPopover.value = data.showPopover;
29+
tipMessage.value = data.message;
30+
popPosition.value = data.popPosition as any; // todo: 待popover组件positionType完善类型之后再替换类型
31+
}
32+
});
33+
});
1434

1535
const iconData = computed(() => {
1636
switch(props.feedbackStatus) {
@@ -30,9 +50,14 @@ export default defineComponent({
3050
feedbackStatus,
3151
extraInfo,
3252
} = props;
33-
return <div class="form-control" ref={formControl}>
53+
return <div class="form-control" ref={formControl} data-uid={uid}>
3454
<div class={`devui-form-control-container${isHorizontal ? ' devui-form-control-container-horizontal' : ''}${feedbackStatus ? ' has-feedback' : ''}${feedbackStatus === 'error' ? ' feedback-error' : ''}`}>
35-
{ctx.slots.default?.()}
55+
<div class="devui-control-content-wrapper">
56+
{ctx.slots.default?.()}
57+
<div class="devui-popover-wrapper">
58+
{ showPopover.value && <Popover visible={true} content={tipMessage.value} popType={"error"} position={popPosition.value} /> }
59+
</div>
60+
</div>
3661
{
3762
(feedbackStatus || ctx.slots.suffixTemplate?.()) &&
3863
<span class="feedback-status">

packages/devui-vue/docs/components/form/index.md

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -841,16 +841,14 @@ export default defineComponent({
841841

842842
#### 验证单个元素,自定义管理消息提示
843843

844-
> doing
845-
>
846-
> 待引入popover组件
844+
> done
847845
848846
配置`messageShowType`可选择消息自动提示的方式,默认为`popover`
849847

850848
- 设置为`popover`错误信息将在元素聚焦时以`popover`形式呈现。
851849
- 设置为`text`错误信息将自动以文本方式显示在元素下方(需要与表单控件容器配合使用)。
852850
- 设置为`none`错误信息将不会自动呈现到视图, 可在模板中获取`message`或通过监听`messageChange`事件获取错误`message`, 或在模板中直接通过引用获取。
853-
- 配置`popPosition`可在消息提示方式为`popover`时,自定义`popover`内容弹出方向 默认为`['right', 'bottom']`
851+
- `options`中配置 `popPosition`可在消息提示方式为`popover`时,自定义`popover`内容弹出方向 默认为`['right', 'bottom']`。更多取值参考popover组件
854852

855853
:::demo
856854

@@ -875,15 +873,17 @@ export default defineComponent({
875873
</d-form-item>
876874
<d-form-item prop="asyncSum">
877875
<d-form-label>计算:1 + 2 = ?</d-form-label>
878-
<d-form-control extraInfo="messageShowType为popover,使用popover进行提示(todo,待引入popover组件)">
876+
<d-form-control extraInfo="messageShowType为popover,使用popover进行提示">
879877
<d-input v-model:value="formModel.asyncSum" v-d-validate-rules="{
880878
rules: {
881879
asyncValidators: [
882880
{message: '不对喔!(async)', asyncValidator: customAsyncValidator}
883881
]
884882
},
885883
options: {
886-
updateOn: 'input'
884+
updateOn: 'input',
885+
messageShowType: 'popover',
886+
popPosition: 'bottom'
887887
}
888888
}" />
889889
</d-form-control>
@@ -1616,10 +1616,10 @@ export default defineComponent({
16161616

16171617
#### v-d-validate-rules
16181618

1619-
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
1620-
| ------- | ------------------ | ------ | --------------------------- | ------ |
1621-
| rules | 必选,表单校验规则 | object | | -- |
1622-
| options | 可选,配置选项 | object | `errorStrategy``updateOn` | |
1619+
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
1620+
| ------- | ------------------ | ------ | ------------------------------------------ | ------ |
1621+
| rules | 必选,表单校验规则 | object | | -- |
1622+
| options | 可选,配置选项 | object | `errorStrategy``updateOn``popPosition` | |
16231623

16241624
> 该指令仅在`d-form`标签或`d-input`等表单类组件上使用有效。
16251625
@@ -1639,12 +1639,8 @@ export default defineComponent({
16391639

16401640
- options支持以下字段
16411641
- errorStrategy,错误更新策略:`dirty`(默认)、`prestine`
1642-
16431642
- updateOn,校验时机,可选值有:`change`(默认)、 `blur``input`
1643+
- popPosition,自定义`popover`内容弹出方向。 默认为`['right', 'bottom']`,更多取值参考popover组件。
1644+
16441645

16451646

1646-
<style>
1647-
ul, ol {
1648-
list-style: unset !important;
1649-
}
1650-
</style>

0 commit comments

Comments
 (0)