你們都知道,H5的input框,喚醒手機的鍵盤在android和ios上展示的不一樣。需求要求實現咱們這邊實現一個本身的鍵盤,無奈需求方仍是大佬,搬磚者仍是乖乖的想一想實現(筆者這邊採用的react框架,因此採用了antd mobile組件庫)css
第一個非常簡單,用組件庫的Modal裏面嵌套咱們本身的循環唄,就這樣整唄。html
tsxreact
const numLen = [1, 2, 3, 4, 5, 6, 7, 8, 9]
export default class BcMobileKeyboard extends React.Component<any, any>{
constructor(props) {
super(props)
}
// 獲取當前點擊的數字,調用父親的方法傳遞過去
getCurNum = (num) => {
this.props.getNumber(num)
}
// 刪除當前的數字
delNum = () => {
this.props.delNumber()
}
// 點擊完成的觸發
complate = () => {
this.props.complate()
}
render () {
const { className, visible = true, maskClosable = false, animationType = 'slide-up', popup = true } = this.props
return (
<Modal
className={`key-board-box ${className}`}
popup={popup}
maskClosable={maskClosable}
visible={visible}
animationType={animationType}
>
<div className='board-top'>
<button onClick={this.complate.bind(this)}>完成</button>
</div>
<ul className="board-num">
{
numLen.map(item => {
return <li onClick={this.getCurNum.bind(this, item)}>{item}</li>
})
}
{/* 這個li單純爲了佈局,讓它佔住位置 */}
<li style={{visibility: 'hidden'}}></li>
<li className="zero" onClick={this.getCurNum.bind(this, 0)}>0</li>
{/* 刪除的icon, 若是複製須要替換這個成大家本身的icon */}
<li><i className="icon iconfont del-icon" onClick={this.delNum.bind(this)}></i></li>
</ul>
</Modal>
)
}
}
複製代碼
鍵盤的樣式android
@import 'assets/style/px2rem.scss';
.key-board-box{
overflow: hidden;
-moz-user-select:none;/*火狐*/
-webkit-user-select:none;/*webkit瀏覽器*/
-ms-user-select:none;/*IE10*/
-khtml-user-select:none;/*早期瀏覽器*/
user-select:none;
-webkit-touch-callout:none ;
-webkit-text-size-adjust:none ;
-webkit-tap-highlight-color:transparent ;
-webkit-user-select:none ;
.board-top{
height: px2rem(44);
display: flex;
justify-content: flex-end;
align-items: center;
button {
outline: none;
border: 0;
padding-right: px2rem(15);
color: #508CEE;
font-size: px2rem(18);
}
}
.board-num{
background: #D2D5DB;
overflow: hidden;
height: px2rem(216);
padding-left: px2rem(6);
li{
margin-right: px2rem(6);
margin-top: px2rem(6);
width: 31.7%;
float: left;
height: px2rem(46);
background:rgba(255,255,255,1);
box-shadow:0px 1px 0px 0px rgba(132,134,136,1);
border-radius: px2rem(5);
display: flex;
justify-content: center;
align-items: center;
font-size: px2rem(25);
font-family:Helvetica;
color:rgba(0,0,0,1);
}
.zero{
margin-bottom: px2rem(5);
}
li:last-child {
background: none;
border: none;
box-shadow: none;
.del-icon {
color: #3F434A;
}
}
}
}
複製代碼
其實主要的就是有了鍵盤, 那麼咱們的input框是否是要有啊?那就高仿一個唄?開整ios
思考問題:web
說一下個人具體思路把。數組
tsx瀏覽器
import React from 'react'
import './style.scss'
import { BcMobileKeyboard } from 'container/index'
interface Rules {
className?: string,
placeholder?: string,
isShowBoard?: boolean,
max?: number,
refs?: Function,
notifyComplate?: Function,
onRef?: any
}
export default class BcImitateInput extends React.Component<Rules, any>{
constructor(props) {
super(props)
this.state = {
curNum: [], // 用來記錄當前div裏面的全部值
selectedInd: null // 當前點擊的光標的位置
}
}
// 拿到鍵盤點擊的數字
setNumberHandle = (num) => {
let { curNum, selectedInd } = this.state
let flag = curNum.some((item) => {return item == 'only'}) // 數據存在only,就表示光標在中間存在過
let max = flag ? this.props.max + 1 : this.props.max // 光標只有一次,全部她的最大值也加1
if (curNum.length >= max) return false
if (selectedInd != null) { // 表示光標在中間存在過 增刪內容
curNum.splice(selectedInd, 0, num) // 添加內容
this.setState({
curNum,
selectedInd: selectedInd + 1 // 光標位置也隨之增長
})
} else { // 表示正常流程走下來。
curNum.push(num)
this.setState({
curNum
})
}
}
// 刪除鍵盤點擊的數字
delNumberHandle = () => {
let { curNum, selectedInd } = this.state
if (curNum.length) {
if (selectedInd - 1 >= 0) { // 表示從中間刪除內容
curNum.splice(selectedInd - 1, 1)
this.setState({
curNum,
selectedInd: selectedInd - 1 // 固然光標隨之減小
})
} else if (selectedInd == null) { // 表示正常的刪除內容
curNum.pop()
this.setState({
curNum
})
}
}
}
// 點擊鍵盤中的完成
complateHandle = () => {
let curNum = this.state.curNum
for (let i = 0; i < curNum.length; i++) {
if (curNum[i] == 'only') {
curNum.splice(i, 1)
break;
}
}
this.props.notifyComplate(curNum.join('')) // 準確的把當前的數據通知出去
}
// 高仿的input的點擊事件
inputClickHandle = (e) => {
// 這裏是爲了點擊div的任何地方 若是不在數字的中間,那麼咱們要讓光標回到最後的位置
let { curNum, selectedInd } = this.state
if (curNum.length && selectedInd != null) {
for (let i = 0; i < curNum.length; i++) {
if (curNum[i] == 'only') {
curNum.splice(i, 1)
break;
}
}
this.setState({
selectedInd: null
})
}
}
// 點擊當前的span獲取當前光標的位置
curNumHandle = (ind, e) => {
if (e) { // 爲了阻止冒泡
e.stopPropagation();
e.preventDefault();
} else {
window.event.returnValue = false;
window.event.cancelBubble = true;
}
let { curNum } = this.state
for (let i = 0; i < curNum.length; i++) {
if (curNum[i] == 'only') {
curNum.splice(i, 1)
break;
}
}
curNum.splice(ind, 0, 'only')
this.setState({
curNum,
selectedInd: ind
})
}
// 初始化數據 就是爲了關閉這個彈窗的時候,數據不能夠保留
initCodeNum = () => {
this.setState({
curNum: [],
selectedInd: null
})
}
setClass = () => {
// 這裏的class是爲了用僞類來實現一些光標
let { curNum, selectedInd } = this.state
if (selectedInd == null && !curNum.length) return 'not'
if (selectedInd != null) return ''
if (selectedInd == null && curNum.length) return 'yes'
}
render() {
const { curNum } = this.state
const { placeholder = '輸入驗證碼', className, isShowBoard } = this.props
return (
<div>
<div className={`${this.setClass()} ${className} imitate-input`} placeholder={placeholder} onClick={this.inputClickHandle}>
{
curNum.length ? curNum.map((ele, index) => {
return <span className={`${ele == 'only' ? 'yes' : ''}`}
onClick={(e) => { this.curNumHandle(index, e) }}>
{ele == 'only' ? '' : ele}
</span>
}) : ''
}
</div>
{/* 就是上文的組件 */}
<BcMobileKeyboard
visible={isShowBoard}
getNumber={this.setNumberHandle}
complate={this.complateHandle}
delNumber={this.delNumberHandle}>
</BcMobileKeyboard>
</div>
)
}
componentWillMount ():void { // 把this 傳遞父級,能夠作更多的事情
this.props.onRef(this)
}
}
複製代碼
input的樣式bash
@import 'assets/style/px2rem.scss';
.imitate-input{
display: flex;
align-items: center;
font-size:px2rem(16);
border: px2rem(1) solid #999999;
user-select:text;
-webkit-user-select:text;
.selected::after{
content:'';
display: block;
width:1px;
height:16px;
animation: 1s steps(1, start) 0s normal none infinite running blink;
}
}
.yes::after{
content:'';
display: block;
width:1px;
height:16px;
animation: 1s steps(1, start) 0s normal none infinite running blink;
}
.not:empty::before{
content:'';
display: block;
width:1px;
height:16px;
animation: 1s steps(1, start) 0s normal none infinite running blink;
}
.not:empty::after{
content: attr(placeholder);
color: #999999;
font-size:px2rem(16);
}
@keyframes blink {
0%{
background-color: white;
}
50% {
background-color: #000000;
}
100% {
background-color: white;
}
}
複製代碼
具體的代碼就是以上的實現,若有錯誤,請多指正。有更好的想法實現,歡迎評論。你們共勉~antd