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

需求

帮助不会写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>

总结

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

相关推荐
wordbaby7 分钟前
Flutter Form Builder 完全指南:告别 Controller 地狱
前端·flutter
A***071720 分钟前
React数据可视化应用
前端·react.js·信息可视化
泉城老铁1 小时前
Vue2实现语音报警
前端·vue.js·架构
q***04051 小时前
Vue项目中 安装及使用Sass(scss)
vue.js·sass·scss
临江仙4551 小时前
前端骚操作:用户还在摸鱼,新版本已悄悄上线!一招实现无感知版本更新通知
前端·vue.js
想个什么名好呢1 小时前
解决uniapp的H5项目uni-popup页面滚动穿透bug
前端
用户93816912553601 小时前
Vue3项目--mock数据
前端
前端加油站2 小时前
一种新HTML 页面转换成 PDF 技术方案
前端·javascript·vue.js
w***Q3502 小时前
Vue打包
前端·javascript·vue.js
有事没事实验室2 小时前
router-link的custom模式
前端·javascript·vue.js