自己用了ng-zorro的組件去寫。
<!------------------------------------------------------------------------------------------------------------------>
<nz-radio-group *ngSwitchCase="'dateChoice'" [(ngModel)]="tdItem.value" name="customDate"
(ngModelChange)="customTime($event)">
<label nz-radio nzValue="day">本日</label>
<label nz-radio nzValue="week">本週</label>
<label nz-radio nzValue="month">本月</label>
<label nz-radio nzValue="timeByMySelf">自定義</label>
<ng-container *ngIf="showCustomTime">
<nz-date-picker [nzDisabledDate]="disabledStartDate" nzFormat="yyyy-MM-dd" [(ngModel)]="startValue"
nzPlaceHolder="開始時間" (ngModelChange)="onStartChange($event)">
</nz-date-picker>~
<nz-date-picker [nzDisabledDate]="disabledEndDate" nzFormat="yyyy-MM-dd" [(ngModel)]="endValue"
nzPlaceHolder="結束時間" (ngModelChange)="onEndChange($event)">
</nz-date-picker>
</ng-container>
</nz-radio-group>
<!------------------------------------------------------------------------------------------------------------------->
// -------------------------自定義時間查詢zjy-----------------------------------------------------------------------------------
//是否展示自定義時間框
showCustomTime: boolean = false;
//獲得日期範圍的工具類
utilDate: UtilDate = new UtilDate();
//自定義的日期開始||結束值
startValue: Date | null = null;
endValue: Date | null = null;
customTime($event) {
if ($event == 'timeByMySelf') {
this.showCustomTime = true;
this.searchAll.startPublishDate = '';
this.searchAll.endPublishDate = '';
// this.postsearch.emit(this.searchAll);
} else if ($event == 'day') {
this.getDayDate()
this.showCustomTime = false;
this.startValue = null;
this.endValue = null;
} else if ($event == 'week') {
this.getWeekDate()
this.startValue = null;
this.endValue = null;
this.showCustomTime = false;
} else if ($event == 'month') {
this.getMonthDate()
this.startValue = null;
this.endValue = null;
this.showCustomTime = false;
}
}
//查詢本日的產品列表,通過獲取本日的時間範圍
getDayDate() {
let search: TableSearch = new TableSearch();
search.startPublishDate = this.utilDate.getDayAndWeek('day').begin;
search.endPublishDate = search.startPublishDate;
this.searchAll.startPublishDate = search.startPublishDate;
this.searchAll.endPublishDate = search.endPublishDate;
this.postsearch.emit(search);
console.log('day', search);
}
//查詢本週的產品列表,通過獲取本日的時間範圍
getWeekDate() {
let search: TableSearch = new TableSearch();
search.startPublishDate = this.utilDate.getDayAndWeek('week').begin;
search.endPublishDate = this.utilDate.getDayAndWeek('week').over;
this.searchAll.startPublishDate = search.startPublishDate;
this.searchAll.endPublishDate = search.endPublishDate;
this.postsearch.emit(search);
console.log('week', search);
}
//查詢本月的產品列表,通過獲取本日的時間範圍
getMonthDate() {
let search: TableSearch = new TableSearch();
search.startPublishDate = this.utilDate.getMonth().begin;
search.endPublishDate = this.utilDate.getMonth().over;
this.searchAll.startPublishDate = search.startPublishDate;
this.searchAll.endPublishDate = search.endPublishDate;
this.postsearch.emit(search);
console.log('month', search);
}
disabledStartDate = (startValue: Date): boolean => {
if (!startValue || !this.endValue) {
return false;
}
return startValue.getTime() > this.endValue.getTime();
};
disabledEndDate = (endValue: Date): boolean => {
if (!endValue || !this.startValue) {
return false;
}
return endValue.getTime() <= this.startValue.getTime();
};
onStartChange(date: Date): void {
this.startValue = date;
if (this.endValue == null && date != null) {
this.endValue = null;
this.selfTimeChange()
}
else if (this.startValue == null && this.endValue == null) {
this.searchAll.startPublishDate = '';
this.searchAll.endPublishDate = '';
this.postsearch.emit(this.searchAll);
} else if (this.startValue == null) {
this.searchAll.startPublishDate = '';
// this.endValue = null;
this.postsearch.emit(this.searchAll);
} else if (this.startValue && this.endValue) {
this.selfTimeChange()
}
}
onEndChange(date: Date): void {
this.endValue = date;
if (this.startValue == null && date != null) {
this.startValue = null;
this.selfTimeChange()
}
else if (this.startValue == null && this.endValue == null) {
this.searchAll.startPublishDate = '';
this.searchAll.endPublishDate = '';
this.postsearch.emit(this.searchAll);
} else if (this.endValue == null) {
this.searchAll.endPublishDate = '';
// this.startValue = null
this.postsearch.emit(this.searchAll);
} else if (this.startValue && this.endValue) {
this.selfTimeChange()
}
}
/**
* 查詢自定義時間範圍的產品列表數據
*/
selfTimeChange() {
let search: TableSearch = new TableSearch();
if (this.startValue) {
let arr = (this.startValue.toLocaleDateString() + '').split('/')
search.startPublishDate = arr[0] + '-' + arr[1] + '-' + arr[2];
}
if (this.endValue) {
let arr = (this.endValue.toLocaleDateString() + '').split('/')
search.endPublishDate = arr[0] + '-' + arr[1] + '-' + arr[2];
}
if (this.endValue == null) {
search.endPublishDate = ''
}
if (this.startValue == null) {
search.startPublishDate = ''
}
this.searchAll.startPublishDate = search.startPublishDate;
this.searchAll.endPublishDate = search.endPublishDate;
this.postsearch.emit(search);
console.log('timeByself', search);
}
// -----------------------------------------------------------------------------------------------------------------------------
export class UtilDate {
getCurrentDate() {
let date = new Date();
let year = date.getFullYear(); //獲取年
let month = date.getMonth() + 1; //獲取月
let day = date.getDate(); //獲取日
let weekDay = date.getDay(); // 星期
let timesStamp = date.getTime(); //getTime() 方法可返回距 1970 年 1 月 1 日之間的毫秒數。
return {
year,
month,
day,
weekDay,
//沒用到
timesStamp
}
}
/**
*
* @param date 傳入DayAndWeek(string)和getMonth(object)
* @param separator 可以自定義所匹配的格式 eg:// YYYY-MM-DD 2019-01-10
*/
myformatStr(date, separator?) {
let year;
let month;
let day;
if (typeof date == 'string') {
year = date.split('/')[0];
month = date.split('/')[1];
day = date.split('/')[2];
} else if (typeof date == 'object') {
year = date.year;
month = date.month;
day = date.day;
}
let mStr = month < 10 ? '0' + month : month + '';
let dStr = day < 10 ? '0' + day : day + '';
if (separator) {
return year + separator + mStr + separator + dStr;
}
return year + '-' + mStr + '-' + dStr;
}
getDayAndWeek(type){
let date = new Date();
let pre = 0;
let next = 0;
let startTime = '';
let endTime = '';
let begin;
let over;
switch (type) {
case 'day':
next++;
break;
case 'week':
pre = 1 - date.getDay();
next = 7 - date.getDay() ;
break;
default:
}
startTime = new Date(date.getTime() + 24 * 60 * 60 * 1000 * pre).toLocaleDateString();
endTime = new Date(date.getTime() + 24 * 60 * 60 * 1000 * next).toLocaleDateString();
begin = this.myformatStr(startTime);
over = this.myformatStr(endTime);
return { begin, over };
}
/**
* 獲取本月日期範圍
*/
getMonth() {
let date = this.getCurrentDate();
let monthStart = {};
let monthEnd = {};
let begin;
let over;
if (date.month == 12) {
monthEnd = { year: date.year + 1, month: date.month + 1, day: 1 };
} else {
monthEnd = { year: date.year, month: date.month + 1, day: 1 };
}
monthStart = { year: date.year, month: date.month, day: 1 };
begin = this.myformatStr(monthStart)
over = this.myformatStr(monthEnd)
return { begin, over }
}
getTimeByMyself(time, id: number) {
let date = this.getCurrentDate();
let selfTimeStart = {};
let selfTimeEnd = {};
let begin;
let over;
let endDay;
let condition;
let cond;
date.year = time.split('/')[0];
date.month = time.split('/')[1];
date.day = time.split('/')[2];
if (id == 2) {
endDay = Number(date.day) + 1
}
selfTimeStart = { year: date.year, month: date.month, day: date.day };
selfTimeEnd = { year: date.year, month: date.month, day: endDay};
condition = { year: date.year, month: date.month, day: endDay - 1};
begin = this.myformatStr(selfTimeStart)
over = this.myformatStr(selfTimeEnd)
cond = this.myformatStr(condition)
return { begin, over,cond }
}
}
橋豆麻袋。。。。這個插件還不對勁,根據要求是要再次點擊radio就要清空查詢條件的。
So不用能ng-zorro的組件了。大佬寫了自定義的組件。(組件是大佬寫的=。。=)
自定義插件如下:
<span class="sl-radio">
<input #inputElement type="radio" class="sl-radio-input" [attr.name]="name" [value]>
<i class="sl-radio-inner app-icon" [class.radio-blank]="!isSelected" [class.radio-selected]="isSelected"
[class.radio-selected-disabled]="isDisabled&&isSelected" [class.radio-disabled]="isDisabled&&!isSelected"></i>
</span>
<span class="sl-radio-content">
<ng-content></ng-content>
</span>
ts
import { Component, OnInit, ElementRef, Renderer2, Input, ViewChild, HostListener, Output, EventEmitter, ChangeDetectorRef, forwardRef } from '@angular/core';
import { Subject } from 'rxjs';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
@Component({
selector: '[sl-radio]',
templateUrl: './radio-tpl.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RadioTplComponent),
multi: true
}
],
})
export class RadioTplComponent implements OnInit, ControlValueAccessor {
name: string;
isMultiple: boolean; // 是否支持多選
@Input() isCanCancel: boolean;
@Input() isSelected: boolean;
@Input() isDisabled: boolean;
@Input() slValue: any;
onChange: (_: boolean) => void = () => null;
onTouched: () => void = () => null;
@ViewChild('inputElement', { static: false }) inputElement: ElementRef;
select$ = new Subject<RadioTplComponent>();
touched$ = new Subject<void>();
constructor(
private cdr: ChangeDetectorRef,
private elementRef: ElementRef,
private renderer: Renderer2,
) {
this.renderer.addClass(elementRef.nativeElement, 'sl-radio-wrapper');
}
ngOnInit() {
}
@HostListener('click', ['$event'])
onClick(event: MouseEvent): void {
event.stopPropagation();
event.preventDefault();
if (!this.isDisabled && !this.isSelected) {
this.select$.next(this);
this.isSelected = true;
this.onChange(true);
} else if (!this.isDisabled && this.isSelected && this.isCanCancel) {
this.select$.next(this);
this.isSelected = false;
this.onChange(false);
}
}
markForCheck(): void {
this.cdr.markForCheck();
}
writeValue(value: any): void {
this.isSelected = value;
this.cdr.markForCheck();
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.isDisabled = isDisabled;
this.cdr.markForCheck();
}
}
通過 ElementRef 我們就可以封裝不同平臺下視圖層中的 native 元素 (在瀏覽器環境中,native 元素通常是指 DOM 元素),最後藉助於 Angular 提供的強大的依賴注入特性,我們就可以輕鬆地訪問到 native 元素。
import { Component, OnInit, Renderer2, ElementRef, ChangeDetectorRef, ContentChildren, QueryList, forwardRef, Input, AfterContentInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
import { RadioTplComponent } from './radio-tpl.component';
import { isNotNil, isString } from '../../utils/convert';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { startWith, takeUntil } from 'rxjs/operators';
import { Subject, Subscription, merge } from 'rxjs';
@Component({
selector: 'sl-radio-group',
templateUrl: './radio-group-tpl.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => RadioGroupTplComponent),
multi: true
}
],
})
export class RadioGroupTplComponent implements AfterContentInit, ControlValueAccessor, OnDestroy, OnChanges {
@Input() isCanCancel: boolean = false;
@Input() isDisabled: boolean;
@Input() slName: string;
@Input() isMultiple: boolean; // 是否支持多選
@ContentChildren(forwardRef(() => RadioTplComponent), { descendants: true }) radios: QueryList<RadioTplComponent>;
onChange: (_: string) => void = () => null;
onTouched: () => void = () => null;
private value: any;
private destroy$ = new Subject();
private selectSubscription: Subscription;
private touchedSubscription: Subscription;
constructor(private cdr: ChangeDetectorRef, renderer: Renderer2, elementRef: ElementRef) {
renderer.addClass(elementRef.nativeElement, 'sl-radio-group-wrapper');
}
updateChildrenStatus(): void {
if (this.radios) {
Promise.resolve().then(() => {
this.radios.forEach(radio => {
radio.isSelected = radio.slValue == this.value;
radio.isCanCancel = this.isCanCancel;
radio.isMultiple = this.isMultiple;
if (isNotNil(this.isDisabled)) {
radio.isDisabled = this.isDisabled;
}
if (this.slName) {
radio.name = this.slName;
}
radio.markForCheck();
})
})
}
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.isDisabled || changes.slName) {
this.updateChildrenStatus();
}
}
ngOnDestroy(): void {
this.destroy$.next();
this.destroy$.complete();
}
writeValue(value: any): void {
this.value = value;
this.updateChildrenStatus();
this.cdr.markForCheck();
}
registerOnChange(fn: any): void {
this.onChange = fn;
}
registerOnTouched(fn: any): void {
this.onTouched = fn;
}
setDisabledState?(isDisabled: boolean): void {
this.isDisabled = isDisabled;
this.cdr.markForCheck();
}
ngAfterContentInit(): void {
this.radios.changes
.pipe(
startWith(null),
takeUntil(this.destroy$)
).subscribe(() => {
this.updateChildrenStatus();
if (this.selectSubscription) {
this.selectSubscription.unsubscribe();
}
this.selectSubscription = merge(...this.radios.map(radio => radio.select$))
.pipe(takeUntil(this.destroy$))
.subscribe(radio => {
if (this.isMultiple) { // 支持多選
let vals = this.value && isString(this.value) ? this.value.split(',') : [];
let index = vals.findIndex(ele => ele == radio.slValue);
if (index != -1) {
vals.splice(index, 1);
} else {
vals.push(radio.slValue);
}
let val = '';
vals.forEach(ele => {
val += ele + ',';
})
this.value = val ? val.substring(0, val.length - 1) : val;
this.onChange(vals);
} else {
if (this.value !== radio.slValue) {
this.value = radio.slValue;
this.updateChildrenStatus();
this.onChange(this.value);
} else {
if (this.isCanCancel) {
this.value = null;
this.updateChildrenStatus();
this.onChange(this.value);
}
}
}
});
if (this.touchedSubscription) {
this.touchedSubscription.unsubscribe();
}
this.touchedSubscription = merge(...this.radios.map(radio => radio.touched$))
.pipe(takeUntil(this.destroy$))
.subscribe(() => {
Promise.resolve().then(() => this.onTouched());
});
});
}
}
不是自己寫的看起來好難。
<ng-content></ng-content>
radio組件用到的樣式
.sl-radio-wrapper {
box-sizing: border-box;
margin: 0 8px 0 0;
padding: 0;
color: rgba(0, 0, 0, .65);
font-size: 14px;
font-variant: tabular-nums;
line-height: 1.5;
list-style: none;
font-feature-settings: 'tnum';
position: relative;
display: inline-block;
white-space: nowrap;
cursor: pointer;
}
.sl-radio {
width: 16px;
height: 16px;
box-sizing: border-box;
margin: 0;
padding: 0;
color: rgba(0, 0, 0, .65);
font-size: 14px;
font-variant: tabular-nums;
list-style: none;
font-feature-settings: 'tnum';
position: relative;
display: inline-block;
line-height: 1;
white-space: nowrap;
vertical-align: sub;
outline: 0;
cursor: pointer;
.sl-radio-input {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
cursor: pointer;
opacity: 0;
}
.sl-radio-inner {
position: absolute;
top: -1px;
}
}
.sl-radio-content {
padding-right: 8px;
padding-left: 8px;
}
關於radio-group組件的各種組合
<div class="usage radio-usage">
<h2>單個 radio狀態</h2>
<h3>可取消選中</h3>
<label sl-radio [isSelected]="true" [isCanCancel]="true" slValue="A">A</label>
<h3>不可取消選中</h3>
<label sl-radio>E</label>
<label sl-radio slValue="B">B</label>
<label sl-radio [isDisabled]="true" slValue="C">C</label>
<label sl-radio [isSelected]="true" slValue="D" [isDisabled]="true">D</label>
<h2>多個radio互斥,可選中1個,可1個不選</h2>
<sl-radio-group [(ngModel)]="radioValue" [isCanCancel]="true">
<label sl-radio slValue="A">A</label>
<label sl-radio slValue="B">B</label>
<label sl-radio slValue="C">C</label>
<label sl-radio slValue="D">D</label>
<sl-button [btnType]="'confirm'" (btnClick)="getRadioValue(radioValue)"></sl-button>
</sl-radio-group>
<h2>多個radio互斥,要麼不選,要麼選中1個</h2>
<sl-radio-group [(ngModel)]="radioValue2">
<label sl-radio slValue="A">A</label>
<label sl-radio slValue="B">B</label>
<label sl-radio slValue="C">C</label>
<label sl-radio slValue="D">D</label>
<sl-button [btnType]="'confirm'" (btnClick)="getRadioValue(radioValue2)"></sl-button>
</sl-radio-group>
<h2>多個radio 不互斥,可多選,也可不選</h2>
<sl-radio-group [(ngModel)]="radioValue3" [isCanCancel]="true" [isMultiple]="true">
<label sl-radio slValue="A">A</label>
<label sl-radio slValue="B">B</label>
<label sl-radio slValue="C">C</label>
<label sl-radio slValue="D">D</label>
<sl-button [btnType]="'confirm'" (btnClick)="getRadioValue(radioValue3)"></sl-button>
<sl-button [btnType]="'danger'" (btnClick)="radioValue3=''">清除</sl-button>
</sl-radio-group>
</div>