Vue 2.x折腾记 - (16) 基于Ant Design Vue 封装一个配置式的表单搜索组件

前言

这次的后台管理系统项目选型用了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版本一些欠缺考虑的东东(比如返回的查询对象上)

用法

就普通的引入,具体暴露的propschange如下

子项会覆盖全局带过来的同名特性,优先级比较高

选项 类型 解释
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
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

crper

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值