H5实现4位验证码输入框思路

1、效果图

最终实现效果:
1

2、实现过程
第一版本
<Flex className="login-code">
    <Flex.Item>
        <InputItem
            type="number"
            className="input1"
            maxLength={1}
            value={codearr[0]}
            onChange={value => {
                console.log("onChange", value)
                codearr[0] = value;
                this.dispatch({ type: "input", data: { codearr: codearr, random: Math.random() } });
                this.moveNext.bind(this, value, 1)();
            }}
        />
    </Flex.Item>
    <Flex.Item>
        <InputItem
            type="number"
            className="input2"
            maxLength={1}
            value={codearr[1]}
            onChange={value => {
                codearr[1] = value;
                this.dispatch({ type: "input", data: { codearr: codearr, random: Math.random() } });
                this.moveNext.bind(this, value, 2)();
            }}
        />
    </Flex.Item>
    <Flex.Item>
        <InputItem
            type="number"
            className="input3"
            maxLength={1}
            value={codearr[2]}
            onChange={value => {
                codearr[2] = value;
                this.dispatch({ type: "input", data: { codearr: codearr, random: Math.random() } });
                this.moveNext.bind(this, value, 3)();
            }}
        />
    </Flex.Item>
    <Flex.Item>
        <InputItem
            type="number"
            className="input4"
            maxLength={1}
            value={codearr[3]}
            onChange={value => {
                codearr[3] = value;
                this.dispatch({ type: "input", data: { codearr: codearr, random: Math.random() } });
                this.moveNext.bind(this, value, 4)();
            }}
        />
    </Flex.Item>
</Flex>
moveNext(value, index) {
    console.log(value, value.length)
    if (value && value.length) {
        setTimeout(() => { // 解决iOS不能自动跳转
            $(`.input${index + 1} input`).focus();
        })
        this.checkSend();
    } else {
        setTimeout(() => { // 解决iOS不能自动跳转
            $(`.input${index - 1} input`).focus();
        })
    }
}

大致思路是创建四个input,输入后跳转下一个input中并主动聚焦输入框.

缺点:删除时不能做到流畅退格删除

第二版本
  .key-input {
    width: 100%;
    height: 50px;
    line-height: 50px;
    padding: 0 4px;
    letter-spacing: 49px;
    box-sizing: border-box;
    text-indent: 21px;
    appearance: none;
    border: transparent;
    font-size: 18px;
    color: transparent;
    text-shadow: 0 0 0 #02b8cd;
  }

使用一个输入框,限制输入框输入长度为4并使用样式调整字体间间距模拟类似输入框

缺点: 当输入至第4位后光标会继续往下跳只是不能输入,无法主动控制光标不跳转,后面想着第四位后主动取消input聚焦输入,依然会出现光标引起的样式问题.

第三版本
import React from "react";

import { Toast, WingBlank } from "antd-mobile";

import { template, ViewComponent, Validators, setEventWithLabel } from "@reco-mobile/core";
import { Namespaces } from "@reco-mobile/auth-models";

import { statisticsEvent } from "@reco-mobile/statistics";

import { Countdownauto } from "./countdownauto"

export namespace Code {
    export interface IProps extends ViewComponent.IProps { }

    export interface IState extends ViewComponent.IState {
        viewRef?: any;
    }

