[ionic3.x開發記錄]參考ionic的float-label動效,寫一個項目內通用的input組件,易擴展

上圖:javascript

module:css

import {NgModule} from "@angular/core";
import {CommonModule} from "@angular/common"
import {PpInputComponent} from './pp-input'
import {FormsModule} from "@angular/forms";

@NgModule({
  declarations: [PpInputComponent],
  imports: [
    CommonModule,
    FormsModule,
  ],
  exports: [PpInputComponent],
})

export class PpInputComponentModule {
}

 ts:html

import {Component, Input, Output, EventEmitter, OnInit, ViewChild, ElementRef, Renderer2, AfterViewInit} from '@angular/core';

/**
 * Generated class for the PpInputComponent component.
 *
 * See https://angular.io/api/core/Component for more info on Angular
 * Components.
 */
@Component({
  selector: 'pp-input',
  templateUrl: 'pp-input.html'
})
export class PpInputComponent implements OnInit, AfterViewInit {
  constructor(private renderer: Renderer2) {
  }

  @ViewChild('ppLabel') private ppLabel: ElementRef; // 獲取元素
  @Input() ppValue: any; // input的值,雙向綁定
  @Input('pp-label') label: string = 'Label'; // label文案
  @Input() validate: any = function (input) { // 驗證數據方法
    if (input) {
      return true
    } else {
      return false
    }
  };
  @Input() type: string = 'text'; // input類型
  @Input() x: string; // label的X軸偏移量
  @Input() isRequired: boolean; // false
  @Input('error-message')  errorMessage: string = 'validate error'; // 錯誤提示信息

  @Output() ppValueChange = new EventEmitter();

  actived: boolean = false; // 樣式控制
  float: boolean; // label是否浮動
  showErrMsg: boolean = false; // 是否顯示錯誤信息

  ngOnInit() {
    if (this.ppValue) {
      this.float = true;
      this.actived = true;
    } else {
      this.float = false;
    }
  }

  ngAfterViewInit() {
    if (this.x) {
      this.renderer.setStyle(this.ppLabel.nativeElement, 'transform', `translate3d(${Number(this.x) / 100}rem, 0.48rem, 0)`)
    }
  }

  // 得到焦點
  ppFocus() {
    this.float = true;
  }

  // 失去焦點
  ppBlur() {
    if (this.ppValue) {
      this.float = true;
    } else {
      this.float = false;
    }
    if (this.validate(this.ppValue)) {
      this.showErrMsg = false;
    } else {
      this.showErrMsg = true;
    }
  }

  // 更新父組件model值
  changeValue() {
    this.ppValueChange.emit(this.ppValue);
    if (this.validate(this.ppValue)) {
      this.actived = true;
      this.showErrMsg = false;
    } else {
      this.actived = false;
    }
  }
}

  scssvue

pp-input {
  .pp-input-container {
    border-bottom: 1px solid #C1CCD5;
    height: 0.92rem;
    &.actived {
      border-color: #6308C7
    }
    .label {
      font-size: 0.28rem;
      color: #95A1AB;
      position: relative;
      font-family: Avenir-Medium;
      pointer-events: none;
      transform: translate3d(0,0.48rem, 0);
      transition: all 0.2s;
      margin: 0.11rem 0.08rem 0.11rem 0;
      &.actived {
        transform: translate3d(0, 0, 0)!important;
        font-size: 0.22rem;
        transition: all 0.2s;
        .actived {
          color: #6308C7
        }
      }
      .required {
        color: #F44E4E
      }
    }
    .pp-input {
      border: none;
      font-size: 0.28rem;
      height: 0.5rem;
      line-height: 0.5rem;
    }
    .content {
      display: flex;
      align-items: center;
    }
  }
  .error-message {
    color: #F44E4E;
    font-size: 0.22rem;
    height: 0;
    line-height: 0.4rem;
    opacity: 0.5;
    transition: all 0.2s;
    overflow: hidden;
    &.show {
      opacity: 1;
      height: 0.4rem;
      transition: all 0.2s;
    }
  }
}

  htmljava

<!-- Generated template for the PpInputComponent component -->
<div class="pp-input-wrapper">
  <div class="pp-input-container" [class.actived]="actived">
    <div class="label" [class.actived]="float" #ppLabel>
      <span class="required" *ngIf="isRequired">*</span><span [class.actived]="actived">{{label}}</span>
    </div>
    <div class="content">
      <ng-content></ng-content>
      <input class="pp-input"
             (focus)="ppFocus()"
             (blur)="ppBlur()"
             (keyup)="changeValue()"
             [type]="type"
             [(ngModel)]="ppValue">
    </div>
  </div>
  <div class="error-message" [class.show]="showErrMsg">{{errorMessage}}</div>
</div>

 目前實現可傳入label文案, label的x軸偏移,input類型,驗證數據的validate方法,input的雙向綁定value值,錯誤提示信息等api

用<ng-content></ng-content>預留的編輯位置,能夠添加更多的html,方便擴展,例如上圖的國家圖標顯示。app

能夠考慮把全部的@Input集合成一個config,html的font-size的值我是動態算的,因此樣式rem的值可能要修改爲你須要的大小。flex

ps: 以前用vue組件也寫過類型的組件,傳送門:http://www.javashuo.com/article/p-nifvoiid-dk.htmlui

相關文章
相關標籤/搜索