import { Directive, ElementRef, Injector, Input, Renderer2, OnInit, AfterViewInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core'; import { NgControl } from '@angular/forms'; import { LocaleService } from '@farris/ui-locale'; import { EventManager } from '@angular/platform-browser'; @Directive({ selector: '[word-count]', exportAs: 'WordCountRef' }) export class TextareaWordcountDirective implements OnInit, AfterViewInit, OnDestroy, OnChanges { @Input('word-count') useWordCount = true; /** * 统计字数的方式; surplus 剩余可输入字数; length: 当前已输入字数; * * 默认为 surplus */ @Input() countType: 'surplus' | 'length' = 'surplus'; @Input() onlyShowInDialog = false; wordCountElement = null; // 当前字数 private currentLengthElement = null; private eventManager: EventManager; private ngControl: NgControl; private onInput = null; private localeSer: LocaleService; constructor(private el: ElementRef, private render: Renderer2, private injector: Injector) { this.eventManager = this.injector.get(EventManager); this.localeSer = this.injector.get(LocaleService); } ngOnInit() { this.ngControl = this.injector.get(NgControl, null); } ngAfterViewInit() { this.initWordCount(); if (this.ngControl && this.useWordCount) { this.ngControl.control.valueChanges.subscribe((e) => { this.updateWordsCount(); }); } } ngOnChanges(changes: SimpleChanges): void { if (changes.useWordCount && !changes.useWordCount.isFirstChange()) { if (this.useWordCount) { this.initWordCount(); } else { this.destroy(); } } } ngOnDestroy() { this.destroy(); } private destroy() { if (this.onInput) { this.onInput(); } if (this.wordCountElement) { this.wordCountElement.remove(); } } initWordCount() { if (this.useWordCount && !this.onlyShowInDialog) { this.createWordCountElement(); } } private createWordCountID() { const tagName = this.el.nativeElement.tagName; if (this.ngControl) { const ctrlName = this.ngControl.name; return `${tagName}_WORDCOUNT_${ctrlName}`; } else { if (this.el.nativeElement.id) { return `${tagName}_WORDCOUNT_${this.el.nativeElement.id}`; } } return ''; } private createWordCountElement() { const max = this.el.nativeElement.maxLength; if (!max || max < 0) { console.info('未设置最大字符数,计数功能失效。'); return; } const wordCountSPAN = this.render.createElement('span'); wordCountSPAN.className = 'textarea-wordcount'; const id = this.createWordCountID(); if (id) { wordCountSPAN.id = id; } this.render.setStyle(wordCountSPAN, 'position', 'absolute'); this.render.setStyle(wordCountSPAN, 'bottom', '10px'); this.render.setStyle(wordCountSPAN, 'right', '20px'); this.render.setStyle(wordCountSPAN, 'cursor', 'pointer'); this.el.nativeElement.after(wordCountSPAN); this.wordCountElement = wordCountSPAN; const currentLengthSPAN = this.render.createElement('span'); wordCountSPAN.appendChild(currentLengthSPAN); this.currentLengthElement = currentLengthSPAN; currentLengthSPAN.after( ` / ${max}` ); this.updateWordsCount(); this.onInput = this.render.listen(this.el.nativeElement, 'input', () => { // value.replace(/\n|\r/gi, '') // 移除换行符 this.updateWordsCount(); }); } updateWordsCount() { if (!this.useWordCount || !this.currentLengthElement) { return; } const max = this.el.nativeElement.maxLength; const val = this.countType === 'surplus' ? max - this.el.nativeElement.value.length : this.el.nativeElement.value.length; const tip = 'messager.prompt.tips.' + this.countType; this.currentLengthElement.innerText = val; this.wordCountElement.title = this.localeSer.getValue(tip).replace('{0}', val); } }