vue自定义无限层级条件配置

192 阅读1分钟

简介:vue+elementui自定义无限层级条件配置。如图:

2023-04-14_182007.png

  1. 基础组件做无限递归(item.vue)
  <div class="custom-menu">
    <template v-for="(item, index) in treeData">
      <div v-if="item.type === 'CD'" class="node" :class="treeData[index+1] ? 'node-style':''" :key="index" style="marginLeft:20px;marginTop:6px;">
        <el-row :gutter="10">
          <el-col :span="5">
            <el-input v-model="item.field"></el-input>
          </el-col>
          <el-col :span="5">
            <el-select v-model="item.op" v-show="item.field">
              <el-option label="或" value="or"></el-option>
              <el-option label="并" value="and"></el-option>
            </el-select>
          </el-col>
          <el-col :span="12">
            <div style="width:100%;">
              <el-input v-model="item.val" v-show="item.field"></el-input>
            </div>
          </el-col>
          <el-col :span="2">
            <span style="lineHeight:32px;fontSize:16px;cursor:pointer;">
              <i class="el-icon-close" @click="clearn(item.id)"></i>
            </span>
          </el-col>
        </el-row>
      </div>
      <div v-else :key="index" class="node" :class="treeData[index+1] ? 'node-style':''" style="marginLeft:20px;marginTop:6px;">
        <el-row :gutter="20">
          <el-col :span="6">
            <el-select v-model="item.op">
              <el-option label="或" value="or"></el-option>
              <el-option label="并" value="and"></el-option>
            </el-select>
          </el-col>
          <el-col :span="18" class="btn-group">
            <span @click="add('condit', item.id)">
              <i class="el-icon-circle-plus-outline"></i>
              添加条件
            </span>
            <span @click="add('group', item.id)">
              <i class="el-icon-circle-plus-outline"></i>
              添加组
            </span>
            <span @click="clearn(item.id)">
              <i class="el-icon-delete"></i>
              删除组
            </span>
          </el-col>
        </el-row>
        <template>
          <ItemCompons :treeData='item.children' @addHandle="addHandle" @deleteItem="deleteItem"></ItemCompons>
        </template>
      </div>
    </template>
  </div>
</template>

<script>
export default {
  name: 'ItemCompons',
  props: {
    treeData: {
      type: Array,
      default () {
        return []
      }
    }
  },
  methods: {
    add (type, id) {
      this.$emit('addHandle', type, id)
    },
    clearn (id) {
      this.$emit('deleteItem', id)
    },
    deleteItem (id) {
      this.$emit('deleteItem', id)
    },
    addHandle (type, id) {
      this.$emit('addHandle', type, id)
    }
  },
  data () {
    return {

    }
  }
}
</script>

<style lang="less">
.custom-menu{
  .el-col{
    border:1px solid transparent
  }
}
.custom-menu {
  .node:after {
    border-top: none;
  }
  .node {
    position: relative;
    padding-left: 16px;
  }
  .node:before {
    content: "";
    left: -1px;
    position: absolute;
    right: auto;
    border-width: 1px;
  }

  .node:after {
    content: "";
    left: 1px;
    position: absolute;
    right: auto;
    border-width: 1px;
  }

  .node:before {
    border-left: 1px dashed #bec0c5;
    bottom: 0px;
    height: 20px;
    top: -4px;
    width: 1px;
  }
  .node-style:before {
    border-left: 1px dashed #bec0c5;
    bottom: 0px;
    height: calc(100% + 4px);
    top: -4px;
    width: 1px;
  }
  .node:after {
    border-top: 1px dashed #bec0c5;
    height: 20px;
    top: 16px;
    width: 15px;
  }
}
</style>

  1. 初始化父级组件(slide.vue)
  <div>
    <el-row :gutter="20">
      <el-col :span="6">
        <el-select v-model="resultData.op">
          <el-option label="或" value="or"></el-option>
          <el-option label="并" value="and"></el-option>
        </el-select>
      </el-col>
      <el-col :span="18" class="btn-group">
        <span @click="add('condit')">
          <i class="el-icon-circle-plus-outline"></i>
          添加条件
        </span>
        <span @click="add('group')">
          <i class="el-icon-circle-plus-outline"></i>
          添加组
        </span>
        <span @click="clearn">
          <i class="el-icon-delete"></i>
          清空条件
        </span>
        <span>
          <i class="el-icon-warning-outline"></i>
        </span>
      </el-col>
    </el-row>
    <ItemCompon :treeData="resultData.children" @addHandle="addHandle" @deleteItem="deleteItem"></ItemCompon>
  </div>
</template>

<script>
import ItemCompon from './item'
import { nanoid } from 'nanoid'
export default {
  name: 'SlideItem',
  components: {
    ItemCompon
  },
  props: {},
  methods: {
    clearn () {
      this.resultData.children = []
    },
    deleteItem (id) {
      const tempData = JSON.parse(JSON.stringify(this.resultData))
      this.resultData = this.deepDelete(tempData, id)
    },
    deepDelete (obj, id) {
      obj.children.map((item, index) => {
        if (item.id === id) {
          console.log(obj)
          obj.children.splice(index, 1)
          console.log(obj)
        }
        if (item.children) {
          this.deepDelete(item, id)
        }
        return item
      })
      return obj
    },
    addHandle (type, id) {
      let obj = {}
      if (type === 'condit') {
        obj = {
          id: nanoid(),
          type: 'CD',
          field: '',
          op: '',
          val: '',
          children: []
        }
      } else if (type === 'group') {
        obj = {
          id: nanoid(),
          type: 'GP',
          field: '',
          op: '',
          val: '',
          children: [
            {
              id: nanoid(),
              type: 'CD',
              field: '',
              op: '',
              val: '',
              children: []
            }
          ]
        }
      }
      this.deepMap(this.resultData, id, obj)
    },
    deepMap (obj, id, data) {
      obj.children.map(item => {
        if (item.id === id) {
          item.children.push(data)
        }
        if (item.children) {
          this.deepMap(item, id, data)
        }
        return item
      })
    },
    add (type) {
      if (type === 'condit') {
        this.resultData.children.push({
          id: nanoid(),
          type: 'CD',
          field: '',
          op: '',
          val: '',
          children: []
        })
      } else if (type === 'group') {
        this.resultData.children.push({
          id: nanoid(),
          type: 'GP',
          field: '',
          op: '',
          val: '',
          children: [
            {
              id: nanoid(),
              type: 'CD',
              field: '',
              op: '',
              val: '',
              children: []
            }
          ]
        })
      }
    }
  },
  data () {
    return {
      resultData: {
        op: 'and',
        children: []
      }
    }
  }
}
</script>

<style lang="less">
.btn-group{
  text-align: right;
  span{
    font-size: 14px;
    line-height: 32px;
    padding-right: 15px;
    cursor: pointer;
  }
}
</style>

  1. 页面引用
// 引入
import SlideItem from './slide'

// 注册
components: {
  SlideItem
}

// 使用
<SlideItem></SlideItem>