如何实现一个移动端美观的验证码输入界面?

前言

平常我们在使用一个移动端app的时候,很多场景下都要用到验证码相关的功能,常见的就是一个input输入框加些样式,然后直接把收到的验证码填入即可。

为了提高用户体验,这次我们就来手动实现一个好看一些的验证码输入界面,效果图如下:


实现步骤如下:

创建元素

<div class="container">
    <span>输入验证码</span>
    <span>验证码已发送到<span class="phone">+86 191*******121</span></span>
    <div class="codeBox">
        <div class="codeItem active"></div>
        <div class="codeItem"></div>
        <div class="codeItem"></div>
        <div class="codeItem"></div>
        <input type="text" class="codeInput" maxlength="4" />
    </div>
    <a>重新获取验证码</a>
</div>

定义样式

<style>
    * {
        box-sizing: border-box;
    }

    a {
        text-decoration: none;
    }

    .container {
        display: flex;
        flex-direction: column;
        align-items: center;
        padding-top: calc(150 / 3.75 * 1vw);
    }

    .codeBox {
        width: calc(250 / 3.75 * 1vw);
        display: flex;
        justify-content: space-between;
        position: relative;
        margin-bottom: calc(50 / 3.75 * 1vw);
    }

    .codeItem {
        width: calc(50 / 3.75 * 1vw);
        height: calc(50 / 3.75 * 1vw);
        font-size: calc(24 / 3.75 * 1vw);
        text-align: center;
        line-height: calc(50 / 3.75 * 1vw);
        border: calc(1 / 3.75 * 1vw) solid #ccc;
        border-radius: calc(10 / 3.75 * 1vw);
        transition: all 0.2s linear;
        position: relative;
    }

    .codeInput {
        width: 100%;
        height: 100%;
        position: absolute;
        opacity: 0;
    }

    .container span:nth-child(1) {
        font-size: calc(20 / 3.75 * 1vw);
        margin-bottom: calc(10 / 3.75 * 1vw);
    }

    .container span:nth-child(2) {
        font-size: calc(12 / 3.75 * 1vw);
        margin-bottom: calc(30 / 3.75 * 1vw);
    }

    .container :last-child ,.container span .phone{
        font-size: calc(12 / 3.75 * 1vw);
        color: rgb(105, 161, 230);
    }

    .active {
        border: calc(3 / 3.75 * 1vw) solid rgb(105, 161, 230);
    }

    /* 闪烁光标的样式 */
    .codeItem.active::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: calc(2 / 3.75 * 1vw);
        /* 光标的宽度 */
        height: calc(24 / 3.75 * 1vw);
        /* 光标的高度 */
        background-color: black;
        animation: blink 1s step-end infinite;
    }

    /* 闪烁动画 */
    @keyframes blink {
        50% {
            opacity: 0;
        }
    }
</style>

现在完成了静态模板,下面就实现交互逻辑


 实现的思路:

codeBox中的4个div模拟的是4个输入框,真实的input输入框其实是隐藏起来的,这样方便做样式处理

在input输入框中输入内容时,通过计算给对应位置的div加激活样式,并把input中的内容展示到这些div的内容中

 1、获取dom元素

首先要获取这4个div元素和输入框元素,并且加载页面自动聚焦到inputBox

//4个div输入框元素
const codeItems = document.querySelectorAll(".codeItem");

//真正的输入框元素
const inputBox = document.querySelector(".codeInput");

//进入页面输入框就自动聚焦
inputBox.focus();

2、绑定事件

要实现输入后的效果,输入框事件少不了,给inputBox添加input事件

inputBox.addEventListener("input", (e) => {

    //切换激活样式方法
    changeActiveItem();

    //更新div输入框的内容
    updateCodeItem();

    //输入完成发送校验请求
    if (inputBox.value.length === 4) {
        //sendCode();
    }

});

 这里的codeItems是一个NodeList,原型链上有forEach方法

function changeActiveItem() {
    //先清除带有active样式的div输入框
    codeItems.forEach((item) => {
        item.classList.remove("active");
    });

    //根据输入框里内容的长度length,来计算当前所在div的索引位置,并加上样式
    //首先获取输入框字符串长度
    const inputValue = inputBox.value.length;

    // 如果输入框没内容,就默认给第一个div加active样式
    if (inputValue === 0) {
        codeItems[0].classList.add("active");
    }

    //判断字符串是否为空并且<4个字符,否则,删空内容或中文输入的时候索引会超出,导致报错
    if (inputValue && inputValue < 4) {
        codeItems[inputValue].classList.add("active");
    }

    
}

function updateCodeItem() {
    // 拿到实际input输入框的内容
    const arrCode = inputBox.value;
    // 遍历每一个div输入框元素,根据索引给元素的innerText赋值
    codeItems.forEach((item, index) => {
        // 一开始输入,其他验证框就会变成undefined,因为arrCode此时长度没到4,遍历后面的索引会超出范围
        arrCode[index] ? item.innerText = arrCode[index] : item.innerText = "";
    });
}

出现的问题: 

1、能输入汉字

到这里似乎没啥问题了,可以正常输入,样式也会相应地变化了,但是有个小问题,验证码框里居然能输入汉字,接下来继续进行改造完善。

2、包含数字和字母

既然要求不能输入汉字,那我直接在input的属性里加上 type="number"就行了嘛。但是有些验证码要数字和字母结合咋办呢。


解决:要对input输入的汉字进行实时过滤,可以用正则表达式+replace方法。

回到input输入框的input事件中,加上这样一行,这样就基本上完成了页面逻辑了,后续可以再进行逻辑优化。

inputBox.addEventListener("input", (e) => {
    //把输入的文本替换成空字符串,否则结束中文输入时,输入框内容会有汉字
    e.target.value = e.target.value.replace(/[^\x00-\xff]/g, "");

    //执行代码
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值