    export class Component<P extends IProps = IProps, S extends IState = IState> extends ViewComponent.Base<P, S> {
        showloading = true;
        namespace = Namespaces.login;
        showloadingContent = "登录中";
        inputRef;
        componentWillUnmount() {
            this.dispatch({ type: "input", data: { codestr: null } });
        }
        componentDidMount() {
            this.dispatch({ type: "hideLoading" });
            this.inputRef.focus()
        }
        tranformClass(index) {
            for (let i = 0; i < 4; i++) {
                if (i + 1 === index) {
                    $(`#cursorspan${i + 1}`).addClass("cursorspan");
                } else {
                    $(`#cursorspan${i + 1}`).removeClass("cursorspan");
                }
            }
        }
        renderHeader(): JSX.Element | null {
            return (
                <>
                    <div className="header-bodernone">{super.renderHeader()}</div>
                </>
            );
        }
        loginNameValidator() {
            const { cellphone, required, composeControl } = Validators,
                { state } = this.props;
            return composeControl([required, cellphone], { value: state!.get("loginName"), name: "手机号码" });
        }
        validator() {
            const { required, maxLength, minLength, composeControl, ValidatorControl } = Validators,
                { state } = this.props;

            return ValidatorControl(
                this.loginNameValidator(),
                composeControl([required, maxLength(4), minLength(4)], {
                    value: state!.get("password"),
                    name: "验证码"
                })
            );
        }

        login() {
            const msg = this.validator()!();

            if (msg) {
                Toast.fail(msg.join(), 1);
                return;
            }
            this.dispatch({ type: "input", data: { loading: true } });
            this.dispatch({
                type: "submit",
                error: e => Toast.fail(e.errmsg),
                callback: () => {
                    Toast.success("登录成功", 1);
                }
            });
            setEventWithLabel(statisticsEvent.c_app_Myself_verificationCodeLogin); // 验证码登录
        }

        sendVerifyCode(delay: Function) {
            const { state } = this.props;

            this.dispatch({
                type: "sendVerifyCode",
                data: { username: state!.get("loginName") },
                delay
            });
        }

        checkSend(codestr) {
            if (codestr && codestr.length === 4) {
                this.dispatch({ type: "input", data: { password: codestr } });
                setTimeout(() => {
                    this.login();
                });
            }
        }
        renderBody(): JSX.Element | null {
            const { state } = this.props,
                codestr = state!.get("codestr");
            return (
                <>
                    <WingBlank>
                        <div className="login-title">输入手机验证码</div>
                        <div className="keyboard-input">
                            <input
                                type="tel"
                                ref={(e) => this.inputRef = e}
                                // className="key-input"
                                onTouchMove={e => {
                                    e.preventDefault();
                                }}
                                maxLength={4}
                                onChange={(event) => {
                                    let value = event.target.value;
                                    // alert(value);
                                    // console.log(value);
                                    this.dispatch({ type: "input", data: { codestr: value } });
                                    this.checkSend(value);
                                    if (value.length + 1 > 4) {
                                        this.tranformClass(value.length)
                                    } else {
                                        this.tranformClass(value.length + 1)
                                    }

                                }}
                                onBlur={() => {
                                    this.tranformClass(5)
                                }}
                                onFocus={() => {
                                    if (codestr) {
                                        if (codestr.length + 1 > 4) {
                                            this.tranformClass(codestr.length)
                                        } else {
                                            this.tranformClass(codestr.length + 1)
                                        }
                                    } else {
                                        this.tranformClass(1)
                                    }
                                }}
                            />
                            <div className="keyboard-span">
                                <span />
                                <span />
                                <span />
                                <span />
                            </div>
                        </div>
                        <div className="input-yzm-box" onClick={() => {
                            this.inputRef.focus()
                        }}><span id="cursorspan1">{codestr && codestr.slice(0, 1)}</span>
                            <span id="cursorspan2">{codestr && codestr.slice(1, 2)}</span>
                            <span id="cursorspan3">{codestr && codestr.slice(2, 3)}</span>
                            <span id="cursorspan4">{codestr && codestr.slice(3, 4)}</span></div>
                        <Countdownauto start={this.sendVerifyCode.bind(this)} content="获取验证码" />
                    </WingBlank>
                </>
            );
        }
    }

    export const Page = template(Component, state => state[Namespaces.login]);
}


创建一个input和四个div,隐藏input不可见主动聚焦可输入,四个div分别映射input四位输入数字,光标闪烁也是四个div通过样式动画模拟出来的,最终完美解决.

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值