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、最后展示下大致效果圖

