首页 > Vue >

vue多条件组合可视化编辑动态查询规则组件

时间: 作者:admin 浏览:

参考图
项目中需要用到多条件组合可视化编辑,而且要多层嵌套,具体编辑完后的数据结构基本如下:

{
    relation: "and",
    conditions: [{
        name: "条件名1",
        operate: "等于",
        value: "值"
    },{
        name: "条件名2",
        operate: "等于",
        value: "值"
    }],
    children: [{
        relation: "",
        conditions: [],
        children: []
    }]
}

主要是用到组件递归(调用自己)的逻辑,使得整个组件变得很简单,上代码:
template:

<div class="rules-box">
    <el-card class="box-card">
        <el-row>
            <el-row class="loop-child flex-row">
                <el-select 
                    class="relations-box"
                    size="mini"
                    v-model="rulesData.relation"
                    @change="ruleChange"
                >
                    <el-option
                        v-for="item in relations"
                        :label="item.label"
                        :value="item.value"
                        :key="item.value"
                    ></el-option>
                </el-select>
                <div
                    v-if="enableDeleteChild"
                    class="delete-child"
                    title="删除子条件"
                    @click="deleteChild(autoIndex)"
                ><i class="el-icon-delete-solid"></i></div>
                <div
                    class="add-child"
                    title="添加子条件"
                    @click="addChild"
                ><i class="el-icon-s-unfold"></i></div>
                <div
                    class="add-sibling"
                    title="添加同级条件"
                    @click="addCondition"
                ><i class="el-icon-circle-plus"></i></div>
            </el-row>
            <template v-for="(item, index) in rulesData.conditions">
                <el-row :key="'condition'+index" class="flex-row loop-child">
                    <el-select
                        class="condition-name"
                        v-model="item.name"
                        @change="rulesChange"
                        size="mini"
                        placeholder="请选择条件名"
                    >
                        <el-option
                            v-for="form in formDatas"
                            :label="form.label"
                            :value="form.value"
                            :key="form.value"
                        ></el-option>
                    </el-select>
                    <el-select
                        class="condition-operate"
                        v-model="item.operate"
                        @change="rulesChange"
                        size="mini"
                        placeholder="请选择逻辑符号"
                    >
                        <el-option
                            v-for="oper in operators"
                            :label="oper.label"
                            :value="oper.value"
                            :key="oper.value"
                        ></el-option>
                    </el-select>
                    <div class="condition-value">
                        <el-input
                            size="mini"
                            v-model="item.value"
                            @input="rulesChange"
                            placeholder="请输入条件值"
                        />
                    </div>
                    <div
                        class="delete-condition"
                        @click="deleteCondition(index)"
                        title="删除条件"
                    ><i class="el-icon-delete-solid"></i></div>
                </el-row>
            </template>
            <el-row
                v-if="rulesData.children.length > 0"
                v-for="(group, index) in rulesData.children"
                class="loop-child"
                :key="'row-'+autoIndex+'-'+index"
            >
                <create-rule
                    :topDatas="rulesData"
                    :rulesData="group"
                    :enableDeleteChild="true"
                    :autoIndex="index"
                    @rulesChange="childChange"
                />
            </el-row>
        </el-row>
    </el-card>
</div>

javascript:

