前情回顾

基于 el-form 封装一个依赖 json 动态渲染的表单控件

Vue3 封装第三方组件(一)做一个合格的传声筒

功能

使用 vue3 + element-plus 封装了一个查询控件,专为管理后台量身打造,支持各种查询需求:

  • 多种查询方式
  • 快捷查询
  • 更多查询
  • 自定义查询
  • 支持防抖
  • 清空每个查询条件
  • 依赖 json 动态创建

有些控件自带清空功能,有些没有自带清空功能,那么就需求我们手动加上清空的功能。

技术栈

  • Vite2
  • Vue3
  • element-plus

查询控件设计

【自我感觉良好的一个脑图】

在线演示

https://naturefw.gitee.io/nf-vue-cdn/elecontrol/

进入页面后请点击“查询控件”。

可以在“表单控件”里面添加测试数据,数据会存入webSQL。

受限于webSQL,有些查询功能无法实现。

功能演示

查询功能具体是什么样子呢?我们先来看一段视频:

点击查看视频演示

各种查询方式

查询控件针对不同的数据类型(后端数据库字段类型),量身打造了多种查询方式,让查询更便捷!

文本

针对文本类的数据类型(varchar、text等),提供常用的模糊查询(包含)、精确查询(=),还有起始于、结束于等查询方式可供选择。

这样用户可以更灵活方便的进行查询操作。

数字

针对数值类型(int、float、decme等),提供常用的精确查询(=)、范围查询(从xx到xxx)还有大于等于等查询方式。

单选组的查询

针对枚举类型,int 或者 varchar 等有限数量。

单选组有两种情况,一个是常见的查询一种情况即可,选择第一选项那么只需要显示第一个选项对应的数据。

另一个就是想同时看多个选项的结果,那么这时候还用单选组的方式就不适合了,需要变成多选组的方式,这样才可以让用户选择多个选项。

所以这里的单选的查询支持两种查询方式:

  • =: 只能查询一个选项,对应单选。
  • 包含:可以同时查询多个选项,对应多选。

支持清空查询条件,即点击右侧的“x”。

多选支持防抖。

勾选和开关

二者对应的数据类型是 bool 型的(bit),所以只有“=”这一种查询方式,增加了一个“清空”的按钮,这样可以单独清掉查询条件。

级联选择

常见的级联选择是省市区县的选择,组件默认给的model是一个数组形式,有多少级就会有多少个数组。

但是在后端数据库里面,往往会分成多个字段来存放,比如省份用一个字段表示,城市用一个字段表示,区县又是一个字段表示。

那么我们在查询的时候,就需要把查询结果按照字段给拆分开,这样才便于查询。

所以这里把查询结果按照字段拆分开然后在返回给后端,比如这样:

{ "a": [ 401, "zhinan" ], "b": [ 401, "shejiyuanze" ], "c": [ 401, "yizhi" ] }

日期

日期查询比较复杂,这里对应的数据类型是date,选择后返回的数据是“2021-05-20”的形式。

然后就是如何让用户感觉爽的问题了。

  • 常规查询方式

一般都是如上图所示,直接选择日期范围,这个看起来似乎没有啥问题,可以选择任意日期。

但是如果用户想查询2021年1月到2021年3月的数据,那么用户的操作就会比较繁琐。

我们来看看一共要点击几次鼠标?

打开日期栏 》 找到一月份(n次) 》 选择一号 》 找到三月份(又是n次) 》选择31号。

整个流程需要点好多次鼠标,实在是太麻烦了。

  • 通过月份查询日期范围

    如果可以直接选择月份呢?像这样:

如果用户想选择多个月份的日期,可以通过“从” + “年月”的形式,选择起始月份即可,返回的数据是"2021-01-01", "2021-03-31" 的形式。

如果客户想选择一个月的范围,那么可以用“=” + “年月”的方式来选择(如上图),返回的数据是"2021-02-01", "2021-02-28" 的形式。

