Angular混合開(kāi)發(fā)移動(dòng)端使用自定義虛擬鍵盤(pán)組件時(shí)進(jìn)行事件訂閱監(jiān)聽(tīng)以及獲取虛擬鍵盤(pán)上的值

1、應(yīng)用場(chǎng)景

我們開(kāi)發(fā)了一個(gè)虛擬鍵盤(pán)的組件,然后將虛擬鍵盤(pán)的組件全局掛載到根目錄上去,通過(guò)某個(gè)屬性去控制虛擬鍵盤(pán)的顯示與否即可,但是,有一個(gè)難點(diǎn),就是在使用到的組件中如果通過(guò)虛擬鍵盤(pán)的Enter鍵將虛擬鍵盤(pán)的值傳到我們想要的組件中去呢?service服務(wù)幾乎不考慮,因?yàn)槟憧梢詫⒅荡娴椒?wù)中去,但是你在使用到的那個(gè)組件中如何去知道用戶(hù)點(diǎn)擊了enter鍵呢?

2、手動(dòng)封裝一個(gè)類(lèi)似Vue中的Bus事件分發(fā)

定義一個(gè)interface,中間有兩個(gè)屬性,也就是事件名稱(chēng)以及傳遞的數(shù)據(jù)值。

import { Injectable } from '@angular/core';
import { Subject, Subscription } from 'rxjs';
import { filter, map } from 'rxjs/operators';

interface IScreenEvent {
  eventType: string;
  eventData: any;
}

@Injectable()
export class EmitBusUtils {
  private _subject = new Subject<IScreenEvent>();

  public emit(eventType: string, eventData: any) {
    this._subject.next({
      eventType,
      eventData,
    });
  }

  subscribe(eventType: string, listener: (value: any) => void): Subscription {
    return this._subject.asObservable()
      .pipe(
        filter((value, index) => value.eventType === eventType),
        map((value, index) => value.eventData),
      ).subscribe(listener);
  }
}

3、部分虛擬鍵盤(pán)組件的代碼

虛擬鍵盤(pán)可以通過(guò)原生js的dom操作等實(shí)現(xiàn)或者可以去參考開(kāi)源庫(kù)等不同的插件的代碼實(shí)現(xiàn),在封裝的虛擬鍵盤(pán)的組件中,我們想要實(shí)現(xiàn)值的傳遞,就需要在用戶(hù)按下enter鍵的時(shí)候,去emit數(shù)據(jù)出去,并且關(guān)閉虛擬鍵盤(pán),將虛擬鍵盤(pán)上的值填入我們想要的對(duì)應(yīng)的地方去。

