1、效果
2、开发过程
1、高级查询是有几个基础模块组成
input、select、时间、IP输入框等等
首先简单封装下这些基础组件,然后根据类型来进行绘制不同的查询项。
- 2、基础组件提供输入后或者选中后的查询值,给高级查询。并留一个focus处理方法
import { Component, ElementRef, Input, ViewChild, Output, EventEmitter } from '@angular/core'; import { Key as KeyBoard} from 'ts-keycode-enum'; import { AdvancedSearchValueService } from './advanced.searchValue.service'; import { AdvancedUtils } from './advanced.utils'; @Component({ selector: 'app-input-search', template: ` <nz-input-group [nzSuffix]="suffixIconSearch" [ngStyle]="width" [nzAddOnBefore]="nzAddOnBefore" nzSearch class="app-input-search" [ngClass]="{'app-input-search-nzSuffix' : nzAddOnBefore}" [nzAddOnAfter]="nzAddOnAfter"> <input class="app-input-search-input" #input (blur)="onblur($event)" (keydown)="onkeydown($event)" [(ngModel)]="searchValue" type="text" nzAllowClear nz-input [placeholder]="placeholder"/> </nz-input-group> <ng-template #suffixIconSearch> <span [ngClass]="{'span-margin' : nzAddOnBefore}"> <div class="app-input-search-input-div" *ngIf="_searchValue"> <i (mousedown)="onmousedown($event)" (click)="clear()" theme="fill" nz-icon type="close-circle" class="app-input-search-input-i app-input-search-input-del"> </i> </div> <button (mousedown)="onmousedown($event)" (click)="_search()" nz-button nzType="primary"> <i nz-icon type="search"></i> </button> </span> </ng-template> `, styleUrls: ['./advanced.searchbox.component.less'], }) export class InputSearchComponent { static readonly KEY = 'app-input-search'; constructor( private el: ElementRef, private searchValueService: AdvancedSearchValueService ) { } /** * 查询数据控制 */ _searchValue: any; get searchValue() { return this._searchValue; } @Input() set searchValue(val) { this._searchValue = val; } _width = 200; get width() { const width: any = this._width; return {'width': width + 'px'}; } @Input() set width(_width){ this._width = Number(_width); }; @Input() searchKey: string; // 查询字段的key 有这个字段会拼成一个对象返回 @Input() nzAddOnBefore: any; @Input() nzAddOnAfter: any; @Input() placeholder: string = '请输入查询内容'; /** * search动作 * @type {EventEmitter<number>} */ @Output('search') // 对外提供接口 获取查询的值 search: EventEmitter<number> = new EventEmitter<number>(); @ViewChild('input') input; /** * 设置光标位置 */ focus() { this.input.nativeElement.focus(); } /** * 获取查询项 * @returns {any} */ getValue() { return this._searchValue; } /** * 清理动作 */ clear() { this.searchValue = null; this.focus(); this._search(); } /** * 鼠标失去焦点事件 * @param event */ onblur(event) { this._search(); } /** * 鼠标点击事件 * @param event */ onmousedown(event) { event.preventDefault(); } /** * 查询动作 */ _search() { let searchValue: any = AdvancedUtils.getSearchValue(this.searchValue, this.searchKey); this.searchValueService.sendSearchValue(searchValue, this.searchKey); this.search.emit(searchValue); } /** * 键盘事件监听 * @param ev */ onkeydown(ev) { if (ev.which === KeyBoard.Enter) { this._search(); } } }
- 3、高级查询组件拿到查询后的值,通知表格刷新
import { Component, OnInit, OnChanges, SimpleChanges, ViewChild, ElementRef, OnDestroy, Input, Output, EventEmitter, HostListener, ViewChildren, QueryList, AfterViewInit, } from '@angular/core'; import { AppUtil } from '@core/util/util.service'; import { TimeSearchComponent } from './time.search.component'; import { InputSearchComponent } from './input.search.component'; import { SelectSearchComponent } from './select.search.component'; import { IpInputWidgetComponent } from '../input/ipInput.widget'; import { Subscription } from 'rxjs'; import { AdvancedSearchValueService } from './advanced.searchValue.service'; @Component({ selector: 'app-advanced-searchbox', templateUrl: './advanced.searchbox.component.html', styleUrls: ['./advanced.searchbox.component.less'], }) export class AdvancedSearchboxComponent implements OnInit, OnDestroy, AfterViewInit { static readonly KEY = 'app-advanced-searchbox'; private _subscription: Subscription; constructor( private util: AppUtil, private searchValueService: AdvancedSearchValueService ) { this._subscription = searchValueService.Status$.subscribe((searchValue)=> { this._advancedSearch(searchValue); }); } ngOnInit() { // items 有使用get赋值的场景 此时不直接使用 拿到items后 添加uuid 赋值给__advanceditems // 使用__advanceditems来进行增删改 this.__advanceditems = this.setAdvancedItem(this.items); this.__allItems = this.util.cloneAllItems(this.__advanceditems); } ngOnDestroy() { this._subscription.unsubscribe(); } ngAfterViewInit() { setTimeout(() => { this._setAAdvancedValue(); }); } /** * advancedSearch动作 * @type {EventEmitter<number>} */ @Output('advancedSearch') // 动态获取宽度 动态调整 advancedSearch: EventEmitter<number> = new EventEmitter<number>(); /** * 时间查询项 */ @ViewChildren(TimeSearchComponent) timeSearchComponents: QueryList<TimeSearchComponent>; /** * 输入框查询项 */ @ViewChildren(InputSearchComponent) inputSearchComponents: QueryList<InputSearchComponent>; /** * 选择框查询项 */ @ViewChildren(SelectSearchComponent) selectSearchComponents: QueryList<SelectSearchComponent>; /** * IP地址查询项 */ @ViewChildren(IpInputWidgetComponent) IPSearchComponents: QueryList<IpInputWidgetComponent>; /** * 添加过滤对象 */ @ViewChild('dropdown_button') dropdown_button; keydown(e, currentViewModel?, options: {id?: any , blackList?: any} = {}) { } /** * items form表单的样式 */ @Input('itemsStyle') itemsStyle: object; /** * 查询参数 */ @Input('params') set params(_params) { this.advancedSearchValue = _params || {}; }; /** * 缓存下来所有的条件 用于后续增加和修改 */ private __allItems: any[]; @Input('items') items: any[]; public __advanceditems: any[]; // select 和 input 的宽度 public _width = 160; /** * 添加uuid */ private setAdvancedItem(_items) { const items = this.util.cloneAllItems(_items); if (items) { const len = items.length; for (let i = 0; i < len; i++) { const singleItems = items[i]; if (!singleItems.uuid) { singleItems.uuid = this.util.uuid(); } items[i] = singleItems; } } return items; } /** * 数据绘制完后 开始赋值 * @private */ private _setAAdvancedValue() { if (this.__advanceditems && !this.util.isEmptyObject(this.advancedSearchValue)) { const oldItems = this.util.cloneAllItems(this.__advanceditems); const len = oldItems.length; for (let i = 0; i < len; i++) { const keyArr = oldItems[i].searchKey.split(','); const keylen = keyArr.length; const _value = []; for (let j = 0; j < keylen; j++) { if (this.advancedSearchValue[keyArr[j]]) { _value.push(this.advancedSearchValue[keyArr[j]]); } } if (_value.length) { oldItems[i]._value = _value.length > 1 ? _value : _value[0]; this.itemClick(oldItems[i], i, false); } } } } /** * 已经点击过的查询条件 * @type {Array} * @private */ _searchItems: any[] = []; get searchItems() { return this._searchItems; } set searchItems(item) { this._searchItems = item; } /** * 点击查询项触发的事件 * @param item * @param index */ itemClick(item, index, focus = true) { this.searchItems.push(item); const len = this.__advanceditems.length; let k = index; for (let i = 0; i < len; i++) { if (item.uuid === this.__advanceditems[i].uuid) { k = i; break; } } this.__advanceditems.splice(k, 1); // 将光标定位到选中的查询项上 if (focus) { setTimeout(()=> { this.focusSelectSearch(item); }, 100); } // 隐藏高级查询项 this.dropdown_button ? this.dropdown_button.hide() : ''; } /** * 将关闭定位到选择的这个高级查询项上 * @param item */ focusSelectSearch(item) { // 根据type拿到组件对象 const _results = this[item.type+ 'SearchComponents']['_results']; const len = _results.length; for (let i = 0; i < len; i++) { const component = _results[i]; /** * 根据uuid进行匹配 如果匹配上 调用focus进行定位 * 每个组件都要提供一个focus方法进行定位 */ if (item.uuid === component.el.nativeElement.id && this.util.isFunction(component.focus)) { component.focus(); } } } /** * 鼠标点击事件 * @param event */ onmousedown(event) { event.preventDefault(); } /** * 删除当前的某个条件 * @param item * @param index */ itemClear(obj) { const item = obj.items; const index = obj.index; this._searchItems.splice(index, 1); this.__advanceditems.push(item); const searchValue = { key: item.searchKey, value: {} }; this._advancedSearch(searchValue); } /** * 重置查询项 */ resetItems() { this.__advanceditems = this.util.cloneAllItems(this.__allItems); this.searchItems = []; this.advancedSearchValue = {}; this._advancedSearch(); } /** * 高级查询条件处理 * @type {{}} * @private */ private _advancedSearchValue: any = {}; get advancedSearchValue() { return this._advancedSearchValue; } set advancedSearchValue(searchValue) { this._advancedSearchValue = searchValue; } /** * 获取最终的高级查询条件 * @param searchValue * @private */ private _advancedSearch(searchValue: any = null) { /** * 判断是否有有查询条件 没有就将条件删除 */ if (searchValue) { if (this.util.isEmptyObject(searchValue.value)) { const keyArr = searchValue.key.split(','); const len = keyArr.length; /** * 倒循环 提高性能 */ for (let i = len - 1; i >= 0; i--) { delete this.advancedSearchValue[keyArr[i]]; } } this.advancedSearchValue = this.util.apply({},this.advancedSearchValue, searchValue.value); } const advancedSearchValue: any = this.advancedSearchValue; this.advancedSearch.emit(advancedSearchValue); } }
<!--添加过滤条件按钮--> <nz-dropdown [nzTrigger]="'click'" #dropdown_button *ngIf="__advanceditems" class="advanced-searchbox-dropdown" [hidden]="!__advanceditems.length"> <button class="grid-tbar grid-tbar-add" [ngClass]="{'grid-tbar-filter': searchItems.length}" nz-button nzType="primary"nz-dropdown> <i nz-icon type="filter" theme="outline"></i>过滤 </button> <ul nz-menu [hidden]="!__advanceditems.length"> <li nz-menu-item *ngFor="let item of __advanceditems;let j = index"> <a (click)="itemClick(item, j)">{{item.lable}}</a> </li> </ul> </nz-dropdown> <button class="grid-tbar grid-tbar-clear" nzType="primary" (mousedown)="onmousedown($event)" nz-button *ngIf="searchItems.length" (click)="resetItems()" nz-tooltip nzTitle="重置过滤条件"> <i nz-icon type="delete" theme="outline"></i>清空 </button> <!--条件区域--> <form nz-form [nzLayout]="'inline'" [ngClass]="{'advanced-searchbox-form': searchItems.length}" [ngStyle]="itemsStyle"> <nz-form-item *ngFor="let search of searchItems;let i = index"> <nz-form-control> <ng-container [ngSwitch]="search.type"> <!--IP查询项--> <ng-container *ngSwitchCase="'IP'"> <nz-input-group nzCompact> <app-advanced-searchbox-lable (itemClear)="itemClear($event)" [lable]="search.lable" [value]="{items: search, index: i}"> </app-advanced-searchbox-lable> <app-ip-input class="advanced-app-ip-input-border" [border]="true" [searchValue]="search._value" id="{{search.uuid}}" [Prefix]="true" [searchKey]="search.searchKey"> </app-ip-input> </nz-input-group> </ng-container> <!--事件查询项--> <ng-container *ngSwitchCase="'time'"> <nz-input-group nzCompact> <app-advanced-searchbox-lable (itemClear)="itemClear($event)" [lable]="search.lable" [value]="{items: search, index: i}"> </app-advanced-searchbox-lable> <app-time-search [searchValue]="search._value" [searchKey]="search.searchKey" id="{{search.uuid}}"> </app-time-search> </nz-input-group> </ng-container> <!--选择框--> <ng-container *ngSwitchCase="'select'"> <nz-input-group nzCompact> <app-advanced-searchbox-lable (itemClear)="itemClear($event)" [lable]="search.lable" [value]="{items: search, index: i}"> </app-advanced-searchbox-lable> <app-select-search [width]="_width" [url]="search.url" [selectedValue]="search._value" [searchKey]="search.searchKey" [optionList]="search.optionList" [lableKey]="search.lableKey" [valueKey]="search.valueKey" [APN]="search.APN" id="{{search.uuid}}"> </app-select-search> </nz-input-group> </ng-container> <ng-container *ngSwitchDefault> <app-advanced-searchbox-lable (itemClear)="itemClear($event)" [lable]="search.lable" [value]="{items: search, index: i}"> </app-advanced-searchbox-lable> <app-input-search [width]="_width" [searchValue]="search._value" id="{{search.uuid}}" [searchKey]="search.searchKey"> </app-input-search> </ng-container> </ng-container> </nz-form-control> </nz-form-item> </form>
3、应用
在表格中使用
<!--tags区域-->
<nz-row class="grid-tags" *ngIf="tags">
<ng-container *ngIf="!tags; else customizeTage"></ng-container>
</nz-row>
<!--tbar区域-->
<nz-row class="grid-tbar" *ngIf="tbar || advancedItems">
<app-input-search *ngIf="searchCapability" (search)="_search($event)" class="app-grid-input-search">
</app-input-search>
<ng-container *ngIf="!tbar; else customizeTbar"></ng-container>
<app-advanced-searchbox (advancedSearch)="_advancedSearch($event)"
[params]="advancedParams"
[itemsStyle]="{'padding-left': '6px', 'margin-top': '12px'}"
[items]="advancedItems">
</app-advanced-searchbox>
</nz-row>
<!--自定义tags-->
<ng-template #customizeTage>
<ng-template [ngTemplateOutlet]="tags"></ng-template>
</ng-template>
<!--自定义tbar-->
<ng-template #customizeTbar>
<ng-template [ngTemplateOutlet]="tbar"></ng-template>
</ng-template>