vue快速构建form表单:联动规则

联动规则的构建(我的构建方式):
构思:
整个form表单分为2个部分
1是form 主要是整个form的显示,提交取消回调,错误信息显示等
2输入控件:如select等

现在添加联动规则,select为例:
select的选项获取有2种,参数设定和ajax获取两种
所以联动有两种形式:过滤现有的选项和重置ajax请求参数获取选项
1.设置要联动的字段参数
过滤:

   {
        type: 'select',
        name: 'column2',
        column: '',
        linkage: 'column1', // 与form字段column1联动
        linkageFilter (item, val) {
            return item.value == val
        },
        options: [
            {text: '测试1', value: '1'},
            {text: '测试2', value: '2'},
            {text: '测试3', value: '3'}
        ]
   }

ajax参数:

   {
        type: 'select',
        name: 'column2',
        column: '',
        linkage: 'column1', // 与form字段column1联动
        url: '/'  // 只需要参数就好,到时select组件会自动将 column1='val' 作为请求参数
   }

2.form.vue watch监听选项变化
检查每个字段是否有联动,如果有联动,将变化的值赋予对应的select组件内的linkageVal

form: { 
            handler (val) { 
                // 联动规则
                for(var i in this.options.columns){
                    if (this.options.columns[i].linkage){
                        this.$refs[this.options.columns[i].column][0].linkageVal = val[this.options.columns[i].linkage]
                    }
                }
            },
            deep: true
        }

3.select.vue 监听linkageVal的变化
分别根据是否有url参数执行过滤还是重新ajax请求

我的源码:
form.vue组件

<template>
    <form v-if="options" onsubmit="return false">
      <template v-for="c in options.columns">
          <div class="form-group">
            <label>
                <span style="color:red" v-if="c.required">*</span> {{ c.name }}
            </label>
            <component :is="'v-'+c.type" :class="!errors[c.column]?'form-control':'form-control is-invalid'" :options="c" v-model="form[c.column]" :ref="c.column"/>
            <div class="invalid-feedback" v-if="errors[c.column]">{{ errors[c.column] }}</div>
        </div>
      </template>
      <a class="btn border" v-on:click="onCancel">取消</a>
      <div class="form-group" v-if="!options.template">
          <div class="col-sm-12 justify-between text-right">
              <a class="btn border" v-on:click="onCancel">取消</a>
              <button class="btn btn-primary" v-on:click="onSave">
                  <i class="fa fa-spin fa-circle-o-notch" v-if="options.submiting"/> 保存
              </button>
          </div>
      </div>
    </form>
</template>
<script>
import select from './control/select'
export default{ 
    name: 'components-common-content-form',
    props: ['options'],
    data () { 
        return { 
            form: {},
            errors: {}
        }
    },
    watch: { 
        errors () {
            this.$forceUpdate()
        },
        form: { 
            handler (val,oVal) { 
                if (typeof this.options.watch == 'function') { 
                    this.options.watch(val)
                }
                // 联动规则
                for(var i in this.options.columns){
                    if (this.options.columns[i].linkage){
                        this.$refs[this.options.columns[i].column][0].linkageVal = val[this.options.columns[i].linkage]
                    }
                }
            },
            deep: true
        }
    },
    methods: {
        onSave () { 
            if (typeof this.options.onSave == 'function') { 
                this.options.onSave(this.form)
            }
        },
        onCancel () { 
            if (typeof this.options.onCancel == 'function') { 
                this.options.onCancel(this.form)
            }
            this.$refs.ldm.getOptions()
        },
        setData (data) { 
            this.form = data
        },
        clearData () { 
            this.form = {}
        },
        setErrors (errors) { 
            this.errors = errors
        },
        clearErrors () { 
            this.errors = {}
        }
    },
    components: { 
        'v-select': select
    }
}
</script>

select.vue 组件

<template>
    <div v-if="options" class="form-control">
        <div class="bg-white rounded p-2" v-if="axiosSource">
            <span ><i  class="fa fa-spinner fa-pulse"/> 数据加载中</span>
        </div>
        <div class="bg-white rounded" v-else>
            <select class="form-control" v-model="localValue">
                <option value="">请选择{{ options.name }}</option>
                <option v-for="o in showOptions" :value="o.value">{{ o.text }}</option>
            </select>
        </div>
    </div>
</template>
<script>
export default{ 
    name: 'components-common-content-control-checkbox',
    props: ['options','value'],
    data () { 
        return { 
            localValue: '',
            localOptions: [],
            linkageVal: '',
            axiosSource: null
        }
    },
    created () {
        if (this.options.url) { 
            this.getOptions()
        }else{ 
            this.options.options?this.localOptions = this.options.options: this.localOptions = []
        }
    },
    watch:{ 
        localValue () { 
            this.$emit('input', this.localValue)
        },
        value () { 
            this.localValue = this.value
        },
        // 联动ajax请求
        linkageVal () { 
            if (this.options.url) { 
                this.getOptions()
            }
        }
    },
    computed: { 
        showOptions () {
            var _this = this
            var val = _this.linkageVal
            var options = _this.localOptions
            // 联动选项筛选
            if (!this.options.url && typeof this.options.linkageFilter == 'function') {
                options = options.filter(function(item){
                    if (val){
                        return _this.options.linkageFilter(item, val)
                    }else{ 
                        return true
                    }
                })
            }
            return options
        }
    },
    methods: {
        getOptions () { 
            var _this = this
            if (_this.axiosSource) { 
                _this.axiosSource.cancel('中断并开始新的请求');
            }
            _this.axiosSource = axios.CancelToken.source()
            // 联动请求
            var url = _this.options.url
            if (_this.linkageVal) { 
                url = _this.options.url + '?' + this.options.linkage + '=' + _this.linkageVal
            }
            // axios开始请求
            axios.get(url)
            .then(function (response) {
                _this.localOptions = response.data
                _this.axiosSource = null
            })
            .catch(function (error) {
                if (error.response.status == 400) {
                    _this.alert({
                        title: '提示',
                        msg: error.response.data.message
                    });
                }else{ 
                    _this.alert({
                        title: error.response.status + '错误',
                        msg: error.response.data.message
                    });
                }
                _this.axiosSource = null
            });
        }
    }
}
</script>
<style scoped>
    .form-control{ 
        padding: 0;
        height: auto;
        background: none;
    }
    .form-control .form-control{ 
        border: 0px;
        padding: 0.375rem 0.75rem;
    }
    .form-control select{ 
        width: 100%;
        height: 100%;
    }
</style>

使用方式

<v-form :options="options" class="w-100" ref="form"/>

options: { 
                columns: [ 
                    { 
                        type: 'select',
                        name: 'select联动主体',
                        column: 'ldm',
                        options: [
                            { 
                                text: '选择1',
                                value: 1
                            },
                            { 
                                text: '选择2',
                                value: 2
                            }
                        ]
                    },
                    { 
                        type: 'select',
                        name: 'select联动附体1',
                        column: 'lda1',
                        linkage: 'ldm',
                        linkageFilter (item, val) { 
                            return item.value == val
                        },
                        options: [
                            { 
                                text: '联动1',
                                value: 1
                            },
                            { 
                                text: '联动2',
                                value: 2
                            }
                        ]
                    },
                    { 
                        type: 'select',
                        name: 'select联动附体2',
                        column: 'lda2',
                        linkage: 'ldm',
                        url: '/'
                    }
                ]
            }
    原文作者:改改心情
    原文地址: https://segmentfault.com/a/1190000018787196
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