mirror of
https://github.com/fugary/simple-element-plus-template.git
synced 2025-11-12 14:27:49 +00:00
优化表单赋值与验证
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup>
|
||||
import { computed, nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { debounce, isObject } from 'lodash'
|
||||
import { debounce, isEmpty, isObject } from 'lodash'
|
||||
import { onClickOutside, onKeyStroke, useVModel } from '@vueuse/core'
|
||||
import chunk from 'lodash/chunk'
|
||||
import { UPDATE_MODEL_EVENT, CHANGE_EVENT, useFormItem } from 'element-plus'
|
||||
@@ -183,7 +183,7 @@ const onInputKeywords = debounce((input) => {
|
||||
}, props.debounceTime)
|
||||
|
||||
onMounted(() => {
|
||||
onClickOutside(autocompletePopover.value?.popperRef?.contentRef, (event) => {
|
||||
onClickOutside(autocompletePopover.value?.popperRef?.contentRef, () => {
|
||||
popoverVisible.value = false
|
||||
})
|
||||
})
|
||||
@@ -202,6 +202,9 @@ watch(() => props.modelValue, (value) => {
|
||||
console.info('=====================value', value)
|
||||
if (!props.useIdModel) {
|
||||
setAutocompleteLabel(value && isObject(value) ? value[labelProp.value] : '')
|
||||
if (isEmpty(value)) {
|
||||
vModel.value = null
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -277,11 +280,11 @@ const moveSelection = function (down) {
|
||||
}
|
||||
|
||||
// 向下按键移动元素
|
||||
onKeyStroke('ArrowDown', e => moveSelection(true))
|
||||
onKeyStroke('ArrowDown', () => moveSelection(true))
|
||||
// 向上按键移动元素
|
||||
onKeyStroke('ArrowUp', e => moveSelection(false))
|
||||
onKeyStroke('ArrowUp', () => moveSelection(false))
|
||||
// 选中回车
|
||||
onKeyStroke('Enter', e => {
|
||||
onKeyStroke('Enter', () => {
|
||||
onSelectData(currentOnRow.value)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { computed, ref } from 'vue'
|
||||
import { $i18nBundle } from '@/messages'
|
||||
import ControlChild from '@/components/common-form-control/control-child.vue'
|
||||
import { useInputType } from '@/components/utils'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import { get, set } from 'lodash'
|
||||
|
||||
/**
|
||||
* @type {{option:CommonFormOption}}
|
||||
@@ -16,17 +18,19 @@ const props = defineProps({
|
||||
required: true
|
||||
},
|
||||
model: {
|
||||
type: Object
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
|
||||
const inputType = computed(() => useInputType(props.option))
|
||||
|
||||
const modelAttrs = computed(() => {
|
||||
if (['el-input', 'el-select', 'common-autocomplete', 'el-autocomplete', 'el-cascader', 'el-tree-select'].includes(inputType.value)) {
|
||||
return Object.assign({ clearable: true }, props.option.attrs || {})
|
||||
const attrs = { ...props.option.attrs }
|
||||
if (attrs.clearable === undefined && ['el-input', 'el-select', 'common-autocomplete', 'el-autocomplete', 'el-cascader', 'el-tree-select'].includes(inputType.value)) {
|
||||
attrs.clearable = true
|
||||
}
|
||||
return props.option.attrs
|
||||
return attrs
|
||||
})
|
||||
|
||||
const label = computed(() => {
|
||||
@@ -42,13 +46,13 @@ const formModel = computed(() => props.option.model || props.model)
|
||||
const modelValue = computed({
|
||||
get () {
|
||||
if (formModel.value && props.option.prop) {
|
||||
return formModel.value[props.option.prop]
|
||||
return get(formModel.value, props.option.prop)
|
||||
}
|
||||
return null
|
||||
},
|
||||
set (val) {
|
||||
if (formModel.value && props.option.prop) {
|
||||
formModel.value[props.option.prop] = val
|
||||
set(formModel.value, props.option.prop, val)
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -70,10 +74,38 @@ const children = computed(() => {
|
||||
return result
|
||||
})
|
||||
|
||||
const formItemRef = ref()
|
||||
|
||||
const rules = computed(() => {
|
||||
const option = props.option
|
||||
let _rules = cloneDeep(option.rules || [])
|
||||
if (option.prop) {
|
||||
if (option.required !== undefined) {
|
||||
const label = option.label || $i18nBundle(option.labelKey)
|
||||
_rules = [{
|
||||
trigger: option.trigger,
|
||||
required: option.required,
|
||||
message: $i18nBundle('common.msg.nonNull', [label])
|
||||
}, ..._rules]
|
||||
}
|
||||
if (option.pattern !== undefined) {
|
||||
const label = option.label || $i18nBundle(option.labelKey)
|
||||
_rules = [{
|
||||
pattern: option.pattern,
|
||||
message: option.patternMsg || $i18nBundle('common.msg.patternInvalid', [label])
|
||||
}, ..._rules]
|
||||
}
|
||||
}
|
||||
formItemRef.value && formItemRef.value.clearValidate()
|
||||
return _rules
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<el-form-item
|
||||
ref="formItemRef"
|
||||
:rules="rules"
|
||||
:prop="option.prop"
|
||||
>
|
||||
<template #label>
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
<script setup>
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import cloneDeep from 'lodash/cloneDeep'
|
||||
import { $i18nBundle } from '@/messages'
|
||||
import { ref, watch } from 'vue'
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { set } from 'lodash'
|
||||
|
||||
/**
|
||||
* @type {CommonFormProps}
|
||||
@@ -65,35 +64,6 @@ const props = defineProps({
|
||||
|
||||
const form = ref()
|
||||
|
||||
const rules = computed(() => {
|
||||
const ruleResult = {}
|
||||
props.options.forEach(option => {
|
||||
if (option.prop) {
|
||||
let _rules = cloneDeep(option.rules || [])
|
||||
if (option.required !== undefined) {
|
||||
const label = option.label || $i18nBundle(option.labelKey)
|
||||
_rules = [{
|
||||
trigger: option.trigger,
|
||||
required: option.required,
|
||||
message: $i18nBundle('common.msg.nonNull', [label])
|
||||
}, ..._rules]
|
||||
}
|
||||
if (option.pattern !== undefined) {
|
||||
const label = option.label || $i18nBundle(option.labelKey)
|
||||
_rules = [{
|
||||
pattern: option.pattern,
|
||||
message: option.patternMsg || $i18nBundle('common.msg.patternInvalid', [label])
|
||||
}, ..._rules]
|
||||
}
|
||||
if (_rules.length) {
|
||||
ruleResult[option.prop] = _rules
|
||||
}
|
||||
}
|
||||
})
|
||||
form.value && form.value.clearValidate()
|
||||
return ruleResult
|
||||
})
|
||||
|
||||
const emit = defineEmits(['submitForm', 'update:model'])
|
||||
|
||||
const formModel = useVModel(props, 'model', emit)
|
||||
@@ -102,7 +72,7 @@ const initFormModel = () => {
|
||||
if (formModel.value) {
|
||||
props.options.forEach(option => {
|
||||
if (option.prop) {
|
||||
formModel.value[option.prop] = option.value || undefined
|
||||
set(formModel.value, option.prop, option.value || undefined)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -123,19 +93,29 @@ defineExpose({
|
||||
ref="form"
|
||||
class="common-form"
|
||||
:model="formModel"
|
||||
:rules="rules"
|
||||
:label-width="labelWidth"
|
||||
v-bind="$attrs"
|
||||
:validate-on-rule-change="validateOnRuleChange"
|
||||
>
|
||||
<common-form-control
|
||||
<template
|
||||
v-for="(option,index) in options"
|
||||
:key="index"
|
||||
>
|
||||
<slot
|
||||
v-if="option.slot"
|
||||
name="option.slot"
|
||||
:option="option"
|
||||
:form="form"
|
||||
:model="formModel"
|
||||
/>
|
||||
<common-form-control
|
||||
:model="formModel"
|
||||
:option="option"
|
||||
/>
|
||||
</template>
|
||||
<slot
|
||||
:form="form"
|
||||
:model="formModel"
|
||||
name="default"
|
||||
/>
|
||||
<el-form-item v-if="showButtons">
|
||||
@@ -160,11 +140,13 @@ defineExpose({
|
||||
</el-button>
|
||||
<slot
|
||||
:form="form"
|
||||
:model="formModel"
|
||||
name="buttons"
|
||||
/>
|
||||
</el-form-item>
|
||||
<slot
|
||||
:form="form"
|
||||
:model="formModel"
|
||||
name="after-buttons"
|
||||
/>
|
||||
</el-form>
|
||||
|
||||
2
src/components/common-form/public.d.ts
vendored
2
src/components/common-form/public.d.ts
vendored
@@ -41,6 +41,8 @@ export interface CommonFormOption {
|
||||
tooltip: string;
|
||||
/** 提示函数 */
|
||||
tooltipFunc: () => void;
|
||||
/** 自定义slot名称 */
|
||||
slot: string;
|
||||
}
|
||||
|
||||
export interface CommonFormProps extends FormProps {
|
||||
|
||||
Reference in New Issue
Block a user