效果
使用方法
html
<app-search-bar #searchBar [searchInfo]="searchList" (returnFilter)="getFilters($event)"></app-search-bar>
ts
// 初始化数据模型
searchList: Array<SearchBarInfo>;
// constructor内赋值,optionList可以从接口获取之后重新在赋值(防止下拉框没数据)
this.searchList = [
{
type: 'select',
placeHolder: '请选择',
ngModalValue: 'enabled',
labelName: '商品状态',
defaultValue: 1,
optionList: [
{ label: '全部商品', value: '' },
{ label: '已停用商品', value: 0 },
{ label: '已启用商品', value: 1 },
]
},
{
type: 'select',
placeHolder: '请选择',
ngModalValue: 'categoryCode',
labelName: '商品分类',
optionList: this.categoryList,
optionLabel: 'name',
optionValue: 'code'
},
{
type: 'input',
placeHolder: '商品名称/拼音简称/编号',
ngModalValue: 'keyword',
labelName: '',
},
{
type: 'checkbox',
ngModalValue: 'isSeasonalDishes',
labelName: '时价菜',
},
]
/* filter为返回选择值的数据,可以直接赋值给当前的搜索对象,也可以单独赋值 */
getFilters(filters) {
this.filters = JSON.parse(JSON.stringify(filters));
this.getDataList();
}
组件代码
search-bar.component.html
<div class="search-bar">
<ng-container *ngFor="let item of searchInfo;let i = index">
<div class="operate-item" *ngIf="item.type === 'input' && !item.hide">
<span *ngIf="item.labelName">{{item.labelName}}:</span>
<input type="text" nz-input [placeholder]="item.placeHolder || '请输入'" [disabled]="item.disabled"
[(ngModel)]="item[item.ngModalValue]" />
</div>
<div class="operate-item" *ngIf="item.type === 'select' && !item.hide">
<span *ngIf="item.labelName">{{item.labelName}}:</span>
<nz-select nzShowSearch nzAllowClear [nzPlaceHolder]="item.placeHolder || '请选择'"
[nzDisabled]="item.disabled" [(ngModel)]="item[item.ngModalValue]">
<nz-option [nzLabel]="options[item.optionLabel] || options.label"
[nzValue]="options[item.optionValue] || options.value" *ngFor="let options of item.optionList">
</nz-option>
</nz-select>
</div>
<div class="operate-item" *ngIf="item.type === 'dateRange' && !item.hide">
<span *ngIf="item.labelName">{{item.labelName}}:</span>
<app-range-date-time [hiddenBtn]="true" [initialValue]="false" [(startDate)]="item[item.beginTime]"
[(endDate)]="item[item.endTime]">
</app-range-date-time>
</div>
<div class="operate-item" *ngIf="item.type === 'datePicker' && !item.hide">
<span *ngIf="item.labelName">{{item.labelName}}:</span>
<nz-date-picker [(ngModel)]="item[item.ngModalValue]" (ngModelChange)="onChange($event)"></nz-date-picker>
</div>
<div class="operate-item cant-selected" *ngIf="item.type === 'checkbox' && !item.hide">
<label nz-checkbox [(ngModel)]="item[item.ngModalValue]" [nzDisabled]="item.disabled">
{{item.labelName}}
</label>
</div>
</ng-container>
<div class="btn-groups">
<button (click)="searchByFilter()" nz-button nzType="primary">
<i class="iconfont fxsousuo"></i>
搜索</button>
<button (click)="resetFilters()" nz-button>
<i class="iconfont fxreset"></i>
清空
</button>
</div>
</div>
search-bar.component.less
.search-bar {
box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.2);
display: flex;
flex-wrap: wrap;
align-items: center;
border-radius: 2px;
padding: 10px 0 0 0;
.operate-item {
margin: 0 10px;
display: flex;
margin-bottom: 10px;
.ant-input,
.ant-picker {
200px;
height: 34px;
}
nz-select {
200px;
height: 34px;
}
span {
min- 80px;
padding: 7px 0;
white-space: nowrap;
text-align: right;
margin-left: auto;
font-size: 12px;
margin-right: 10px;
}
}
.cant-selected {
user-select: none;
}
.btn-groups {
flex: 1;
text-align: right;
min- 150px;
margin-bottom: 10px;
.ant-btn {
margin-right: 15px;
}
}
}
search-bar.component.ts
import { Component, ComponentRef, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { SearchBarInfo } from '@app/core/models/common-model';
@Component({
selector: 'app-search-bar',
templateUrl: './search-bar.component.html',
styleUrls: ['./search-bar.component.less']
})
export class SearchBarComponent implements OnInit {
@Input() notRefreshAfterReset: boolean; // 重置之后是否刷新 传ture过来则不刷新
@Input() searchInfo: Array<SearchBarInfo>; // 传过来的搜索项
@Output() returnFilter = new EventEmitter<any>(); // 返回搜索对象 filters
filters: {};
defaultBeginTime: Date;
defaultEndTime: Date;
constructor() {
this.filters = {};
this.defaultBeginTime = null;
this.defaultEndTime = null;
}
onChange(e) {
console.log(e);
}
searchByFilter() {
const tempFilters = {};
this.searchInfo.map(item => {
if (item.type !== 'dateRange') {
if (item[item.ngModalValue] !== undefined && item[item.ngModalValue] !== null) {
tempFilters[item.ngModalValue] = item[item.ngModalValue];
}
} else {
if (!item.beginTime) {
console.warn('请设置时间开始默认值');
return;
}
if (item[item.beginTime] !== undefined && item[item.beginTime] !== null) {
tempFilters[item.beginTime] = item[item.beginTime];
}
if (!item.endTime) {
console.warn('请设置时间结束默认值');
return;
}
if (item[item.endTime] !== undefined && item[item.endTime] !== null) {
tempFilters[item.endTime] = item[item.endTime];
}
}
});
this.returnFilter.emit(tempFilters);
}
resetFilters() {
this.searchInfo.map(item => {
// TODO: clearable 基本是undefined,但是传进来的值不可预估(尽管有类型限制,但是万一有傻逼),
// 所以只要clearable传了fasle进来,则认为是不可清除,其他均可清除
if (item.clearable !== false) {
item[item.ngModalValue] = undefined;
}
});
if (!this.notRefreshAfterReset) {
this.returnFilter.emit({});
}
}
ngOnInit() {
this.searchInfo.map((item, index) => {
// 设置搜索栏的默认值
if (item.defaultValue !== undefined && item.defaultValue !== null) {
item[item.ngModalValue] = item.defaultValue;
}
});
}
}
Interface
export interface SearchBarInfo {
hide?: boolean; // 搜索条件显示隐藏
type: string; // 搜索框类型(input/select/...)
ngModalValue?: string; // 输入框对应的ngmodal值
labelName?: string; // 搜索框label,不填则不展示
placeHolder?: string; // placeHolder
defaultValue?: string | number | boolean; // 输入框默认值
optionList?: Array<any>; // Array<{ label: string; value: string | number | boolean }>
optionLabel?: string; // 不写则默认为 label
optionValue?: string; // 不写则默认为 value
beginTime?: string; // type为dateRange 时间范围时的控件对应的初始值
endTime?: string; // type为dateRange 时间范围时的控件对应的结束值
disabled?: boolean; // 是否设为不可选中状态
clearable?: boolean; // 是否可清除 默认可清楚,传入false则不可清除
}
app-range-date-time 是自己根据业务进一步封装的时间选择控件,可以直接删除这个一项