import { AfterViewInit, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { EmitBusUtils } from '@core/utils/emit-bus.utils';
import { AppService } from 'app/app.service';
declare var aKeyboard: any;

@Component({
  selector: 'virtual-keyboard',
  template: `
    <div class="box" >
      <ion-icon
        class="delete-icon delete"
        (click)="onClose()"
        src="assets/icon/close-outline.svg"
      ></ion-icon>
      <ion-input
        (touchstart)="onTouchStart($event)"
        (touchmove)="onTouchMove($event)"
        (touchend)="onTouchEnd($event)"
        id="inputKeyboard"
        placeholder=" 按住此區(qū)域可進(jìn)行拖拽"
        readonly
      ></ion-input>
      <div id="main"></div>
    </div>
  `,
  styles: [
    `
      .box {
        position: fixed;
        width: 300px;
        height: 240px;
        box-shadow: 2px 2px 4px rgb(0 0 0 / 10%);
        top: 100px;
        left: 300px;
      }

      #input {
        margin: auto;
        background: #fff;
        border-top-left-radius: 0.3rem;
        border-top-right-radius: 0.3rem;
        border-left: 1px solid #f7ecec;
        border-top: 1px solid #f7ecec;
        border-right: 1px solid #f7ecec;
      }

      ion-icon.drag-icon {
        font-size: 2rem;
        position: absolute;
        left: -18px;
        top: 4px;
      }

      ion-icon.delete-icon {
        font-size: 1.5rem;
        position: absolute;
        right: -5px;
        top: -19px;
        color: #ccc;
      }
    `,
  ],
})
export class KeyboardComponent implements AfterViewInit {
  _isShow; // 是否顯示
  @Input()
  set isShow(value: any) {
      this._isShow = value;
  }

  get isShow() {
      return this._isShow;
  }
  @Output() change: EventEmitter<boolean> = new EventEmitter<boolean>();
  @Output() sendData: EventEmitter<any> = new EventEmitter<any>();
  constructor(private _app: AppService, private _bus: EmitBusUtils) {

  }
  keyboard;
  inputKeyboard;
  container;
  isDown = false; // 是否按下拖拽圖標(biāo)
  position = {
    start_x: 0,
    start_y: 0,
    move_x: 0,
    move_y: 0,
    box_x: 0,
    box_y: 0,
  };

  ngAfterViewInit() {
   if (this._isShow) {
     this.inputKeyboard = document.querySelector('#inputKeyboard');
     this.container = document.querySelector('.box');
     this.keyboard = new aKeyboard.numberKeyboard({
       el: '#main',
       style: {
         position: 'absolute',
         top: this.position.box_x + 35 + 'px',
         left: this.position.box_y,
         right: '0',
         bottom: '0',
       },
     });
  
     this.keyboard.inputOn('#inputKeyboard', 'value');

     this.keyboard.onclick('Enter', (e) => {
       this.change.emit(false);
       this._bus.emit('getInputValue', {
         value: document.querySelector('#inputKeyboard')['value']
       });
     });
   }
  }

  // 關(guān)閉事件
  onClose() {
    this._isShow = false;
    this.change.emit(this._isShow);
  }

  // 觸摸開(kāi)始事件
  onTouchStart(e) {
    this.position['start_x'] = e.changedTouches[0].clientX;
    this.position['start_y'] = e.changedTouches[0].clientY;

    this.position['box_x'] = this.container.offsetLeft;
    this.position['box_y'] = this.container.offsetTop;
    this.isDown = true;
  }

  // 觸摸移動(dòng)事件
  onTouchMove(e) {
    if (!this.isDown) {
      return;
    }
    this.position['move_x'] =
      e.changedTouches[0].clientX - this.position['start_x'];
    this.position['move_y'] =
      e.changedTouches[0].clientY - this.position['start_y'];

    this.container.style.left =
      this.position['box_x'] + this.position['move_x'] + 'px';
    this.container.style.top =
      this.position['box_y'] + this.position['move_y'] + 'px';
  }

  // 手指離開(kāi)屏幕
  onTouchEnd(e) {
    this.isDown = false;
  }

  
}

4、掛載到根目錄下

掛載到根目錄下通過(guò)app服務(wù)中的isShow為true還是false去控制。

<virtual-keyboard [isShow]="app.isShow" *ngIf="app.isShow" (change)="handleChange($event)" ></virtual-keyboard>
5、在需要使用虛擬鍵盤(pán)的地方去subscribe訂閱事件

每次點(diǎn)擊文本框的時(shí)候,進(jìn)行取反操作,this.appService.isShow = !this.appService.isShow;也就是虛擬鍵盤(pán)的彈出與關(guān)閉,this._bus.subscribe('訂閱的事件名(一定要與emit那邊相同的事件名相同)', (res) => { // 這里的res也就是那邊emit傳過(guò)來(lái)的值 })

  async handleOpen(query) {
    // tslint:disable-next-line: curly
    if (query && query.mark) return;
    this.appService.isShow = !this.appService.isShow;
    await this._bus.subscribe('getInputValue', (res) => {
      if (res) {
        console.log(res);
        query.count = Number(res.value);
      } 
    });
  }
6、最后展示下大致效果圖
圖1.png

圖2.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Vue一文學(xué)會(huì)? Vue大家都知道就是一個(gè)國(guó)內(nèi)非常流行的框架,最近因?yàn)檫^(guò)了許久沒(méi)用Vue對(duì)于Vue的許多早已淡忘,...
    看物看霧閱讀 689評(píng)論 0 3
  • Vue自定義數(shù)字鍵盤(pán) 前言 最近做 Vue 開(kāi)發(fā),因?yàn)橛胁簧夙?yè)面涉及到金額輸入,產(chǎn)品老是覺(jué)得用原生的 input ...
    Cryptic閱讀 5,024評(píng)論 0 6
  • 1.說(shuō)說(shuō)對(duì)雙向綁定的理解 1.1、雙向綁定的原理是什么 我們都知道Vue是數(shù)據(jù)雙向綁定的框架,雙向綁定由三個(gè)重要部...
    GuessYe閱讀 642評(píng)論 0 0
  • 什么是Vue.js Vue.js是目前最火的一個(gè)前端框架,React是最流行的一個(gè)前端框架,(React除了開(kāi)發(fā)網(wǎng)...
    EEEEsun閱讀 736評(píng)論 0 1
  • 1.什么是vue的生命周期? Vue實(shí)例從創(chuàng)建到銷(xiāo)毀的過(guò)程,就是生命周期。也就是從開(kāi)始創(chuàng)建、初始化數(shù)據(jù)、編譯模板、...
    陳二狗想吃肉閱讀 628評(píng)論 0 0

友情鏈接更多精彩內(nèi)容