export default {
    name:"CreateRule",
    mixins:[],
    props:{
        rulesData: {
            type: Object,
            default: ()=>{
                return {
                    relation: 'and',
                    conditions: [],
                    children: []
                }
            }
        },
        formDatas: {
            type: Array,
            default: ()=>{
                return []
            }
        },
        topDatas: {
            type: Object,
            default: ()=>{
                return {
                    relation: 'and',
                    conditions: [],
                    children: []
                }
            }
        },
        enableDeleteChild: {
            type: Boolean,
            default: false
        },
        autoIndex: {
            type: Number,
            default: 0
        }
    },
    data(){
        return {
            relations:[{
                label: "满足全部条件",
                value:"and"
            },{
                label: "满足任一条件",
                value:"or"
            }],
            operators: [{
                label:"等于",
                value:"=="
            },[{
                label:"大于",
                value:">"
            },[{
                label:"大于等于",
                value:">="
            },[{
                label:"小于",
                value:"<"
            },[{
                label:"小于等于",
                value:"<="
            },[{
                label:"不等于",
                value:"!="
            }]
        }
    },
    methods:{
        addCondition(){
            let conditionName = this.formDatas && this.formDatas[0] && this.formDatas[0].label
            if(conditionName){
                this.rulesData.conditions.push({
                    name: conditionName,
                    operate:"==",
                    value:""
                })
                this.rulesChange(this.rulesData)
            }else{
                this.$message.warning("请先获取条件数据!")
            }
        },
        addChild(){
            let conditionName = this.formDatas && this.formDatas[0] && this.formDatas[0].label
            if(conditionName){
                this.rulesData.children.push({
                    relation: 'and',
                    conditions:[],
                    children:[]
                })
                this.changeObserver()//监测组件是否改变的方法,组件改变不等于条件改变的ruleChange方法
            }else{
                this.$message.warning("请先获取条件数据!")
            }
        },
        deleteChild(index){
            let conditionDelete = this.topDatas && this.topDatas.children && this.topDatas.children.length > 0
            if(conditionDelete){
                this.topDatas.children.splice(index, 1)
            }
            this.rulesChange(this.rulesData)
        },
        deleteCondition(index){
            this.rulesData.conditions.splice(index, 1)
            this.rulesChange()
        },
        childChange(childData){
            this.rulesChange()
        },
        rulesChange(){
            this.changeObserver()
            this.$emit("rulesChange", this.rulesData)
        },
        changeObserver(){
            this.$emit("changeObserver", this.rulesData)
        }
    }
}

css:

<style lang="scss" scoped>
    .rules-box{
        width:100%;
        *{
            box-sizing:border-box;
        }
        ::v-deep {
            .el-card__body{
                padding:0 1em;
            }
        }
        .flex-row{
            display: flex;
            flex-direction: row;
            align-items:center;
        }
        .loop-child{
            width:100%;
            position:relative;
            border:1px solid #d9d9d9;
            border-style: none none none solid;
            padding:10px 0 10px 12px;
            line-height:1;

            ::v-deep {
                .el-input__icon{
                    width:14px;
                    line-height:28px;
                }
                .el-input__inner{
                    padding-left:5px;
                    padding-right:18px;
                }
            }
            &::before{
                display:block;
                content:'';
                position:absolute;
                background-color:white;
                width:1px;
                height:50%;
            }
            &:first-child::before{
                left:-1px;
                top:0;
            }
            &:last-child::before{
                left:-1px;
                bottom:0;
            }
            &::after{
                top:50%;
                left:0;
                position:absolute;
                content:'';
                display:block;
                width:1px;
                height:1px;
                border:1px solid #d9d9d9;
                border-style: solid none none none;
            }
            .relations-box{
                margin-right:0.5em;
            }
            .delete-child{
                cursor:pointer;
                padding:0.28em;
                margin-right:0.5em;
            }
            .delete-condition{
                cursor:pointer;
                padding:0.28em;
                margin:0 0 0 0.5em;
            }
            .add-child{
                cursor:pointer;
                padding:0.28em;
                margin-right:0.5em;

                i{
                    font-size:18px;
                }
            }
            .add-sibling{
                cursor:pointer;
                padding:0.28em;
                margin-right:0.5em;

                i{
                    font-size:18px;
                }
            }
            .condition-name{
                max-width:140px;
                ::v-deep{
                    .el-input{
                        display:inline-block;
                    }
                }
            }
            .condition-operate{
                max-width:83px;
            }
            .condition-value{
                flex:1;
                margin-left:1rem;
            }
        }
    }
</style>

调用方法:

<create-rule :formDatas="formDatas" :rulesData="rulesData" @rulesChange="rulesChange" />
export default {
    data(){
        return {
            formDatas:[
                {
                    label:"条件名1",
                    value:"one"
                },
                {
                    label:"条件名2",
                    value:"two"
                }
            ],
            rulesData:{//初始化条件对象或者,已保存的条件对象
                relation:"and",
                conditions:[],
                children:[]
            }
        }
    },
    methods:{
        rulesChange(datas){
            console.log(datas)//输出的条件对象
        }
    }
}

参考资料:

https://blog.csdn.net/weixin_49847526/article/details/124383704

前端新手交流群
欢迎加入web前端新手交流qq群:734802480

更多文章

栏目文章


Copyright © 2014-2022 seozhijia.net 版权所有-粤ICP备13087626号-4