这样用户就非常方便了,节省了n次鼠标点击。不过这还没有结束,还有选择“年”的情况。

  • 通过年查询日期范围

    如果要查询一年的或者多年的日期范围呢?我们可以选择“年”的方式。

如果选择一整年的话,我们可以使用“=” + “年”的方式(如上图),选择需要的年份即可,返回的数据是 "2021-01-01", "2021-12-31" 的形式。

如果选择连续的多个年份,可以用“从” + “年”的方式(如上图),选择起始年份即可,返回的数据是"2021-01-01", "2022-12-31" 的形式。

年、年月、年周的查询

上面是针对date类型的数据,这里是针对int、varchar类型的数据。

有时候为了加快查询速度,数据库设计上面可能会用增加“冗余字段”的方式来提升性能,比如增加“年”的字段,类型是int,存放“2021”、“2022”这样的数据。

同理,可以增加“年月”的字段,类型是int,存放“202101”、“202103”这类的数据,还有“年周”的情况。

这里的查询方式就是针对这种情况来设计的。

  • 年的查询

要比日期查询简单很多。

  • 年月的查询

  • 年周的查询

这里不是指星期几,而是一年内的第几周,听说有些企业是按照周来安排工作的,所以这里也提供了周的查询。

日期时间的查询

快速查询

显示常用的查询条件。

自定义查询方案

可以把常用的查询字段放在一起,组成一个查询方案,方便用户使用。

更多查询

显示全部查询条件,查询后的字段可以带入快捷查询,便于随时更改查询条件。

文件结构

上面都是介绍功能,下面开始介绍一下实现方式。

首先看一下文件结构:

  • packages

    存放基础的js,和UI库无关的基本逻辑代码,很显然等稳定后会发布到npm上面,以便于支持其他UI库。

    目前有表单子控件、表单控件、查询子控件、查询控件,以后还会有列表控件、按钮控件等。

  • control-web

    web 控件的意思。存放组件的UI部分。至于会不会发布到npm,目前还没有想好,因为有个灵活性的问题。

  • views

    这里就是如何使用的代码了。

实现方式

我们以文本类的查询为例进行介绍,我们先做一个查询方式的组件,然后做一个文本的查询子控件。

查询方式

<template>
<el-dropdown @command="handleCommand">
<span class="el-dropdown-link">
{{kindName}}<i
class=" el-icon--right"
:class="{'el-icon-arrow-down': isUp, 'el-icon-arrow-up': !isUp}"></i>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
v-for="kindId in findKind"
:key="'s_kind_'+ kindId"
:command="kindId"
>
{{findKindList[kindId].name}}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</template>

使用 el-dropdown 做一个选择列表。

import { defineComponent, ref } from 'vue'
import { findKindList } from '/nf-control-web' // 查询方式的 select
export default defineComponent({
name: 'el-find-kind',
props: {
// 返回选择的查询方式
modelValue: [Number],
// 需要显示的查询方式
findKind: {
type: Array,
default: () => { return [411] }
}
},
emits: ['update:modelValue', 'change'],
setup (props, context) {
const kindName = ref(findKindList[props.modelValue].name) const handleCommand = (command) => {
kindName.value = findKindList[command].name
context.emit('update:modelValue', command)
context.emit('change', command)
} return {
isUp,
kindName,
findKindList,
handleCommand
}
}
})

设置属性,接收查询方式,和用户选择的查询方式。

查询子控件

<template>
<!--查询方式-->
<div style="float:left;width:65px;text-align:center;">
<find-kind
v-model="findChoiceKind"
:findKind="findKind"
@change="myChange"
/>
</div>
<!--查询内容-->
<div :style="{width: (150 * colCount - 10 ) + 'px'}" style="float:left;">
<div style="float:left;" :style="{width: (150 * colCount - 40 ) + 'px'}">
<component
:is="ctlList[controlType]"
v-model="findText"
v-bind="$attrs"
:delay="delay"
:colName="colName"
@myChange="myChange">
</component>
</div>
</div>
</template>

