基于element的自定义组件实现前端自定义sql查询条件(改良版)

此篇文章是对基于element的自定义组件实现前端自定义sql查询条件的优化改良版,优化后版本使用更简单,无需在父组件内创建方法处理数据变动

自定义输入选择框组件 (InputSelect.vue)

此组件实现了一个自定义的输入选择框,允许用户选择一个条件类型并通过输入框输入对应的值。组件可以被多个实例化,并且所有的实例都会更新同一个数组对象,该数组对象在父组件中通过 v-model 进行双向绑定。

组件功能概述

  1. 条件选择:通过下拉菜单选择条件类型。
  2. 值输入:根据选择的条件类型,在输入框中输入对应的值。
  3. 禁用输入:对于某些条件类型(如 isNull),输入框会被禁用。
  4. 动态更新:当条件类型或值发生变化时,自动更新父组件中的数组对象。

组件效果

在这里插入图片描述

数据请求格式

在这里插入图片描述

组件相关代码

<template>
  <div>
    <el-input placeholder="请输入"
              v-model="columnValue"
              class="input-with-select"
              clearable
              :disabled="disabledType.includes(columnType)"
              @input="updateItem">
      <el-select slot="prepend"
                 placeholder="请选择"
                 style="width: 110px"
                 clearable
                 v-model="columnType"
                 @change="updateItem">
        <el-option-group v-for="group in options"
                         :key="group.label">
          <el-option v-for="item in group.options"
                     :key="item.value"
                     :label="item.label"
                     :value="item.value">
          </el-option>
        </el-option-group>
      </el-select>
    </el-input>
  </div>
</template>

<script>
/**
 * *****使用方法*****
 *
 * 在父组件中添加引用。columnName为查询的字段,v-model为父组件中绑定的变量
 *
 * <input-select columnName="status" v-model="queryParams.items" />
 *
 */
export default {
  name: 'InputSelect',
  props: {
    value: {
      type: Array,
      required: true,
      default: [],
    },
    columnName: {
      type: String,
      required: true,
      default: null,
    }
  },
  data() {
    return {
      options: [
        {label: 'e', options: [{value: 'eq', label: '精确匹配'}, {value: 'notEq', label: '不匹配'}]},
        {label: 'l', options: [{value: 'like', label: '包含'}, {value: 'notLike', label: '不包含'}]},
        {label: 'll', options: [{value: 'left', label: '开头是'}, {value: 'right', label: '结尾是'}]},
        {label: 'n', options: [{value: 'isNull', label: '为空'}, {value: 'notNull', label: '不为空'}]},
        {label: 'b', options: [{value: 'isBlank', label: '空文本'}, {value: 'notBlank', label: '非空文本'}]}
      ],
      disabledType: ['isNull', 'notNull', 'isBlank', 'notBlank'],
      columnType: 'eq',
      columnValue: ''
    }
  },
  watch: {
    value: {
      handler(newItems) {
        // 当items发生变化时,更新内部的状态
        const foundItem = newItems.find(item => item.columnName === this.columnName);
        if (foundItem) {
          this.columnType = foundItem.columnType;
          this.columnValue = foundItem.columnValue;
        } else {
          this.columnType = 'eq';
          this.columnValue = '';
        }
      },
      deep: true
    }
  },
  methods: {
    updateItem() {
      if (this.disabledType.includes(this.columnType)) {
        this.columnValue = '';
      }
      const updateItems = [...this.value]
      // 更新单个项的信息
      const item = {columnName: this.columnName, columnValue: this.columnValue, columnType: this.columnType};

      // 移除已存在的相同属性名称的项
      const existingItemIndex = updateItems.findIndex(i => i.columnName === this.columnName);
      if (existingItemIndex > -1) {
        updateItems.splice(existingItemIndex, 1);
      }

      // 检查是否所有必需的属性都有值
      if (item.columnName && item.columnType && (item.columnValue || this.disabledType.includes(item.columnType))) {
        // 添加新的项
        updateItems.push(item);
      }
      this.$emit('input', updateItems);
    }
  }
}
</script>
<style scoped>
</style>

