暗黑模式
使用 Vue3+element Plus 简单模仿了禅道系统的高级搜索组件,说简单也有点复杂,还没有完全开发完,但是大体架子有了,剩下一些功能点继续coding。边开发边记录吧,因为这个相比之前的内容确实复杂一些,也更接地气。
大概的功能如下图
主要思路
这是一个相对复杂的组件,所以拆分成了多个文件,主要有3个:
- 主要区域,用于显示和设置搜索条件
- 右侧,保存的搜索方案,可以切换搜索方案(主区域的条件跟着变化)
- 保存搜索方案的弹窗
备选搜索项是一个数组,包含所有可选的条件,可以来自于接口,也可以前端自行定义,此处我在前端定义了几个数据用于DEMO演示
备选搜索项和默认搜索方案经过处理,获得一个初始展示的条件列表,如果列表有数据,那么就会展示默认设置的条件,表单内容显示为空。
当用户设置完搜索条件后,可以点击搜索,也可以保存到自定义的查询方案。查询方案保存在localstorage中
文件结构如下图
代码比较多,下面贴出来比较重要的部分。
主要搜索条件区域
搜索条件表单,默认是6个,数据通过备选搜索项和默认查询方案得来。
如果没有需要默认展示的条件,6个搜索条件都是空的,
// 备选参与搜素的项目
let listColumns = reactive<SearchColumnItem[]>([])
listColumns = demoList
// 初始渲染的搜索条件, 还未加入查询方案的影响
let defaultColumns = reactive<SearchColumnItem[]>(listColumns.filter((cur) => cur.default))
<ul>
<li
v-for="(i, index) in maxCount"
:key="i"
:class="index < showCount ? 'flex' : 'hidden'"
>
<SearchItem
:columns="listColumns"
:defaultColumn="defaultColumns[index]"
:index="index"
:ref="(el:any) => setRef(el, index)"
/>
</li>
</ul>
单个搜索条件继续拆分成子组件 SearchItem.vue
<template>
<el-select v-if="index > 0" v-model="formData.andOr" class="mr-1 w-[80px] flex-shrink-0">
<el-option v-for="ao in andOrOptions" :key="ao.value" :label="ao.label" :value="ao.value" />
</el-select>
<el-select class="mr-1 w-[150px] flex-shrink-0" v-model="formData.code" @change="changeCode">
<el-option v-for="c in columns" :key="c.code" :label="c.label" :value="c.code" />
</el-select>
<el-select
class="mr-1 w-[100px] flex-shrink-0"
v-model="formData.condition"
@change="changeCondition"
><el-option v-for="c in conditionOptions" :key="c.value" :label="c.label" :value="c.value"
/></el-select>
<component
:disabled="disabled"
class="flex-1"
:is="ctOptions[formData.type as keyof typeof ctOptions]"
v-model:value="formData.value"
></component>
</template>
其中component对应的是formComponents下的文件,在父组件中根据搜索项的配置,用component使用对应输入组件。
这些是用户输入的组件,之所以分成多个组件,一是简单清晰,而是方便扩展自定义组件。目前只放了几个基础的element plus的组件。
渲染搜索条件使用的数据格式如下,可以根据需要自行修改增加
export default [
{
label: '用户名',
code: 'name',
type: 'input',
condition: 'equal',
default: true
},
...
]
export const andOrOptions = [
{
value: 'and',
label: '并且'
},
{
value: 'or',
label: '或者'
}
]
export const conditionOptions = [
{
value: 'equal',
label: '等于'
},
{
value: 'notEqual',
label: '不等于'
},
...
]
多个同名ref的处理
点击搜索时,会获取6个子组件的数据,组合成searchParams,Vue2中我们可以使用多个同名ref,然后使用this.$refs来遍历数据,Vue3在循环生成ref时和Vue2有一些不同,稍稍麻烦一点。
不过这里我又小小卡住了一会———开始setRef方法保存的是对象,结果每次点击搜索按钮,itemRefs数组的length就翻一倍,无解,最后该用现在的写法使用数组保存,保证ref不会超出预期数量。
<SearchItem
:columns="listColumns"
:defaultColumn="defaultColumns[index]"
:index="index"
:ref="(el:any) => setRef(el, index)"
/>
...
let itemRefs: Array<any> = []
function setRef(el: HTMLElement | ComponentPublicInstance, index: number) {
itemRefs[index] = el
}
// 搜索时遍历获取子组件数据
function search() {
searchParams.params = []
itemRefs.forEach((element) => {
if (element?.formData?.code) {
searchParams.params.push(element.formData)
}
})
}
只要捋清了各个功能点,合适拆分子组件,复杂的组件也可以变简单!
有了你的赞👍,我会更努力😄
本项目GIT地址:github.com/lucidity99/…