前言
这次的后台管理系统项目选型用了Vue
来作为主技术栈;
因为前段时间用过React
来写过项目(用了antd
),感觉棒棒的。
所以这次就排除了Element UI
,而采用了Ant Design Vue
;
在分析整个项目原型后,发现又可以抽离类似之前的React表格搜索组件
效果图
- 2019-04-10 14:50 : 修正了部分的初始化
props
及联动,新增了slot
的传递
- 2019-04-17: 我又增加了一种布局展示,内联模式,顺带修复了一些已知的问题,组件重命名为
AdvancedSearch.vue
-
2019-04-23: 新增
slider
组件的配置 -
2019-04-25:若是传入的数据长度小于最大格式,默认显示为内联模式,否则为卡片模式
-
2019-05-12: 回调支持传入自定义函数(用于返回自己组合的数据格式)
其他特性等,具体可以看下面的思维导图.
具体业务的封装中还要复杂的多,还结合了一些自定义封装组件,展示出来代码篇幅太长。
实现思路
- 用什么来实现组件之间的通讯
昨天写第一版的时候,思维还没绕过来,用props
和自定义事件($on,$emit
)来实现,
实现出来的代码量贼多,因为每细化多一层组件,复杂度就越高。各种互相回调来实现。
仔细翻了下Ant Design Vue
的文档,发下可以类似React
的套路实现
- 怎么来实现
要实现一个结合业务可复用的东东,首先我们必须先梳理我们要实现的功能点。
props
尽量不破坏文档控件暴露的特性,而是折中去实现,拓展。
先画个思维导图梳理下功能点
遇到的问题
jsx
来实现的问题
一开始想用jsx
来实现,发现还是太天真了。各种报错,特别对Vue
指令的支持一团糟
以及函数式组件的写法也是坑挺多,没办法,乖乖的回归template
的写法
vue
官方提供了jsx
的支持,日渐完善;Github:vue/jsx
- 控件挤成一坨的问题
这个可能是antd vue
版本的样式没处理好,我仔细排查了。若没有复写他的样式,完全没法展开。
placeholder
不会自动撑开,数字控件也是很小
修正前:
修正后
- 补全当初写
react
版本一些欠缺考虑的东东(比如返回的查询对象上)
用法
就普通的引入,具体暴露的props
和change
如下
子项会覆盖全局带过来的同名特性,优先级比较高
选项 | 类型 | 解释 |
---|---|---|
responsive | 对象 | 栅栏的布局对象 |
size | 字符串 | 控件规格大小(大部分都有default,small,large ) |
gutter | 数字 | 控件的间距 |
datetimeTotimeStamp | 布尔类型 | 若是为true ,所有时间控件都会转为时间戳返回 |
searchDataSource | 数组对象 | 就是需要渲染控件的数据源,具体看源码的props |
@change | 函数 | 就是查询的回调 |
@callbackFormat | 可选函数 | 传递会改动回调数据,不传递则忽略 |
// SearchDataSource是数据源,具体可以看props的默认值
<table-search :SearchDataSource="SearchDataSource" @change="tableSearchChange" />
<table-search :SearchDataSource="SearchDataSource" @change="tableSearchChange" @callbackFormat="formatFunc">
<a-button type="primary" @click="test">xxxx</a-button>
<template v-slot:extra>
<div>fasdfas</div>
</template>
</table-search>
// 对象默认为true的,null这个特殊对象会给if直接过滤掉
methods: {
tableSearchChange(searchParams) {
if (searchParams) {
// 执行查询
} else {
// 执行了重置,一般默认重新请求整个不带参数的列表
}
console.log('回调接受的表单数据: ', searchParams);
}
}
代码实现
AdvancedSearch.vue
<template>
<div class="advance-search-wrapper">
<a-form :form="form" @submit="handleSubmit">
<template v-if="layoutMode === 'inline'">
<a-card :bordered="bordered">
<a-row :gutter="gutter">
<template v-for="(item, index) in renderDataSource">
<field-render
:SearchGlobalOptions="SearchGlobalOptions"
:itemOptions="item"
:key="item.fieldName"
v-show="index < SearchGlobalOptions.maxItem || (index >= SearchGlobalOptions.maxItem && collapsed)"
/>
</template>
<a-col :style="{
width: collapsed ? '100%' : 'auto' }">
<a-tooltip placement="bottom">
<template slot="title">
<span>执行查询</span>
</template>
<a-button type="primary" :size="SearchGlobalOptions.size" @click="handleSubmit" icon="search">
查询
</a-button>
</a-tooltip>
<a-tooltip placement="bottom">
<template slot="title">
<span>清空所有控件的值</span>
</template>
<a-button
:size="SearchGlobalOptions.size"
style="margin-left: 8px"
@click="resetSearchForm"
icon="border"
>
重置
</a-button>
</a-tooltip>
<template v-if="showCollapsedText">
<a @click="togglecollapsed" style="margin-left: 8px">
<a-tooltip placement="bottom">
<template slot="title">
<span>{
{ collapsed ? '点击收起部分控件' : '点击展开所有控件' }}</span>
</template>
{
{ collapsed ? '收起' : '展开' }}
<a-icon :type="collapsed ? 'up' : 'down'" />
</a-tooltip>
</a>
</template>
<slot name="extra" />
</a-col>
</a-row>
</a-card>
</template>
<template v-else>
<a-card :bordered="bordered">
<template v-slot:title>
<span style