前言
这个组件实现并不是很复杂,我会尽量注释;
这货诞生的理由就是项目刚好有一个地方必须只能选择年月,
而github
上ng2+
日期组件都涉及到年月日或时分秒;
效果用gifcam
录制的,色彩有些失真,将就吧。
效果图
实现思路
- 月份只有十二个,只要把个位数做好补位就好
- 年份的生成是可控的(传参),当前年份往前推几年和往后推几年构成;
- 数据遍历结构很简单
{ date:2017, // 月份是字符串,年份是数字 active:false, type:'year' // 月份是'month' }
页面样式就自行折腾啦,我这里只是用了最直白粗暴的下拉滑动
实现代码
html
<div class="only-year-month-select"> <div class="select" (click)="isExpand = !isExpand"> <input type="text" [placeholder]="placeholder" class="form-control" [(ngModel)]="selected" [disabled]="true"> </div> <div class="list-menu" *ngIf="isExpand" [@fadeIn]="true"> <div class="sub-list1"> <p class="title">年份</p> <ul class="year-wrap"> <li *ngFor="let i of selectYearRange;let index = index" [class.active]="i.active" (click)="actValue(selectYearRange,index)" (dblclick)="emitResult(i)">{{i.date}}</li> </ul> </div> <div class="sub-list2"> <p class="title">月份</p> <ul class="month-wrap"> <li *ngFor="let i of selectMonthRange;let index = index" [class.active]="i.active" (click)="actValue(selectMonthRange,index)" (dblclick)="emitResult(i)">{{i.date}}</li> </ul> </div> </div> </div>
components
import { Component, OnInit, Input, Output, EventEmitter, HostListener, ElementRef } from '@angular/core'; // 动画 import { fadeIn } from '../../animation/fadeIn'; @Component({ selector: 'app-only-year-month-select', templateUrl: './only-year-month-select.component.html', styleUrls: ['./only-year-month-select.component.scss'], animations: [fadeIn] }) export class OnlyYearMonthSelectComponent implements OnInit { @Input() public placeholder: string; @Input() public range: any; @Output() public result = new EventEmitter(); public isExpand = false; public selectYear: any; public selectMonth: any; public selectYearRange: Array<any> = []; public selectMonthRange: Array<any> = []; public selected: any; constructor( private _el: ElementRef ) { } ngOnInit() { this.getCurrentDate(); } // 获取当前的年月 getCurrentDate(): void { const TODAY = new Date(); this.selectYear = TODAY.getFullYear(); this.selectMonth = TODAY.getMonth() < 9 ? '0' + (TODAY.getMonth() + 1) : String(TODAY.getMonth() + 1); this.selectYearRange.push( { date: this.selectYear, active: true, type: 'year' } ); this.selectMonthRange.push( { date: this.selectMonth, active: true, type: 'month' } ); this.selectYearRange = this.getRangeYear(this.selectYear, this.range.before, this.range.after); this.selectMonthRange = this.getRangeMonth(this.selectMonth); console.log(this.selectYearRange, this.selectMonthRange); } // 需要生成的日期范围 getRangeYear(year: number, before: number = 5, after: number = 10): any { // console.log(year, before, after); let _beforeYear = year; let _afterYear = year; for (let i = 0; i < before; i++) { this.selectYearRange.unshift( { date: --_beforeYear, active: false, type: 'year' } ); } for (let j = 0; j < after; j++) { this.selectYearRange.push( { date: ++_afterYear, active: false, type: 'year' } ); } return this.selectYearRange; } // 月份范围 getRangeMonth(month): any { for (let i = 0; i < 12; i++) { const temp = i < 9 ? '0' + (i + 1) : '' + (i + 1); if (month !== temp) { this.selectMonthRange.push( { date: temp, active: false, type: 'month' }); } } this.selectMonthRange.sort(this.compare('date')); return this.selectMonthRange; } // 数组对象排序 compare(property) { return function (a, b) { const value1 = a[property]; const value2 = b[property]; return value1 - value2; }; } // 年份或者月份选择 actValue(list: any, index: number) { list.forEach((v, i) => { if (i === index) { v.active = true; if (v.type === 'year') { console.log(v.date); this.selectYear = v.date; } if (v.type === 'month') { console.log(v.date); this.selectMonth = v.date; } } else { v.active = false; } }); this.emitResult(); } // 获取结果集 emitResult(e?: any) { if (e) { // 双击则关闭弹出 this.isExpand = false; } this.selected = this.selectYear + '-' + this.selectMonth; this.result.emit(this.selected); } // 监听全局点击事件 @HostListener('document:click', ['$event.target']) public onClick(targetElement) { const clickedInside = this._el.nativeElement.contains(targetElement); if (!clickedInside) { this.isExpand = false; this.emitResult(); } } }
fadeIn.ts
// 动画的效果很简单,就是把css3的效果用js来实现,具体的效果就是渐现 // 放在突然出来一块区域的地方,触发看起来会比较顺眼,有个过渡 import { trigger, state, style, transition, animate, keyframes } from '@angular/animations'; //transition(':enter', [ ... ]); // void => * //transition(':leave', [ ... ]); // * => void export const fadeIn = trigger('fadeIn', [ state('in', style({ display: 'none' })), transition('void => *', [ animate(200, keyframes([ style({ height: '0', opacity: 0, offset: 0 }), style({ height: '*', opacity: 1, offset: 1 }) ])) ]), transition('* => void', [ animate(200, keyframes([ style({ height: '*', opacity: 1, offset: 0 }), style({ height: '0', opacity: 0, offset: 1 }) ])) ]), ]); // 200 是过渡时间,毫秒 // offset相当于 css3 中keyframes的百分比,,控制动画的进度的。。0 -> 1 就相当于 0% -> 100%
封装成模块
可以输出模块给其他地方引用
import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { OnlyYearMonthSelectComponent } from './only-year-month-select.component'; @NgModule({ imports: [ CommonModule, // 用用到一些内置的指令必须依赖这个,比如*ngIF, *ngFor FormsModule // 有用到表单元素必须引入这货 ], declarations: [OnlyYearMonthSelectComponent], // 声明年月组件 exports: [OnlyYearMonthSelectComponent] // 导出年月组件 }) export class OnlyYearMonthSelectModule { }
组件使用
温馨提示:
- 若不是以模块的方式到处,只要在使用的模块引入组件声明下就能使用
- 反之则需要引入这个模块,方可使用
局部代码
module
// 在要使用的模块中引入 // 公用组件 import { MitEhartsModule } from '../../../widgets/mit-echarts/mit-echarts.module'; import { MitDataTableModule } from '../../../widgets/mit-data-table/mit-data-table.module'; import { MitLoadingModule } from '../../../widgets/mit-loading/mit-loading.module'; import { OnlyYearMonthSelectModule } from '../../../share/only-year-month-select/only-year-month-select.module'; import { DepartmentSelectModule } from '../../../share/department-select/department-select.module'; const mitModule = [ MitEhartsModule, MitDataTableModule, MitLoadingModule, DepartmentSelectModule, OnlyYearMonthSelectModule ] @NgModule({ imports: [ CommonModule, FormsModule, NgbDatepickerModule, ...mitModule, DailyCarRoutes ], providers: [DailyCarService], declarations: [...page] }
html
<div class="form-group condition-wrapper"> <label class="form-control-label">月份</label> <app-only-year-month-select class="form-control" [placeholder]="'yyyy-mm'" (result)="Time = $event" [range]="{before:5,after:10}"></app-only-year-month-select> </div>