一个软键盘组件,有两种形态,一种拼音键盘,一种纯数字键盘,这里贴出一张拼音键盘看看样式吧
接下来就是组件的三大件了 html
<div class="close-panel">
<button mat-icon-button matTooltip="关闭" (click)="close()">
<mat-icon>close</mat-icon>
</button>
</div>
<div *ngIf="inputMode=='zh-cn'">
<div class='simple-input-method' (click)="pinyinSelect($event)">
<div class="pinyin">拼音:{{this.hanzi}}{{this.pinyin}}</div>
<div class="result">
<ol>
<li *ngFor="let item of currentPageResult;let index=index" [attr.data-idx]='index+1'>{{item}}</li>
</ol>
<div class="page-up-down">
<span class="page-up" [ngStyle]="{'opacity':pageCurrent>1?'1':'0.3'}">▲</span>
<span class="page-down" [ngStyle]="{'opacity':pageCurrent<pageCount?'1':'0.3'}">▼</span>
</div>
</div>
</div>
</div>
<div class="simple-keyboard"></div>
scss
.close-panel {
display: flex;
justify-content: flex-end;
}
// .zh-panel {
// display: flex;
// .zh-char {
// padding: 10px;
// cursor: pointer;
// &:hover {
// background-color: #ffe0b2;
// }
// }
// }
.input-value {
margin-bottom: 5px;
}
::ng-deep .simple-keyboard .hg-button {
height: 55px !important;
font-size: 18px;
}
::ng-deep .mat-bottom-sheet-container-medium {
min-width: 85vw !important;
max-width: calc(100vw - 64px);
}
::ng-deep .mat-bottom-sheet-container-large {
min-width: 70vw !important;
max-width: calc(100vw - 128px);
}
// ::ng-deep .result-li {
// float: left;
// margin-left: 30px;
// cursor: pointer;
// &:first-child {
// color: red;
// }
// }
.simple-input-method {
background: #FFF;
border: solid 1px #ececec;
border-radius: 5px;
color: #0364CD;
display: block;
margin-bottom: 5px;
}
.simple-input-method .pinyin {
border-bottom: solid 1px #ececec;
padding: 4px 10px;
font-weight: bold;
}
.simple-input-method .result {
padding: 4px 10px 4px 0px;
ol {
margin: 0;
padding: 0;
display: inline-block;
vertical-align: middle;
li {
float: left;
margin-left: 30px;
cursor: pointer;
&:first-child {
color: red;
}
}
:after {
content: '';
display: block;
clear: left;
}
}
}
// .simple-input-method .result ol:after {
// content: '';
// display: block;
// clear: left;
// }
.simple-input-method .page-up-down {
display: inline-block;
border: solid 1px #BADBFF;
font-size: 15px;
color: #4C9AEF;
border-radius: 1px;
margin-left: 10px;
}
.simple-input-method .page-up-down .page-down {
border-left: solid 1px #BADBFF;
}
.simple-input-method .page-up-down span {
cursor: pointer;
}
.simple-input-method .page-up-down span.disable {
opacity: .3;
}
ts
import { KeyboardService } from './keyBoard.service';
import { MatBottomSheetRef } from '@angular/material';
import { Component, OnInit, ChangeDetectorRef } from '@angular/core';
import Keyboard from 'simple-keyboard';
@Component({
selector: 'bottom-sheet',
templateUrl: 'keyBoardBottomSheet.component.html',
styleUrls: ['./keyBoardBottomSheet.component.scss']
})
export class KeyBoardBottomSheet implements OnInit {
keyboard: Keyboard;
inputValue;
inputMode;
hanzi = ''; // 候选汉字
pinyin = ''; // 候选拼音
result = []; // 当前匹配到的汉字集合
currentPageResult = [];
pageCurrent = 1; // 当前页
pageSize = 9; // 每页大小
pageCount = 0; // 总页数
constructor(
private keyboardSvr: KeyboardService,
private bottomSheetRef: MatBottomSheetRef<KeyBoardBottomSheet>,
private changeRef: ChangeDetectorRef) { }
ngOnInit(): void {
}
ngAfterViewInit() {
let layout;
if (this.keyboardSvr.KeyBoardType == 'num') {
layout = {
default: ["1 2 3", "4 5 6", "7 8 9", ". 0 {bksp}", "{enter}"],
};
}
else if (this.keyboardSvr.KeyBoardType == 'default') {
layout = {
default: [
"1 2 3 4 5 6 7 8 9 0 {bksp}",
"{tab} q w e r t y u i o p",
"{lock} a s d f g h j k l {enter}",
"{shift} z x c v b n m , .",
"{space}"]
};
}
this.keyboard = new Keyboard({
layout,
display: {
'{bksp}': '<i matListIcon style="font-size: 20px;" class="iconfont icon-delete" aria-hidden="true"></i>',
'{enter}': '<i matListIcon style="font-size: 20px;" class="iconfont icon-huiche" aria-hidden="true"></i>',
'{lock}': '中/英',
'{tab}': 'tab',
'{shift}': 'Shift',
'{space}': '空格'
},
theme: "hg-theme-default hg-layout-numeric numeric-theme"
});
this.keyboardSvr.registKeyboard(this.keyboard);
this.keyboardSvr.onZhCnChanged = (input) => {
if (input == '{bksp}') {
this.delChar()
} else if (input == '{space}') {
this.selectHanzi(1)
} else {
let keyCode = (input + '').toLocaleUpperCase().charCodeAt(0);
if (keyCode >= 65 && keyCode <= 90) // A-Z
{
this.addChar(String.fromCharCode(keyCode + 32));
}
else if (keyCode >= 48 && keyCode <= 57 && this.pinyin) // 1-9
{
this.selectHanzi(keyCode - 48);
}
}
}
this.keyboardSvr.onInputModeChanged = (inputMode) => {
this.inputMode = inputMode;
this.changeRef.detectChanges();
this.reset();
}
}
close() {
this.keyboardSvr.destroyKeyboard();
}
pinyinSelect(e) {
var target = e.target;
if (target.nodeName == 'LI') {
this.selectHanzi(parseInt(target.getAttribute('data-idx')));
}
else if (target.nodeName == 'SPAN') {
if (target.className == 'page-up' && this.pageCurrent > 1) {
this.pageCurrent--;
this.refreshPage();
}
else if (target.className == 'page-down' && this.pageCurrent < this.pageCount) {
this.pageCurrent++;
this.refreshPage();
}
}
}
selectHanzi(i) {
var hz = this.result[(this.pageCurrent - 1) * this.pageSize + i - 1];
if (!hz) return;
this.hanzi += hz;
var idx = this.pinyin.indexOf("'");
if (idx > 0) {
this.pinyin = this.pinyin.substr(idx + 1);
this.refresh();
}
else // 如果没有单引号,表示已经没有候选词了
{
this.keyboardSvr.setInput(this.hanzi);
this.reset();
}
}
refresh() {
var temp = this.getHanzi(this.pinyin.replace(/'/g, ''));
this.result = temp[0];
this.pinyin = temp[1];
var count = this.result.length;
this.pageCurrent = 1;
this.pageCount = Math.ceil(count / this.pageSize);
this.refreshPage();
}
refreshPage() {
this.currentPageResult = this.result.slice((this.pageCurrent - 1) * this.pageSize, this.pageCurrent * this.pageSize);
this.changeRef.detectChanges();
}
getSingleHanzi(pinyin) {
return (<any>window).pinyinUtil.dict.py2hz2[pinyin] || (<any>window).pinyinUtil.dict.py2hz[pinyin] || '';
}
getHanzi(pinyin) {
var result = this.getSingleHanzi(pinyin);
if (result) return [result.split(''), pinyin];
var temp = '';
for (var i = 0, len = pinyin.length; i < len; i++) {
temp += pinyin[i];
result = this.getSingleHanzi(temp);
if (!result) continue;
// flag表示如果当前能匹配到结果、并且往后5个字母不能匹配结果,因为最长可能是5个字母,如 zhuang
var flag = false;
if ((i + 1) < pinyin.length) {
for (var j = 1, len = pinyin.length; j <= 5 && (i + j) < len; j++) {
if (this.getSingleHanzi(pinyin.substr(0, i + j + 1))) {
flag = true;
break;
}
}
}
if (!flag) return [result.split(''), pinyin.substr(0, i + 1) + "'" + pinyin.substr(i + 1)];
}
return [[], '']; // 理论上一般不会出现这种情况
}
addChar(ch) {
this.pinyin += ch;
this.refresh();
}
delChar() {
if (this.pinyin.length == 0) {
this.keyboardSvr.delInput();
} else if (this.pinyin.length == 1) {
this.reset();
return;
} else {
this.pinyin = this.pinyin.substr(0, this.pinyin.length - 1);
this.refresh();
}
}
reset() {
this.hanzi = '';
this.pinyin = '';
this.result = [];
this.currentPageResult = [];
this.pageCurrent = 1;
this.pageCount = 0;
this.changeRef.detectChanges();
}
}
还有最重要的service.ts
import { Injectable } from '@angular/core';
import Keyboard from 'simple-keyboard';
import { MatBottomSheet, MatBottomSheetRef } from '@angular/material';
@Injectable()
export class KeyboardService {
private keyboard: Keyboard;
private cmp: any;
private svr: MatBottomSheet;
isShow = false;
onKeyboardOpened;
onKeyboardClosed;
onKeyboardTypeChanged;
onZhCnChanged;
onInputModeChanged;
onInputChanged;
private bRef: MatBottomSheetRef;
private keyboardType: 'num' | 'default' = 'default';
get KeyBoardType() {
return this.keyboardType;
}
private value = '';
private inputMode: 'zh-cn' | 'en' = 'en';
constructor(
) {
}
registKeyboard(keyboard: Keyboard) {
this.keyboard = keyboard;
this.keyboard.options.onKeyPress = (input: string) => {
// console.log('keypress', input);
if (input == '{lock}') {
this.changeInputMode();
} else if (input == '{tab}') {
} else {
if (this.inputMode == 'en') {
if (input == '{bksp}') {
this.delInput()
}
else if (input == '{enter}') {
this.onInputChanged && this.onInputChanged(this.value, input);
}
else if (input == '{shift}') {
this.handleShift();
} else if (input == '{space}') {
this.setInput(' ')
} else {
this.setInput(input)
}
} else if (this.inputMode == 'zh-cn') {
if (this.keyboard.options.layoutName == 'shift') {
this.handleShift();
}
this.onZhCnChanged && this.onZhCnChanged(input);
}
}
}
}
private handleShift = () => {
let currentLayout = this.keyboard.options.layoutName;
let shiftToggle = currentLayout === "default" ? "shift" : "default";
this.keyboard.setOptions({
layoutName: shiftToggle
});
};
setInput(input: string) {
this.value += input;
this.onInputChanged && this.onInputChanged(this.value);
}
delInput() {
this.value = this.value.substr(0, this.value.length - 1);
this.onInputChanged && this.onInputChanged(this.value);
}
changeInputMode() {
this.keyboard && this.keyboard.clearInput();
if (this.inputMode == 'zh-cn') {
this.inputMode = 'en';
}
else if (this.inputMode == 'en') {
if (!(<any>window).pinyinUtil) {
throw ('拼音组件未成功加载');
} else {
this.inputMode = 'zh-cn';
}
}
this.onInputModeChanged && this.onInputModeChanged(this.inputMode);
}
registContainer(svr, cmp) {
this.svr = svr;
this.cmp = cmp;
}
showKeyboard(type: 'num' | 'default' = 'default') {
let setting = this.getFromLocalStorage<any>('TerminalSetting');
console.log('showKeyboard:' + JSON.stringify(setting));
let enableKeyboard = false;
if (setting && setting.enableKeyboard) {
enableKeyboard = true;
}
if (!enableKeyboard) {
return;
}
if (this.keyboardType != type) {
this.keyboardType = type;
}
if (this.bRef) {
}
else {
this.bRef = this.svr.open(this.cmp, {
panelClass: 'bottom-sheet-panel',
hasBackdrop: false
});
}
this.bRef.afterDismissed().subscribe(() => {
this.destroyKeyboard();
this.onKeyboardClosed && this.onKeyboardClosed();
});
this.bRef.afterOpened().subscribe(() => {
this.isShow = true;
this.onKeyboardOpened && this.onKeyboardOpened();
});
}
changeKeyboardType(type: 'num' | 'default') {
let layout;
if (type == 'num') {
if (this.inputMode = 'zh-cn') {
this.changeInputMode();
}
layout = {
default: ["1 2 3", "4 5 6", "7 8 9", ". 0 {bksp}", "{enter}"],
}
}
else {
layout = null;
}
this.keyboard.setOptions({
layout
});
this.onKeyboardTypeChanged && this.onKeyboardTypeChanged();
}
clearKeyboardInput() {
this.value = ''
this.keyboard.clearInput();
}
keyboardHandle(onInputChanged) {
if (this.keyboard) {
this.keyboard.clearInput();
this.value = '';
this.onInputChanged = onInputChanged;
}
}
destroyKeyboard() {
if (!this.isShow) {
return;
}
this.svr.dismiss();
this.isShow = false;
this.onInputChanged = null;
this.onInputModeChanged = null;
this.bRef = null;
this.inputMode = 'en';
this.onKeyboardClosed && this.onKeyboardClosed();
}
getFromLocalStorage<T>(key): T {
let result;
let r = localStorage.getItem(key);
try {
result = JSON.parse(r);
}
catch (error) {
result = r;
}
return result;
}
changePosition(element: HTMLElement, container) {
const positionY = element.offsetTop;
const bodyHeight = document.documentElement.clientHeight;
if (positionY + 400 > bodyHeight) {
container.nativeElement.style.paddingBottom = '500px';
}
container.nativeElement.scrollTop = element.offsetTop;
}
resetPosition(container) {
container.nativeElement.style.paddingBottom = '0px';
}
}
现在贴上使用方法 在其他页面中找一个input,给个点击事件
<input matInput placeholder="LDC IP地址" formControlName="ip" (click)="showOrHiddeKeyboard()">
// 键盘的占位符,当然你也可以不要
<div style='height:400px' *ngIf="keyboardShow" #keyboardPadding></div>
ts中最重要的就是初始化时
keyboardShow: boolean;
conectLDCFormGroup = new FormGroup({
"ip": new FormControl(this.value, Validators.required),
});
@ViewChild('keyboardPadding') keyboardPadding: ElementRef;
constructor(
private bottomSheet: MatBottomSheet,
public keyboardSvr: KeyboardService,
private changeRef: ChangeDetectorRef,
) { }
ngOnInit(): void {
// 注册
this.keyboardSvr.registContainer(this.bottomSheet, KeyBoardBottomSheet);
// 订阅的键盘打开时
this.keyboardSvr.onKeyboardOpened = () => {
this.keyboardShow = true;
this.changeRef.detectChanges();
setTimeout(() => {
this.keyboardPadding.nativeElement.scrollIntoView();
}, 100);
}
// 键盘关闭时
this.keyboardSvr.onKeyboardClosed = () => {
this.keyboardShow = false;
}
}
最后就是给出处理键盘的方法了,这里面获取键盘传过来的值
showOrHiddeKeyboard() {
if (this.keyboardSvr.isShow) {
this.keyboardSvr.destroyKeyboard();
}
else {
this.keyboardSvr.showKeyboard('num');
this.keyboardSvr.keyboardHandle(
(input: string, key: string) => {
if (key == '{enter}') {
this.btnOk();
}
else {
// 就是在这里接收的值
this.conectLDCFormGroup.patchValue({ 'ip': input });
}
}
);
}
}