组件功能概述
InputSelect
是一个结合了输入框 (el-input
) 和下拉选择框 (el-select
) 的复合组件。用户可以先选择一个条件类型,然后输入相应的值。这个组件特别适合用于表单中的高级搜索或过滤场景。
优化版====>>>基于element的自定义组件实现前端自定义sql查询条件(改良版)
优化后版本使用更简单,无需在父组件内创建方法处理数据变动
组件效果
数据请求格式
后端逻辑可参考(以mybatis为例)
<if test="query.matchList != null and query.matchList.size() > 0">
<foreach collection="query.matchList" separator="AND" item="condition">
<choose>
<!-- 精确匹配 -->
<when test="condition.value == 'eq'">
AND ${columnName} = #{columnValue}
</when>
<!-- 不匹配 -->
<when test="condition.value == 'notEq'">
AND ${columnName} != #{columnValue}
</when>
<!-- 包含 -->
<when test="condition.value == 'like'">
AND ${columnName} LIKE CONCAT('%', #{columnValue}, '%')
</when>
<!-- 不包含 -->
<when test="condition.value == 'notLike'">
AND ${columnName} NOT LIKE CONCAT('%', #{columnValue}, '%')
</when>
<!-- 开头是 -->
<when test="condition.value == 'left'">
AND ${columnName} LIKE CONCAT(#{columnValue}, '%')
</when>
<!-- 结尾是 -->
<when test="condition.value == 'right'">
AND ${columnName} LIKE CONCAT('%', #{columnValue})
</when>
<!-- 为空 -->
<when test="condition.value == 'isNull'">
AND ${columnName} IS NULL
</when>
<!-- 不为空 -->
<when test="condition.value == 'notNull'">
AND ${columnName} IS NOT NULL
</when>
<!-- 空文本 -->
<when test="condition.value == 'isBlank'">
AND (${columnName} = '' OR ${columnName} IS NULL)
</when>
<!-- 非空文本 -->
<when test="condition.value == 'notBlank'">
AND (${columnName} != '' AND ${columnName} IS NOT NULL)
</when>
<!-- 其他情况 -->
<otherwise>
<!-- 处理未匹配到的情况,通常为空或报错 -->
</otherwise>
</choose>
</foreach>
</if>
组件结构
InputSelect
组件主要由以下部分组成:
- 模板: 包含一个
el-input
和嵌套在其内的el-select
。 - 数据: 定义了下拉选项、禁用类型、当前选择的类型和值。
- 监听器: 监听外部传入的
items
变化,以同步更新组件状态。 - 方法:
updateItem
方法用于处理输入变化,并更新组件状态及通知父组件。
组件相关代码
<template>
<div>
<el-input placeholder="请输入"
v-model="value"
class="input-with-select"
clearable
:disabled="disabledType.includes(type)"
@input="updateItem">
<el-select slot="prepend"
placeholder="请选择"
style="width: 110px"
clearable
v-model="type"
@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>
/**
* *****使用方法*****
*
* 在父组件中添加引用
*
* <input-select name="remark" :items="queryParams.items" @items-updated="onItemsUpdated"/>
*
* 并在methods中添加</br>
*
* onItemsUpdated(items) { this.queryParams.items = items; },
*/
export default {
name: 'InputSelect',
props: {
items: {
type: Array,
default: () => []
},
name: {
type: String,
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'],
type: 'eq',
value: ''
}
},
watch: {
items: {
handler(newItems) {
// 当items发生变化时,更新内部的状态
const foundItem = newItems.find(item => item.name === this.name);
if (foundItem) {
this.type = foundItem.type;
this.value = foundItem.value;
} else {
this.type = 'eq';
this.value = '';
}
},
deep: true
}
},
methods: {
updateItem() {
if (this.disabledType.includes(this.type)) {
this.value = '';
}
// 更新单个项的信息
const item = {name: this.name, value: this.value, type: this.type};
// 移除已存在的相同属性名称的项
const existingItemIndex = this.items.findIndex(i => i.name === this.name);
if (existingItemIndex > -1) {
this.items.splice(existingItemIndex, 1);
}
// 检查是否所有必需的属性都有值
if (item.name && item.type && (item.value || this.disabledType.includes(item.type))) {
// 添加新的项
this.items.push(item);
// 通知父组件更新
this.$emit('items-updated', this.items);
}
}
}
}
</script>
<style scoped>
</style>
使用方法
3.1 引入组件
首先,在父组件中引入并注册 InputSelect
组件。
<template>
<div>
<!-- 引入 InputSelect 组件 -->
<input-select name="remark" :items="queryParams.items" @items-updated="onItemsUpdated"/>
</div>
</template>
<script>
import InputSelect from './InputSelect.vue';
</script>
3.2 配置组件
配置 InputSelect
组件时,需要传递以下属性:
name
: 输入框的名称,用于区分不同的输入选择组件。items
: 一个数组,用于存储组件的状态信息(名称、类型、值)。
同时,需要定义一个方法 onItemsUpdated
来接收更新后的 items
数组。
// 父组件中定义的方法
export default {
components: {
InputSelect
},
data() {
return {
queryParams: {
items: []
}
};
},
methods: {
onItemsUpdated(updatedItems) {
this.queryParams.items = updatedItems;
}
}
};
示例
假设我们需要一个用于搜索备注字段的输入选择组件,我们可以这样使用:
<template>
<div>
<input-select name="remark" :items="queryParams.items" @items-updated="onItemsUpdated"/>
</div>
</template>
<script>
import InputSelect from './InputSelect.vue';
export default {
components: {
InputSelect
},
data() {
return {
queryParams: {
items: []
}
};
},
methods: {
onItemsUpdated(updatedItems) {
this.queryParams.items = updatedItems;
}
}
};
</script>
当用户选择了条件类型(例如“精确匹配”)并输入了一个值后,InputSelect
组件会自动更新 items
数组,并通过 @items-updated
事件通知父组件进行后续处理。
结语
通过上述步骤,我们可以轻松地在 Vue.js 应用中集成 InputSelect
组件,从而提高表单的交互性和功能性。希望这篇分享能帮助到正在寻找类似解决方案的开发者们!