Commit ef2583ca7276d10d21d3d36194ffc03684286993

Authored by 刘汉宸
1 parent 463409cd

feat: 修改SchemaForm

examples/views/docs/component/schema-form.md
@@ -228,6 +228,104 @@ export default { @@ -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 因为与`z-form`、`z-form-item`用法相同,所以除了可以用作表单以外,也可用作详情展示,同时因为本身是schema配置项,所以可以做到表单和详情**配置复用**。 331 因为与`z-form`、`z-form-item`用法相同,所以除了可以用作表单以外,也可用作详情展示,同时因为本身是schema配置项,所以可以做到表单和详情**配置复用**。
packages/schema-form/index.vue
@@ -2,32 +2,16 @@ @@ -2,32 +2,16 @@
2 <z-form ref="form" v-model="model" v-bind="schema.props" v-on="schema.props"> 2 <z-form ref="form" v-model="model" v-bind="schema.props" v-on="schema.props">
3 <template v-for="(item, index) in schema.items"> 3 <template v-for="(item, index) in schema.items">
4 <template v-if="item.is"> 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 <item-render v-else :item="item" :value="get(model, item.prop)" :onInput="value => onComponentInput({ value, item })"></item-render> 7 <item-render v-else :item="item" :value="get(model, item.prop)" :onInput="value => onComponentInput({ value, item })"></item-render>
17 <slot :name="`label-${item.prop}`" slot="label" v-bind="slotProps"></slot> 8 <slot :name="`label-${item.prop}`" slot="label" v-bind="slotProps"></slot>
18 <slot :name="`error-${item.prop}`" slot="error" v-bind="slotProps"></slot> 9 <slot :name="`error-${item.prop}`" slot="error" v-bind="slotProps"></slot>
19 </z-form-item> 10 </z-form-item>
20 </template> 11 </template>
21 <template v-else> 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 </z-form-item> 15 </z-form-item>
32 </template> 16 </template>
33 </template> 17 </template>
@@ -118,6 +102,19 @@ export default { @@ -118,6 +102,19 @@ export default {
118 }, 102 },
119 methods: { 103 methods: {
120 get, 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 validate(callback) { 118 validate(callback) {
122 return this.$refs.form.validate(callback); 119 return this.$refs.form.validate(callback);
123 }, 120 },
@@ -130,10 +127,6 @@ export default { @@ -130,10 +127,6 @@ export default {
130 clearValidate(props) { 127 clearValidate(props) {
131 return this.$refs.form.clearValidate(props); 128 return this.$refs.form.clearValidate(props);
132 }, 129 },
133 - keywordFilter(val = {}) {  
134 - const { children, is, ...other } = val;  
135 - return other;  
136 - },  
137 onComponentInput({ value, item }) { 130 onComponentInput({ value, item }) {
138 set(this.model, item.prop, value); 131 set(this.model, item.prop, value);
139 }, 132 },