带你实现一个且或筛选条件组件(核心版)

需求

帮助不会写sql且或关系逻辑查询的用户,借助前端的且或过滤条件的交互,来实现类似后端的sql语句查询的功能。

前端数据结构分析

整个结构是一个条件数组,如下图是每一个条件的具体内容,即红色部分,分别为:event 、prop、condition、relation(且/或),condition为当前条件的核心,是这个过滤条件的细化,condition为一个条件数组,子数组的数据格式可以为A,也可以为B,也可以为任意个A和任意B的组合,其中组成B的最小单元又是A。

综上:可以得出如下的数据结构:

typescript 复制代码
export interface IFilterData {
  event: string // 事件
  prop: string //  属性/指标
  relation: string // condition的关系且/或
  condition: (IConditionA | IConditionB)[]
}
export interface IConditionA {
  prop: string //  属性/标签
  operator: string //操作:等于、不等于、包含等
  value: string // 值
}
export interface IConditionB {
  relation: string // condition的关系且/或
  condition?: IConditionA[]
}

组件拆分

1. 组件 1 (base-event-filter.vue)

红色部分为for循环一个过滤条件,蓝色部分为添加按钮,因此我们把红色拆为一个组件。整体HTML结构如下:

xml 复制代码
<div class="base-event-filter">
  <!-- 红色部分 -->
  <ItemFilter :data="filterData" />
  <!-- 蓝色部分 -->
  <span class="add_icon" @click="handleAdd">
    添加指标
  </span>
</div>
typescript 复制代码
<script lang="ts" setup>
  import ItemFilter from './item-filter.vue'
  interface IFilterData {
    event: string // 事件
    prop: string //  属性/指标
    relation: string // condition的关系且/或
    condition: (IConditionA | IConditionB)[]
  }
  type Props = {
    modelValue: IFilterData[]
  }
	const props = defineProps<Props>()
	const emit = defineEmits(['update:modelValue'])

  const filterData = ref(props.modelValue ?? [])
  
  const handleAdd = () => {
    filterData.value.push({ event: '',prop:'', condition: [], relation: '且' })
  }

  watch(filterData, (val) => {
    emit('update:modelValue', val)
  })
</script>

2. 组件拆分------ItemFilter.vue

仍重点讲红色部分,红色部分为我们数据结构的relation以及condition,relation比较好处理,就是一个css样式,点击用于切换条件直接的关系,核心是右侧的结构。

图片交互的数据结构可以描述如下:

csharp 复制代码
{
  event:'',
  prop:'',
  relation:'且',
  condition:[
    // IConditionB
    {
      relation:'或',
  		condition:[
      	{
          prop:'',
          operator:'',
          value:''
        },
  			{
          prop:'',
          operator:'',
          value:''
        }
      ]
    },
		// IConditionA
  	{
       	prop:'',
      	operator:'',
      	value:''
    }
  ]
}

我们把整体的红色部分拆为一个组件,因为这个组件还做了组件嵌套,也就是组件递归,我们把这个组件称为item-filter-child.vue

3. 核心组件------item-filter-child.vue

HTML结构:

xml 复制代码
<div class="item-filter-child">
  <!-- relation -->
  <div v-if="currentData.condition?.length > 1" class="relation">
    <span>且</spa >
      <span>或</span>
  </div>
  <!-- 过滤条件 -->
  <div>
    <div
      v-for="(condition, conditionIndex) in currentData.condition"
      :key="conditionIndex"
      class="child-item"
      >
      <!-- IConditionA -->
      <template v-if="!condition.condition?.length || condition.condition.length === 1">
         <!-- prop、operator、value对应的HTML -->
      </template>
      <!-- IConditionB 递归组件本身 -->
      <ItemFilterChild v-else :data="condition"></ItemFilterChild>
    </div>
  </div>
</div>

总结

到此整个组件就完成了,本文主要讲述组件的实现方法、组件的拆分逻辑,以及递归组件的实现,希望能帮助到你。

相关推荐
小墨宝17 分钟前
js 生成pdf 并上传文件
前端·javascript·pdf
HED32 分钟前
用扣子快速手撸人生中第一个AI智能应用!
前端·人工智能
DN金猿37 分钟前
使用npm install或cnpm install报错解决
前端·npm·node.js
丘山子37 分钟前
一些鲜为人知的 IP 地址怪异写法
前端·后端·tcp/ip
志存高远661 小时前
Kotlin 的 suspend 关键字
前端
www_pp_1 小时前
# 构建词汇表:自然语言处理中的关键步骤
前端·javascript·自然语言处理·easyui
YuShiYue1 小时前
pnpm monoreop 打包时 node_modules 内部包 typescript 不能推导出类型报错
javascript·vue.js·typescript·pnpm
天天扭码2 小时前
总所周知,JavaScript中有很多函数定义方式,如何“因地制宜”?(ˉ﹃ˉ)
前端·javascript·面试
一个专注写代码的程序媛2 小时前
为什么vue的key值,不用index?
前端·javascript·vue.js
vvilkim2 小时前
React 与 Vue:两大前端框架的深度对比
vue.js·react.js·前端框架