平时工做中,想必你必定会遇到无数次列表需求,而且是带有搜索功能的列表需求,但无论怎么怎么样,请相信这一切都是万变不离其宗。css
不信?请看:html
基本就是上面这些了吧?咱们不妨看看下面这张截图: vue
上面的截图也算是简单的了,只有一个两种类型,一个是输入框,一个是下拉框,但也足以说明问题了,回想一下,当你遇到这样的需求你会如何实现?通常地咱们是否是会像下面这样写书:数组
<div class="container">
<a-row>
<a-col :span="20">
<a-form class="search-form" layout="inline" @submit="search">
<a-form-item label="维修项目">
<a-input placeholder="请输入" />
</a-form-item>
<a-form-item label="维修师傅">
<a-select placeholder="请选择">
<a-select-option
:value="item.id"
:key="item.id"
v-for="item of userOptions"
>{{item.name}}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="楼号">
<a-select placeholder="请选择">
<a-select-option
:value="item.id"
:key="item.id"
v-for="item of floorOptions"
>{{item.name}}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="宿舍">
<a-select placeholder="请选择">
<a-select-option
:value="item.id"
:key="item.id"
v-for="item of roomOptions"
>{{item.name}}</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="button">
<a-button class="offset-right-12" type="primary" html-type="submit">搜索</a-button>
<a-button @click="reset">重置</a-button>
</a-form-item>
</a-form>
</a-col>
<a-col :span="4" class="text-right">
<a-button type="primary" @click="showModal()">新增</a-button>
</a-col>
</a-row>
<a-table
class="offset-top-12"
rowKey="id"
:pagination="pagination"
:loading="loading"
bordered
:columns="columns"
:dataSource="dataList"
>
<span slot="visitDate" slot-scope="scope">{{scope.visitDate | date}}</span>
<span slot="leaveDate" slot-scope="scope">{{scope.leaveDate | date}}</span>
<span slot="createDate" slot-scope="scope">{{scope.createDate | date}}</span>
<div slot="action" slot-scope="scope" class="text-right no-wrap">
<a-button type="link" @click="showModal(scope)">修改</a-button>
<a-divider type="vertical" />
<a-button type="link" @click="deleteModal(scope.id)">删除</a-button>
</div>
</a-table>
</div>
</template>
复制代码
示例基于 antd vueantd
若是过滤条件更多(常有的事),那么页面中的代码量更加惊人,整个页面弥漫着反客为主的味道,仅仅是过滤条件就已经占了整个页面的一半。ide
这会致使什么问题?函数
若是以为页面代码时过多,不会对你在开发以及维护上产生过多的负面影响,但至少有一个理由我以为你应该选择去把这些过滤条件进行封装,那就是若是不去对列表页过滤条件进行封装,若遇到统一修改这些过滤条件(不论是业务性的,仍是样式及结构的)你就会变得很被动,瞬间从高大尚的脑力活变成了出力不讨好的苦力活。那么如何去封装呢?this
key
,分别为:id
,name
)组件有至少有两个参数以及两个事件。其中一个参数是用于遍历出过滤条件的一个数组,另外一个是保存了全部查询参数的一个对象。spa
为何分红两个参数,而不一个参数搞定。缘由以下:双向绑定
两个事件分别是 search
和 rest
,这两个应该不用多说了。下面咱们就先来看看封装好的条件过滤组件。
<template>
<a-row>
<a-col :span="20">
<a-form class="search-form" :form="form" layout="inline" @submit="search">
<a-form-item :label="item.name" v-for="(item, index) of items" :key="index">
<a-input v-model="searchParams[item.key]" v-if="!item.type || item.type === 'input'" :placeholder="item.placeholder || '请输入'"/>
<a-select allowClear v-model="searchParams[item.key]" v-else-if="item.type === 'select'" :placeholder="item.placeholder || '请选择'">
<a-select-option
:key="index"
v-for="(option, index) of item.options"
:value="option[item.optionValuekey || 'id']"
>{{option[item.optionNamekey || 'name']}}</a-select-option>
</a-select>
</a-form-item>
<a-form-item class="button">
<a-button type="primary" html-type="submit">搜索</a-button>
<a-button @click="reset">重置</a-button>
</a-form-item>
</a-form>
</a-col>
<a-col :span="4" class="text-right">
<slot name="right-content"></slot>
</a-col>
</a-row>
</template>
<script>
import deepClone from "@/utils/deepClone";
/**
* items 为过滤条件,能够在对应的项中自定义下拉选项的名称(optionNamekey)和值(optionValuekey)的键,默认分别取 name 和 id
* items 如何要下拉框显示 placeholder,对应的下拉框的初始值能够设置为 undefined 或者 不定义查询参数,若是设置为空, placeholder 不会显示。
* searchParams 为接口查询参数对象
*/
export default {
model: {
prop: 'searchParams',
event: "change"
},
props: {
searchParams: {
type: Object,
default: () => {
return {};
}
},
items: {
type: Array,
default: () => {
return [];
}
}
},
data() {
return {
// 保存初始化时的项
initSearchParams:{},
form: this.$form.createForm(this, { name: "dynamic_search" })
};
},
created() {
this.init()
},
methods: {
init(){
// 保存初始值的
this.initSearchParams = deepClone(this.searchParams)
},
search() {
const cpValue = deepClone(this.searchParams)
this.$emit("change", cpValue);
this.$emit("search", cpValue);
},
reset() {
const cpValue = deepClone(this.initSearchParams)
this.$emit("change", cpValue);
this.$emit("reset", cpValue);
}
}
};
</script>
<style lang="scss" scoped>
.search-form {
@extend .offset-bottom-24;
.ant-form-item {
&.button {
margin-right: 0;
white-space: nowrap;
}
.ant-input {
width: 120px;
}
.ant-select {
min-width: 120px;
}
.ant-btn + .ant-btn {
@extend .offset-left-12;
}
}
}
</style>
复制代码
上面的这个组件只是包涵了两各状况(输入框,下拉框),其它的话能够本身按需添加。deepClone()
方法为深度拷贝。为会把须要深度拷贝?缘由以下:
searchParams
数据。组件接收两个 prop
属性
items
是用以保存用于渲染过滤条件的一个数据。searchParams
初始化及收集请求接口参数,这个参数实现了双向绑定,配合 v-model
使用。用法就很简单了,引入,调用,传参:
<template>
<div class="container">
<search-form :items="searchForm" v-model="searchParams" @search="findRepair">
<a-button slot="right-content" type="primary" @click="showModal()">新增</a-button>
</search-form>
<a-table
rowKey="id"
:pagination="pagination"
:loading="loading"
bordered
:columns="columns"
:dataSource="dataList"
>
<template slot="createDate" slot-scope="createDate">{{createDate | date }}</template>
<a-tag :color="scheduleMap[scope.schedule].color" slot="schedule" slot-scope="scope">{{ scheduleMap[scope.schedule].name }}</a-tag>
<div slot="action" slot-scope="scope" class="text-right no-wrap">
<a-button type="link" @click="showModal(scope)">修改</a-button>
<a-divider type="vertical" />
<a-button type="link" @click="deleteModal(scope.id)">删除</a-button>
</div>
</a-table>
<EditModal ref="EditModal"></EditModal>
</div>
</template>
复制代码
而后在 data 中定义两个 searchForm 和 searchParams
data() {
return {
searchForm: [
{ name: "发起人", key: "name" },
{ name: "维修师傅", key: "repairerId", type: "select", options: [] },
{ name: "楼号", key: "floorId", type: "select", options: [] },
{ name: "宿舍", key: "roomId", type: "select", options: [] }
],
searchParams: {
pageNo: 1,
pageSize: 15,
name: "",
repairerId: undefined,
floorId: undefined,
roomId: undefined
}
};
},
复制代码
searchParams
对象中有三个字段的值设置为 undefined
,这三个属性是用于收集下拉框的选中值,因此不能够给空字符串,而若是你不想这么写,你也可能直接写成:
searchParams: {
pageNo: 1,
pageSize: 15,
name: ""
}
复制代码
两种方式均可能,不过第一种方式相对来讲会比较好一些,就是一看就知道这接口的请求参数都有哪些,有时写代码真的不能过于含蓄,要直白一点,毕竟公司里都是团队模式开发,要让改你代码的年轻小伙也能享受到如鱼得水感受,而且可让相似:“前人种树,后人乘凉” 这样的佳句一直传承下去,而不是让后来者接连 ***,何乐而不为呢。