Commit ef2583ca7276d10d21d3d36194ffc03684286993
1 parent
463409cd
Exists in
master
and in
2 other branches
feat: 修改SchemaForm
Showing
2 changed files
with
115 additions
and
24 deletions
Show diff stats
examples/views/docs/component/schema-form.md
| ... | ... | @@ -228,6 +228,104 @@ export default { |
| 228 | 228 | |
| 229 | 229 | ::: |
| 230 | 230 | |
| 231 | +## 显示状态 | |
| 232 | + | |
| 233 | +支持配置`if`、`show`对表单项进行`v-if`、`v-show`逻辑的设置。 | |
| 234 | + | |
| 235 | +::: snippet 隐藏表单项的示例 | |
| 236 | + | |
| 237 | +```html | |
| 238 | +<template> | |
| 239 | + <z-schema-form v-model="form" :schema="schema"></z-schema-form> | |
| 240 | +</template> | |
| 241 | + | |
| 242 | +<script> | |
| 243 | +export default { | |
| 244 | + data() { | |
| 245 | + return { | |
| 246 | + form: { | |
| 247 | + name: '张三', | |
| 248 | + age: 27, | |
| 249 | + address: '上海市青浦区华新镇纪鹤公路1988号', | |
| 250 | + }, | |
| 251 | + schema: { | |
| 252 | + props: { labelWidth: '70px', size: 'small', span: 12 }, | |
| 253 | + items: [ | |
| 254 | + { is: 'el-input', prop: 'id', props: { disabled: true }, label: 'ID', show: false }, | |
| 255 | + { is: 'el-input', prop: 'name', label: '姓名', rules: [{ required: true, message: '请输入姓名' }] }, | |
| 256 | + { is: 'el-input-number', prop: 'age', label: '年龄', rules: [{ required: true, message: '请输入有效年龄' }] }, | |
| 257 | + { is: 'el-input', props: { type: 'textarea' }, prop: 'address', label: '住址', span: 24 }, | |
| 258 | + { is: 'el-input', prop: 'package', label: '包裹', span: 24, if: false }, | |
| 259 | + ] | |
| 260 | + }, | |
| 261 | + }; | |
| 262 | + }, | |
| 263 | +}; | |
| 264 | +</script> | |
| 265 | +``` | |
| 266 | + | |
| 267 | +::: | |
| 268 | + | |
| 269 | +## 动态规则 | |
| 270 | + | |
| 271 | +某些情况下,表单中的某一项根据另一项的值来做当前项`显示状态`、`校验规则`、`标签名称`的动态判断。支持将任意表单配置项的任意参数改写为`function`类型,参数提供`value`、`model`、`onInput`等。 | |
| 272 | + | |
| 273 | +::: snippet 动态规则仅在配置项中有效,配置项子节点中无效 | |
| 274 | + | |
| 275 | +```html | |
| 276 | +<template> | |
| 277 | + <z-schema-form v-model="form" :schema="schema" @submit="onSubmit" @reset="onReset" @cancel="onCancel"> | |
| 278 | + <template #footer="{ submit, reset, cancel }"> | |
| 279 | + <z-form-item> | |
| 280 | + <el-button type="primary" @click="submit">确定</el-button> | |
| 281 | + <el-button plain @click="reset">重置</el-button> | |
| 282 | + <el-button plain @click="cancel">取消</el-button> | |
| 283 | + </z-form-item> | |
| 284 | + </template> | |
| 285 | + </z-schema-form> | |
| 286 | +</template> | |
| 287 | + | |
| 288 | +<script> | |
| 289 | +export default { | |
| 290 | + data() { | |
| 291 | + return { | |
| 292 | + form: { | |
| 293 | + name: '', | |
| 294 | + age: '', | |
| 295 | + address: '', | |
| 296 | + }, | |
| 297 | + schema: { | |
| 298 | + props: { labelWidth: '70px', size: 'small', span: 12 }, | |
| 299 | + items: [ | |
| 300 | + { is: 'el-input', prop: 'name', label: '姓名', rules: [{ required: true, message: '请输入姓名' }] }, | |
| 301 | + { is: 'el-input-number', prop: 'age', label: '年龄', rules: [{ required: true, message: '请输入有效年龄' }], if({ model }) { return model.name } }, | |
| 302 | + { is: 'el-input', props: { type: 'textarea' }, prop: 'address', label: '住址', span: 24, | |
| 303 | + if({ model }) { return model.age }, | |
| 304 | + rules({ model }) { | |
| 305 | + return model.address ? [{ required: true, min: 3, max: 5, message: '长度在 3 到 5 个字符', trigger: 'input' }] : [{ required: false }]; | |
| 306 | + } | |
| 307 | + }, | |
| 308 | + ] | |
| 309 | + }, | |
| 310 | + }; | |
| 311 | + }, | |
| 312 | + methods: { | |
| 313 | + onSubmit(value) { | |
| 314 | + console.log(value); | |
| 315 | + }, | |
| 316 | + onReset() { | |
| 317 | + console.log('reset'); | |
| 318 | + }, | |
| 319 | + onCancel() { | |
| 320 | + console.log('cancal'); | |
| 321 | + } | |
| 322 | + } | |
| 323 | +}; | |
| 324 | +</script> | |
| 325 | +``` | |
| 326 | + | |
| 327 | +::: | |
| 328 | + | |
| 231 | 329 | ## 配置复用 |
| 232 | 330 | |
| 233 | 331 | 因为与`z-form`、`z-form-item`用法相同,所以除了可以用作表单以外,也可用作详情展示,同时因为本身是schema配置项,所以可以做到表单和详情**配置复用**。 | ... | ... |
packages/schema-form/index.vue
| ... | ... | @@ -2,32 +2,16 @@ |
| 2 | 2 | <z-form ref="form" v-model="model" v-bind="schema.props" v-on="schema.props"> |
| 3 | 3 | <template v-for="(item, index) in schema.items"> |
| 4 | 4 | <template v-if="item.is"> |
| 5 | - <z-form-item v-bind="keywordFilter(item)" :key="index"> | |
| 6 | - <slot | |
| 7 | - v-if="$scopedSlots[item.prop]" | |
| 8 | - :name="item.prop" | |
| 9 | - :value="get(model, item.prop)" | |
| 10 | - :onInput="value => onComponentInput({ value, item })" | |
| 11 | - :props="{ value: get(model, item.prop) }" | |
| 12 | - :listeners="{ input: value => onComponentInput({ value, item }) }" | |
| 13 | - v-bind="slotProps" | |
| 14 | - > | |
| 15 | - </slot> | |
| 5 | + <z-form-item v-if="bindParam(item, 'if', true)" v-show="bindParam(item, 'show', true)" v-bind="bindItemProps(item)" :key="index"> | |
| 6 | + <slot v-if="$scopedSlots[item.prop]" :name="item.prop" :value="get(model, item.prop)" :onInput="value => onComponentInput({ value, item })" v-bind="slotProps"> </slot> | |
| 16 | 7 | <item-render v-else :item="item" :value="get(model, item.prop)" :onInput="value => onComponentInput({ value, item })"></item-render> |
| 17 | 8 | <slot :name="`label-${item.prop}`" slot="label" v-bind="slotProps"></slot> |
| 18 | 9 | <slot :name="`error-${item.prop}`" slot="error" v-bind="slotProps"></slot> |
| 19 | 10 | </z-form-item> |
| 20 | 11 | </template> |
| 21 | 12 | <template v-else> |
| 22 | - <z-form-item v-bind="keywordFilter(item)" :key="index" :value="get(model, item.prop)"> | |
| 23 | - <slot | |
| 24 | - :name="item.prop" | |
| 25 | - :value="get(model, item.prop)" | |
| 26 | - :onInput="value => onComponentInput({ value, item })" | |
| 27 | - :props="{ value: get(model, item.prop) }" | |
| 28 | - :listeners="{ input: value => onComponentInput({ value, item }) }" | |
| 29 | - v-bind="slotProps" | |
| 30 | - ></slot> | |
| 13 | + <z-form-item v-if="bindParam(item, 'if', true)" v-show="bindParam(item, 'show', true)" v-bind="bindItemProps(item)" :key="index" :value="get(model, item.prop)"> | |
| 14 | + <slot :name="item.prop" :value="get(model, item.prop)" :onInput="value => onComponentInput({ value, item })" v-bind="slotProps"></slot> | |
| 31 | 15 | </z-form-item> |
| 32 | 16 | </template> |
| 33 | 17 | </template> |
| ... | ... | @@ -118,6 +102,19 @@ export default { |
| 118 | 102 | }, |
| 119 | 103 | methods: { |
| 120 | 104 | get, |
| 105 | + bindParam(item, key, def) { | |
| 106 | + if (typeof item[key] === 'function') { | |
| 107 | + return item[key]({ model: this.model }); | |
| 108 | + } | |
| 109 | + return def || item[key]; | |
| 110 | + }, | |
| 111 | + bindItemProps(item) { | |
| 112 | + const { children, is, props, on, ...other } = item || {}; | |
| 113 | + return Object.keys(other).reduce((result, current) => { | |
| 114 | + result = { ...result, [current]: this.bindParam(item, current, item[current]) }; | |
| 115 | + return result; | |
| 116 | + }, {}); | |
| 117 | + }, | |
| 121 | 118 | validate(callback) { |
| 122 | 119 | return this.$refs.form.validate(callback); |
| 123 | 120 | }, |
| ... | ... | @@ -130,10 +127,6 @@ export default { |
| 130 | 127 | clearValidate(props) { |
| 131 | 128 | return this.$refs.form.clearValidate(props); |
| 132 | 129 | }, |
| 133 | - keywordFilter(val = {}) { | |
| 134 | - const { children, is, ...other } = val; | |
| 135 | - return other; | |
| 136 | - }, | |
| 137 | 130 | onComponentInput({ value, item }) { |
| 138 | 131 | set(this.model, item.prop, value); |
| 139 | 132 | }, | ... | ... |