后端逻辑可参考(以mybatis为例)

 <if test="query.items!= null and query.items.size() > 0">
   <foreach collection="query.items" separator="AND" item="condition">
	    <choose>
	        <!-- 精确匹配 -->
	        <when test="condition.columnType == 'eq'">
	            AND ${condition.columnName} = #{condition.columnValue}
	        </when>
	        <!-- 不匹配 -->
	        <when test="condition.columnType == 'notEq'">
	            AND ${condition.columnName} != #{condition.columnValue}
	        </when>
	        <!-- 包含 -->
	        <when test="condition.columnType == 'like'">
	            AND ${condition.columnName} LIKE CONCAT('%', #{condition.columnValue}, '%')
	        </when>
	        <!-- 不包含 -->
	        <when test="condition.columnType == 'notLike'">
	            AND ${condition.columnName} NOT LIKE CONCAT('%', #{condition.columnValue}, '%')
	        </when>
	        <!-- 开头是 -->
	        <when test="condition.columnType == 'left'">
	            AND ${condition.columnName} LIKE CONCAT(#{condition.columnValue}, '%')
	        </when>
	        <!-- 结尾是 -->
	        <when test="condition.columnType == 'right'">
	            AND ${condition.columnName} LIKE CONCAT('%', #{condition.columnValue})
	        </when>
	        <!-- 为空 -->
	        <when test="condition.columnType == 'isNull'">
	            AND ${condition.columnName} IS NULL
	        </when>
	        <!-- 不为空 -->
	        <when test="condition.columnType == 'notNull'">
	            AND ${condition.columnName} IS NOT NULL
	        </when>
	        <!-- 空文本 -->
	        <when test="condition.columnType == 'isBlank'">
	            AND (${condition.columnName} = '' OR ${columnName} IS NULL)
	        </when>
	        <!-- 非空文本 -->
	        <when test="condition.columnType  == 'notBlank'">
	            AND (${condition.columnName} != '' AND ${columnName} IS NOT NULL)
	        </when>
	        <!-- 其他情况 -->
	        <otherwise>
	            <!-- 处理未匹配到的情况,通常为空或报错 -->
	        </otherwise>
	    </choose>
    </foreach>
</if>

HTML 结构

  • el-input:主输入框,用于输入值。
  • el-select:条件选择器,用于选择条件类型。
  • el-option-groupel-option:用于组织和展示条件选项。
 <div>
    <el-input placeholder="请输入"
              v-model="columnValue"
              class="input-with-select"
              clearable
              :disabled="disabledType.includes(columnType)"
              @input="updateItem">
      <el-select slot="prepend"
                 placeholder="请选择"
                 style="width: 110px"
                 clearable
                 v-model="columnType"
                 @change="updateItem">
        <el-option-group v-for="group in options"
                         :key="group.label">
          <el-option v-for="item in group.options"
                     :key="item.value"
                     :label="item.label"
                     :value="item.value">
          </el-option>
        </el-option-group>
      </el-select>
    </el-input>
  </div>

JavaScript 逻辑

  • props:接收父组件传入的数组 value 和列名 columnName
  • data:存储组件内部状态,包括条件类型、值以及条件选项。
  • watch:监听 value 的变化,更新组件内部状态。
  • methods
    • updateItem:当条件类型或值发生变化时,更新父组件中的数组对象。
export default {
  name: 'InputSelect',
  props: {
    value: {
      type: Array,
      required: true,
      default: [],
    },
    columnName: {
      type: String,
      required: true,
      default: null,
    }
  },
  data() {
    return {
      options: [
        {label: 'e', options: [{value: 'eq', label: '精确匹配'}, {value: 'notEq', label: '不匹配'}]},
        {label: 'l', options: [{value: 'like', label: '包含'}, {value: 'notLike', label: '不包含'}]},
        {label: 'll', options: [{value: 'left', label: '开头是'}, {value: 'right', label: '结尾是'}]},
        {label: 'n', options: [{value: 'isNull', label: '为空'}, {value: 'notNull', label: '不为空'}]},
        {label: 'b', options: [{value: 'isBlank', label: '空文本'}, {value: 'notBlank', label: '非空文本'}]}
      ],
      disabledType: ['isNull', 'notNull', 'isBlank', 'notBlank'],
      columnType: 'eq',
      columnValue: ''
    }
  },
  watch: {
    value: {
      handler(newItems) {
        // 当items发生变化时,更新内部的状态
        const foundItem = newItems.find(item => item.columnName === this.columnName);
        if (foundItem) {
          this.columnType = foundItem.columnType;
          this.columnValue = foundItem.columnValue;
        } else {
          this.columnType = 'eq';
          this.columnValue = '';
        }
      },
      deep: true
    }
  },
  methods: {
    updateItem() {
      if (this.disabledType.includes(this.columnType)) {
        this.columnValue = '';
      }
      const updateItems = [...this.value]
      // 更新单个项的信息
      const item = {columnName: this.columnName, columnValue: this.columnValue, columnType: this.columnType};

      // 移除已存在的相同属性名称的项
      const existingItemIndex = updateItems.findIndex(i => i.columnName === this.columnName);
      if (existingItemIndex > -1) {
        updateItems.splice(existingItemIndex, 1);
      }

      // 检查是否所有必需的属性都有值
      if (item.columnName && item.columnType && (item.columnValue || this.disabledType.includes(item.columnType))) {
        // 添加新的项
        updateItems.push(item);
      }
      this.$emit('input', updateItems);
    }
  }
}

使用示例

在父组件中,你可以像下面这样使用这个组件:

假设我们需要一个用于搜索备注和状态字段的输入选择组件,我们可以这样使用:

 <el-form :model="queryParams" ref="queryForm" v-show="showSearch" inline>
      <el-form-item label="备注" prop="items">
        <input-select columnName="remark" v-model="queryParams.items"/>
      </el-form-item>
      <el-form-item label="状态" prop="items">
        <input-select columnName="status" v-model="queryParams.items" />
      </el-form-item>
      <el-form-item class="queryBtn">
        <el-button type="primary" icon="el-icon-search" @click="handleQuery">搜索</el-button>
        <el-button icon="el-icon-refresh" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

总结

这个组件允许用户通过选择条件类型和输入值来构建查询条件,并且可以被多个实例化,所有的实例都会更新同一个数组对象。这使得在前端构建复杂的查询条件变得更加简单和直观。

  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值