移動端拉起手機數字鍵盤,只容許用戶輸入數字和小數點?

你們在作移動端開發的時候,想必必定會遇到拉起系統自帶的鍵盤吧。最近接到需求, 想要拉起數字的鍵盤,只容許用戶輸入數字和小數點,並且在用戶失去焦點的同時,將輸入框的內容進行千分位,聚焦的時候還能夠刪除。 看似幾個需求,但還真很差整。針對此需求,筆者考慮了三種方案,建議選擇第二種(簡單粗暴),由於第一種真的是在浪費生命,它會給你無盡的深淵~css

廢話很少說,先來分析一波。react

  • 拉起數字鍵盤,那麼input框的type值爲number
  • 禁止用戶輸入除數字、小數點其餘異樣字符,正則替換
  • 輸入框的內容千分位,eg: 1,000.00。失去焦點,將內容格式化,字符串類型,那麼type值爲text
  • 聚焦的時候,還必須調起來的是數字鍵盤,因此改變type的類型爲number,在把千分位的內容換成數字

以上是實現這個的具體思路,接下來就迎接各大機型的兼容性問題吧,放心,會讓你開心到飛起。web

第一種方案(先上代碼,再來分析)

input.tsxbash

import React from 'react'
import {Images} from "config/index";
import './style.scss'
interface Props {
    isFormat?: Boolean,
    isShowAll?: Boolean,
    val?: any,
    handleFormat: Function,
    handleChange?: Function,
    handleDel?: Function,
    handleAll?: Function,
    placeholder?: any,
    small?: any
    isShowDelIcon?: Boolean,
    disabled?: Boolean
}
export default class BcInputMoney extends React.Component<any, any>{
    constructor(props) {
        super(props)
        this.state = {
            inputType: 'number' // 初始是number類型
        }
    }
    handleChange = (e) => {
        let val = e.target.value
        // 動態替換異樣字符
        val = val.replace(/^\D*(\d*(?:\.\d{0,2})?).*$/g, '$1').replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3')
        val = val.replace(/[^\d.]/g, '').replace(/\.{2,}/g, '.').replace('.', '$#$').replace(/\./g, '').replace('$#$', '.').replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3').replace(/^\./g, '')
        this.props.handleChange(e, val)
    }
    handleDel = () => {
        const { isFormat } = this.props
        if (isFormat) { // 表示須要格式化
            this.setState({
                inputType: 'number'
            })
        }
        this.props.handleDel()
    }
    handleAll = () => {
        this.props.handleAll()
    }
    handleBlur = () => {
        const { isFormat, val } = this.props
        if (isFormat && val) { // 表示須要格式化
            if (val <= 999) { 
            // 由於 999.00 格式化的時候 和 不格式化的時候 值是一致的,因此動態改變成text的時候第一次拉不起鍵盤
                this.setState({
                    inputType: 'number'
                })
            } else {
                this.setState({
                    inputType: 'text'
                })
            }
            this.props.handleFormat('blur')
        }
    }
    handleFoucs = () => {
        const { isFormat, val } = this.props
        if (isFormat && val) { // 表示須要格式化
            this.setState({
                inputType: 'number'
            })
            this.props.handleFormat('focus')
        }
    }
    render() {
        const { isShowAll, val, placeholder, small, isShowDelIcon = true, disabled = false, type } = this.props
        let { inputType } = this.state
        return (
            <div className="bc-money-input-box">
                <span className="unit">¥</span>
                <div className="inputs">
                    <input 
                        pattern="[0-9]*"
                        className={"money-input " + (small ? small : '')}
                        disabled={disabled}
                        type={inputType} 
                        value={ val == null ? '' : val } 
                        placeholder={ placeholder ? placeholder : '請輸入金額'} 
                        onBlur={this.handleBlur} 
                        onFocus={this.handleFoucs}
                        onChange={this.handleChange}/>
                    </div>
                <div className={`del-img ${isShowDelIcon ? '' : 'hidden'}`} onClick={ this.handleDel }>
                    <img src={Images.delIcon} alt="" width="16" height="17"/>
                </div>
                <div className={`all ${isShowAll ? '' : 'hidden'}`} onClick={ this.handleAll }>所有</div>
            </div>
        )
    }
}
複製代碼

style.scssflex