放置查询方式和查询用的组件。

import { defineComponent } from 'vue'
// 引入查询子控件的管理类
import { findItemManage } from '/nf-control-web'
// 查询方式的控件
import selectFindKind from './s-findkind.vue' // 异步组件,引入表单子控件
import { formItemToFindItem } from '../nf-el-find-item/map-el-find-item.js' /*
* 查询子控件,文本类
* * 单行文本
* * 多行文本
* * ulr、电话、邮箱等
*/
export default defineComponent({
name: 'el-find-item-text',
inheritAttrs: false,
props: {
controlId: Number, // 控件ID
controlType: Number, // 控件类型
colName: String, // 字段名称
modelValue: [Array, String], // 查询结果,数组形式
colCount: { // 占用空间
type: Number,
default: 1
},
findKind: { // 查询方式
type: Array, // , 407, 408
default: () => { return [403, 401, 402, 404, 405, 406] }
},
delay: { // 防抖
type: Number,
default: 600
}
},
components: {
'find-kind': selectFindKind
},
emits: ['update:modelValue', 'my-change'],
setup (props, context) {
// 表单子控件 to 查询子控件 的 字典
const ctlList = formItemToFindItem const {
findChoiceKind, // 选择的查询方式
findText, // 一个关键字查询
mySubmit
} = findItemManage(props, context) // 设置默认查询方式
findChoiceKind.value = props.findKind[0] // 提交查询结果
const myChange = () => {
// 一个关键字查询
mySubmit(findText.value)
} return {
ctlList, // 控件字典,用于加载具体的控件
findChoiceKind, // 查询方式
findText, // 一个查询关键字
myChange // 触发提交事件
}
}
})

设置需要的属性,比如具体的查询方式、防抖时间间隔等。因为文本查询比较简单,所以只需要简单的提交查询条件即可。

查询控件

<template>
<!--快捷查询-->
<el-card class="box-card">
<el-scrollbar>
<div class="flex-content" style="min-width:400px;">
<el-form
inline
label-position="right"
:model="findItemModel"
ref="formControl"
class="demo-form-expand"
label-width="1px"
size="mini"
>
<el-form-item style="width:100px">
<el-dropdown size="small">
<el-button type="primary">
快捷查询<i class="el-icon-arrow-down el-icon--right"></i>
</el-button>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item
@click="quickClick(0)"
>
快捷查询
</el-dropdown-item>
<el-dropdown-item
v-for="(item, key, index) in customer"
:key="'quick_' + index"
@click="quickClick(key)"
>
{{item.title}}
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</el-form-item>
<el-form-item
v-for="(ctrId, index) in arrQuickFind"
:key="'find_quick_'+index"
style="border:1px solid #cfe1f3;min-height:33px;"
:style="{width: ( 160 * getCtrMeta(ctrId).colCount + 80) + 'px'}"
>
<!--判断要不要加载插槽-->
<template v-if="getCtrMeta(ctrId).controlType === 1">
<slot :name="ctrId">父组件没有设置插槽</slot>
</template>
<!--查询的子控件,采用动态组件的方式-->
<template v-else>
<component
:is="ctlList[getCtrMeta(ctrId).controlType]"
v-model="findItemModel[ctrId]"
v-bind="getCtrMeta(ctrId)"
@myChange="mySubmit">
</component>
</template>
</el-form-item>
<el-form-item style="width:60px">
<el-button type="primary" round @click="moreOpen">更多</el-button>
</el-form-item>
</el-form>
</div>
</el-scrollbar>
</el-card>
<!--更多查询,放在抽屉里面-->
<findmore
:allFind="allFind"
:reload="reload"
:itemMeta="itemMeta"
:findKind="findKind"
:moreFind="moreFind"
v-model:isShow="isShow"
/>
</template>

