div高仿出來input,拉起高仿的數字鍵盤?

你們都知道,H5的input框,喚醒手機的鍵盤在android和ios上展示的不一樣。需求要求實現咱們這邊實現一個本身的鍵盤,無奈需求方仍是大佬,搬磚者仍是乖乖的想一想實現(筆者這邊採用的react框架,因此採用了antd mobile組件庫)css

首先要實現一個鍵盤,你們的思路是怎麼樣的呢?

  • 用li循環唄,9鍵出來。
  • 用div模擬input + 光標。

第一個非常簡單,用組件庫的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)}>&#xe602;</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

  1. placeholder的存在?
  2. 一閃一閃的光標存在?光標具體存在的位置?
  3. 他的點擊事件?(沒有拓展失焦、聚焦功能)?

說一下個人具體思路把。數組

  • 初始我在input框裏沒有任何內容的時候,我用僞類來實現的光標的存在。(css動畫)
  • 就是input框的內容我任意點擊光標的位置改變,採用的是每個數字我都是一個span,點擊會拿取下標,在添加空的span再來實現光標。
  • 我用'only'作的惟一標示,讓我更有利的判斷。
  • 關閉彈窗的時候,我這個input的span都要刪掉,也就是將數組清空。

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

相關文章
相關標籤/搜索