.bc-money-input-box{
    background: #FFFFFF;
    min-height: px2rem(38);
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-family:PingFangSC-Regular;
    font-weight:400;
    margin-left: px2rem(15);
    .unit{
        padding-right: px2rem(10);
        font-size: px2rem(22);
        color:rgba(51,51,51,1);
        width: px2rem(12);
    }
    .inputs{
        flex: 1;
        .money-input{
            height: px2rem(38);
            width: 100%;
            border: none;
            outline: none;
            box-sizing: border-box;
            font-size: px2rem(24);
            font-family:PingFangSC-Medium;
            font-weight:500;
            color:rgba(51,51,51,1) !important;
            background: transparent;
        }
    }
    .del-img{
        width: px2rem(20);
        height: px2rem(38);
        margin-right: px2rem(10);
        display: flex;
        align-items: center;
    }
    .all{
        width: px2rem(35);
        margin-left: px2rem(-4);
        padding-right: px2rem(15);
        font-size: px2rem(16);
        color:rgba(80,140,238,1);
        line-height: px2rem(38);
    }
    .hidden{
        display: none;
    }
}
.money-input::-webkit-input-placeholder {
    font-size: px2rem(24);
    font-family:PingFangSC-Regular;
    display: flex;
    line-height:normal;
    align-items: center;
    color:rgba(153,153,153,1);
    background: transparent;
    transform: translate(0, 0);
    -ms-transform:translate(0, 0); 	/* IE 9 */
    -moz-transform:translate(0,0);	/* Firefox */
    -webkit-transform:translate(0, 0); /* Safari 和 Chrome */
    -o-transform:translate(0, 0);
}
.s::-webkit-input-placeholder {
    font-size: px2rem(16);
    line-height: px2rem(38);
    font-family:PingFangSC-Regular;
    color:rgba(153,153,153,1);
    background: transparent;
    transform: translate(0, 0);
    -ms-transform:translate(0, 0); 	/* IE 9 */
    -moz-transform:translate(0,0);	/* Firefox */
    -webkit-transform:translate(0, 0); /* Safari 和 Chrome */
    -o-transform:translate(0, 0);
}
複製代碼

頁面中使用該組件的方法ui

import React from 'react'
import {observer, inject} from 'mobx-react'
import { BcButton, BcInputMoney } from 'container/index'
import help from 'utils/Tool'
@inject('store')
@observer
export default class Demo extends React.Component<any, any> {
    state = {
        money: ''
    }
    changeMoney = (e, val) => { // 子組件調用的方法
        this.setState({
            money: val
        })
    }
    FormatMoney = (type) => { // 格式話當前的內容
        let { money } = this.state
        if (money.indexOf('.') == money.length - 1) {
            money = money.replace('.', '')
        }
        if (type == 'focus') {
            this.setState({
                money: help.clearComma(money)
            })
        }
        if (type == 'blur') {
            this.setState({
                money: help.formatNum(money.toString())
            })
        }
    }
    delMoney = () => { // 清空當前值
        if (this.state.money) {
            this.setState({
                money: ''
            })
        }
    }
    render () {
       let { money } = this.state
       return (
           <div className="box">
               <BcInputMoney
                isFormat={true}
                isShowDelIcon={money}
                isShowAll={false}
                val={money}
                handleDel={this.delMoney}
                handleChange={this.changeMoney}
                handleFormat={this.FormatMoney}
                placeholder={'請輸入充值金額'} />
                <BcButton className="recharge">充值</BcButton>
           </div>
       )
   }
}
複製代碼

以上呢就是組件之間的通訊,你們花下心思必懂,給你們說下如下代碼存在的問題。this

iOS

  1. 單純的type值拉起數字鍵盤是能夠的,可是在格式化完內容以後,在拉起鍵盤去修改輸入框的內容的時候,拉起來的是英文26鍵,因此加上這個 pattern="[0-9]*",可是弊端是沒有小數點。
  2. 輸入框的內容進行回刪,光標的位置回錯亂,緣由就是在輸入的時候,針對異樣字符替換。
  3. 能夠往輸入框裏面輸入+-符號。

Android

錘子spa

  1. 用戶輸入錯誤字符會被置空(change的時候針對異樣字符替換爲‘’)

華爲code

  1. 回刪光標的位置回退倒最後一位
  2. 輸入小數點的時候光標錯亂
  3. 輸入異樣字符內容置空,必須在末位
  4. 在中間輸入異樣字符,光標位置錯亂

小米、vivoorm

  1. 輸入異樣字符內容置空,必須在末位
  2. 在中間輸入異樣字符,光標位置錯亂

這只是針對幾個問題作出來的處理。再次細化安卓各類的機型,問題想必也不會少,因此別浪費生命啦~

第二種方案。

咱們能夠轉換一種思路,第一種咱們一直在input上作事情,作完可能這個機型能夠,另外一個機型又是另外一種問題,因此咱們 可不能夠把側重點放在輸入完內容以後點擊的按鈕上,輸入完內容,用戶確定操做按鈕下一步操做,咱們在這裏攔截是否符合咱們的規範 ,不用考慮兼容問題,咱們開發也方便,更況且輸入錯誤的格式的用戶也應該很少。

上代碼(同上,就是添加下一步按鈕的事件,把input的change事件的替換正則的給幹掉)

let { money } = this.state
    const regMoney = /(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/ // 金錢
    const fixedTwo =  /^\d*(\.?\d{0,2})/g // 輸入框對金額限制小數點後兩位
    let val = help.clearComma(money)
    if (regMoney.test(val) && fixedTwo.test(val)) {
        console.log('舒適提示,您輸入的內容格式有誤')
    } else {
        console.log('輸入框的內容格式正確,下一步吧')
    }
複製代碼

第三種方案。

脫離了需求的軌跡,不在動態改變input的type值,上來就是text,這樣存在的問題少,可是就是拉起鍵盤的是英文鍵盤。代碼同上,把input的type值寫死就好。咱們目前採用的方案就是這種。

以上呢,是在寫這個東西踩的坑,閱讀的童靴若有用,請點個小贊再走唄。若有錯誤,歡迎指正。

相關文章
相關標籤/搜索