这里是快捷查询,更多查询做成了单独的组件,这样可以让模板代码简洁一点,不至于太乱。

/**
* @function div 格式的查询控件
* @description 可以依据 json 动态生成查询控件
* @returns {*} Vue 组件,查询控件
*/
export default {
name: 'el-find-div',
components: {
findmore
},
props: {
...findProps
},
setup (props, context) {
// 控件字典
const ctlList = findItemListKey // 依据ID获取组件的meta,因为 model 不支持[]嵌套
const getCtrMeta = (id) => {
return props.itemMeta[id] || {}
} const {
moreFind, // 接收更多查询 更多查询里面子控件的事件
isShow, // 抽屉是否打开
arrQuickFind, // 快捷栏的数组
findItemModel, // 查询子控件的model
moreOpen, // 点击更多,清空快捷
quickClick, // 个性化方案的单击事件
mySubmit // 查询子控件的事件
} = findManage(props, context) return {
isShow, // 抽屉是否打开
moreFind, // 接收更多查询
arrQuickFind, // 快捷栏的数组
ctlList, // 子控件字典
resetForm, // 重置表单
formControl, // 获取表单的dom
getCtrMeta, // 返回子控件的meta
findItemModel, // 查询子控件的model
moreOpen, // 点击更多,清空快捷
quickClick, // 个性化方案的单击事件
mySubmit
}
}
}

代码比较多,这里是 setup 部分,主要负责代码函数的整合。减少代码混乱的程度。

使用方式

<template>
<!--演示查询控件-->
<nf-find
v-model="query"
v-bind="formProps"
/>
查询条件:{{query}}
<!--数据列表 演示查询结果-->
<findGrid :dataList="dataList"/>
<!--可以分页-->
<findPager/> </template>

模板部分比较简单了,设置好属性即可。

import { reactive, watch } from 'vue'
// 组件
import findCom from '../control-web/nf-el-find/el-find-div.vue'
import findGrid from './find-grid.vue'
import findPager from './find-pager.vue'
// 加载json文件
import json from '/json/find-test.json' // 数据列表的状态
import dataListControl from '../control/data-list' export default {
name: 'eleFindComponent',
components: {
findGrid,
findPager,
'nf-find': findCom
},
setup () {
const query = reactive({}) const findTest = json.findTest
// 设置查询控件的属性
const findProps = reactive({})
// 添加重新绑定的开关
findProps.reload = false // 模拟异步加载meta
Object.assign(findProps, findTest.baseProps)
findProps.itemMeta = findTest.itemMeta // 表单子控件的属性
findProps.findKind = findTest.findKind // 查询方式 return {
query,
dataList,
// 渲染表单的meta
findProps
}
}
}

这里主要是加载json文件,然后给查询控件设置属性。

然后获得查询条件,提交给后端API申请数据即可。

json 文件的格式

比较长,发个图片示意一下:

更多代码欢迎查看源码。

源码

https://gitee.com/naturefw/nf-vite2-element

在线演示

https://naturefw.gitee.io/nf-vue-cdn/elecontrol/

基于 element-plus 封装一个依赖 json 动态渲染的查询控件的更多相关文章

  1. 基于 el-form 封装一个依赖 json 动态渲染的表单控件

    nf-form 表单控件的功能 基于 el-form 封装了一个表单控件,包括表单的子控件. 既然要封装,那么就要完善一些,把能想到的功能都要实现出来,不想留遗憾. 毕竟UI库提供的功能都很强大了,不 ...

  2. WPF编程,通过Double Animation同时动态缩放和旋转控件的一种方法。

    原文:WPF编程,通过Double Animation同时动态缩放和旋转控件的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_4330793 ...

  3. 动态绑数据(GridView控件Header和ItemTemplate)

    想了解此篇文章,建议先预习一下<动态变更GridView控件列名>http://www.cnblogs.com/insus/p/3232057.html,因为多少有些关联.不管怎样,它能够 ...

  4. WPF 中动态创建和删除控件

    原文:WPF 中动态创建和删除控件 动态创建控件 1.容器控件.RegisterName("Name",要注册的控件)   //注册控件 2.容器控件.FindName(" ...

  5. 一个Demo让你掌握Android所有控件

    原文:一个Demo让你掌握Android所有控件 本文是转载收藏,侵删,出处:"安卓巴士"      下面给出实现各个组件的源代码: 1.下拉框实现--Spinner packag ...

  6. 封装:WPF中可以绑定的BindPassWord控件

    原文:封装:WPF中可以绑定的BindPassWord控件 一.目的:本身自带的PassWord不支持绑定 二.Xaml部分 <UserControl x:Class="HeBianG ...

  7. QT 创建一个具有复选功能的下拉列表控件

    最近研究了好多东西,前两天突然想做一个具有复选功能的下拉列表框.然后在网上"学习"了很久之后,终于发现了一个可以用的,特地发出来记录一下. 一.第一步肯定是先创建一个PROJECT ...

  8. 动态绑数据(Repeater控件HeaderTemplate和ItemTemplate)

    前几天,Insus.NET有写了<动态绑数据(GridView控件Header和ItemTemplate)>http://www.cnblogs.com/insus/p/3303192.h ...

  9. 基于ionic框架封装一个图片轮播指令的几点

    在这里我想在项目中封装一个图片轮播的指令 (本项目使用的是ionic框架) 1)定义指令 define(['app'],function(myapp){ myapp.directive('myslid ...

随机推荐

  1. JAVAEE_Servlet_21_Cookie

    Cookie * Cookie 是什么? - Cookie翻译过来是曲奇饼干的意思 - Cookie可以保存回话状态,但是这个会话状态是保存在客户端上的,只要清除Cookie,或者 Cookie失效, ...

  2. 拿到蚂蚁金服的offer是一种什么体验?3年Java程序员分享面经

    前言:我是一名三年的Java程序员,之前一直是在外包公司工作的.在这个月五号的时候,通过我的学长做内推,有了去蚂蚁金服面试的机会.我是在12号接到的电话面试的,因为蚂蚁金服需要7天的简历评估的.还有就 ...

  3. 022- Java算数运算符

    算数运算符有哪些: 输入以下代码: public class Operator01 { public static void main(String[]args){ int a = 10; int b ...

  4. 【并发编程】ThreadLocal

    ThreadLocal Thread类中 具有一个ThreadLocal.ThreadLocalMap ,这个变量是由ThreadLocal去维护的,各个线程之间相互隔离

  5. 解决Android加固多进程ptrace反调试的思路整理

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/53613481 一.Android多进程反调试的原理代码 当ptrace附加目标进程 ...

  6. hdu3786 找出直系亲属 水题

    题意:找出直系亲属Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

  7. POJ1324贪吃蛇(状态压缩广搜)

    题意:       给你一个地图,有的地方能走,有的地方不能走,然后给你一条蛇,问你这条蛇的头部走到1,1的位置的最少步数,注意,和贪吃蛇不太一样,就是蛇咬到自己身体的那个地方,具体怎么不一样自己模拟 ...

  8. jQuery数组($.grep,$.each,$.inArray,$.map)处理函数详解

    1.jQuery.grep( array, function(elementOfArray, indexInArray) [, invert ] ) 描述: 查找满足过滤函数的数组元素.原始数组不受影 ...

  9. Linux安装Redis报错`cc:命令未找到`

    缺少gcc和gcc-c++的编译环境,安装即可. 可以联网情况下使用命令 yum install gcc yum install gcc-c++ 然后清理原来的残余文件 make distclean ...

  10. Linux安装与使用FTP服务-vsftpd

    简介 vsftpd 是"very secure FTP daemon"的缩写,安全性是它的一个最大的特点.vsftpd 是一个 UNIX 类操作系统上运行的服务器的名字,它可以运行 ...