首页 > 其他分享 >实用功能分享,弹窗展示形式的6位卡号输入功能实现【玩转业务功能】

实用功能分享,弹窗展示形式的6位卡号输入功能实现【玩转业务功能】

时间:2023-12-04 12:31:24浏览次数:27  
标签:弹窗 实用功能 value let 输入 卡号 input 光标

前言

本篇主要分享如何实现一个弹窗展示形式的6位卡号输入功能。

6位卡号输入

前面是根据卡的不同状态的流程实现,接下来,讲讲卡号输入的交互实现。

卡号输入 UI

UI 的呈现,会影响前端的实现方式。这里 UI 设计成弹出层的方式,每个数字都是一个方框。

实用功能分享,弹窗展示形式的6位卡号输入功能实现【玩转业务功能】_数字输入弹窗

开发前

在开发前,我列了一些可能出现的问题。比如,不同手机的光标样式、输入时页面抖动、input无法只输入数字等。

所以我在实现的时候,有针对性的规避前面罗列的问题。

功能设计

功能点

首先我罗列了一下主要的功能点,包含了前面提到的问题的规避:

1、唤起手机数字软键盘,只允许输入数字

2、卡号限制6位

3、可删除,删除后光标自动前移,直到第一位

4、重置光标样式

光标样式是浏览器自带样式,考虑重置生效的兼容性和不同浏览器的兼容性

5、光标自动后移

单一的input输入框设计,防止页面抖动

实现

1、唤起手机数字软键盘,只允许输入数字

一般我们将 input 输入框设置为 type='number',此时便只能输入数字了。

但是这个设置在IOS下是不起作用的,即便我又加了pattern="[0-9]*",也还是能输入e、+、-等符号,这个时候,就只需要上正则了。

正则判断数字类型,如果不满足,则将输入值重置为空。

let value = e.target.value;
let regExp = /^[0-9]+$/;
if (!regExp.test(value)) {
  value = '';
}

2、卡号限制6位,光标自动后移

输入框设置为 type='number,maxLength设置值是不会生效的。(如果我没记错的话,只有type='tel',会生效)

所以光标移到最后,如果不做特殊处理,输入框可以一直输入值。

于是我将最后的值做了截取,只保留前6位。

// 卡号数组
let [carmiList, setCarmiList] = useState([]); 
// 光标所在位置
let [currIndex, setCurrIndex] = useState(1);

// 只允许输入单个数字
if (value > 10) {
  value = value.slice(0, 1);
}

// 收集6位卡号
if (currIndex <= 6) {
  carmiList.push(value); 
}

// 当光标到达第6个方框时,卡号只取前面6位
if (currIndex >= 6) {
  nativeInputRef.current.value = value;
  carmiList = carmiList.slice(0, 6);
  setCarmiList([...carmiList]);
  return;
}

3、删除操作

通过监听删除键,处理删除功能。keyCode 的值为8时,表示点击了删除键。

如果此时光标在第一个方框,则清空全部卡号。

如果光标不在第一位,则将卡号数组移除一位,得到新的卡号值,同时光标减去1,得到新的光标位置。

const isBackSpaceKey = e.keyCode === 8;
if (isBackSpaceKey) {
  if (currIndex <= 1) {
    setCarmiList([]);
    setCurrIndex(1);
  } else {
    carmiList.pop();
    let newValue = carmiList.slice();
    setCarmiList([...newValue]);
    setCurrIndex(currIndex - 1);
  }
}

4、重置光标样式

caret-color:设置 input 元素中光标的颜色。

::first-line:用来指定选择器第一行的样式。caret-color 无法改变 IOS 的光标颜色,所以又设置了 ::first-line 选择器的颜色用来兼容 IOS。

input {
  caret-color: goldenrod;
  outline: none; 
  &:focus{
    border-color: goldenrod;
  }
  // 兼容Safari
  &::first-line {
    color: goldenrod;
  }
}

5、光标自动后移

为了防止抖动,所以我只保留了一个 input 输入框,通过光标位置更换 input 输入框展示的位置。

<div className='card'>
  {carmiList.map((item, index) => {
    return (
      <Fragment key={index}>
        {currIndex === index ? (
          <input
            className='card-item'
            ref={nativeInputRef}
            key={index}
            id='carmiEle'
            type='number'
            pattern='[0-9]*'
            autoFocus
            autoComplete='off' // 不保存输入的数字
            maxLength='1'
            onChange={e => handleChange(e, index)}
            onKeyDown={e => handleDelete(e, index, item)}
            inputMode='numeric'
          />
        ) : (
          <div className='card-item'>{item.num}</div>
        )}
      </Fragment>
    );
  })}
</div>

躲不开的兼容性问题

测试过程,很顺利,直到 iPhone 12及以上,页面抖动的效果,「出人不意料之外」的出现了。真是令前端「闻风丧胆战心惊」的移动端兼容性

在移动端兴起以前,PC端的兼容性处理,是最令前端头疼的事情之一。但是PC端的兼容性问题,还是比较好复现的,即便开发自己的电脑没有对应的浏览器,身边人也能找到,再不济,装个虚拟机,也能满足。

但是移动端的兼容性,排查起来,就没那么容易了,手机机型的匮乏,是一个问题。另一个问题则是,移动端的环境不像PC端那么直观。

无论问题有多难,还是要解决它。

曲折的问题解决过程

这个抖动,我最开始觉得是因为页面有滚动条,所以每次输入数字之后,input失焦,又很快再次聚焦,导致页面发生了快速的滚动。所以出现了抖动。

所以开始的时候我就想方设法的不让页面产生滚动。

可能方案1

打开卡号输入弹出层的同时,将页面滚动到顶部。

/**
 * 快速定位到顶部
 */
const goTop = () => {
  document.body.scrollTop = document.documentElement.scrollTop = 0;
};

结果,该抖还是抖。

可能方案2

打开弹出层的时候,将页面设置为禁止滚动。

document.body.style.overflow = 'hidden';

结果,该抖还是抖。

可能方案3

所以说禁止页面滚动的方式无法解决问题,连暂时方案都算不上。最根本的还是解决 input 聚焦和失焦导致页面发生抖动的情况。

如果 input 一直不失焦不就行了?我感觉我可能找到了真正的解决方案。

不失焦就表示它一直是输入状态,也就是它不是被替换了而是发生了挪动,也就是说它挪到了下一个方框上。

input 输入框上设置好可移动属性,X轴的值是动态的。

style={{ transform: `translate(${cardX}px, -32px)` }}

输入操作,每次向右移动一个方框+边距的距离;

删除操作,每次向左移动一个方框+边距的距离;

// X轴移动的距离
const [cardX, setCardX] = useState(0); 
// 每次移动的距离
let [drift, setDrift] = useState(0);

// 输入操作
setCardX(cardX + drift); 

// 删除操作
setCardX(cardX - drift);

每次移动的距离,我是算出来的,因为不同手机下的值不一样。

/**
   * 获取每次移动的位移
   */
  const getDriftVal = () => {
    let contentItem = document.getElementsByClassName('content-item')[0];
    let contentClass = document.getElementsByClassName('card-content')[0];
    let itemOffsetWidth = contentItem.offsetWidth;
    let boxOffsetWidth = contentClass.offsetWidth;
    let widthDVal = boxOffsetWidth - itemOffsetWidth * 6;
    let interval = Filter.accuracyExcept(widthDVal, 5);
    drift = Filter.accuracyAdd(interval, itemOffsetWidth) || 56;
    setDrift(drift);
  };

到这,抖动的问题,终于被解决了。

总结

想要解决问题,关键还是要找到问题的本质,对症下药。

但是有时候,问题的根本原因并不是那么好找到,这需要我们日常多积累经验+不断的学习巩固。

6位卡号输入功能,该功能可能出现的兼容性问题,以及解决这些问题的思路和方案。

兼容性问题,对于前端而言,是一个「拦路虎」。能找到问题的本质,有时候并不容易,但是每一次的寻找答案的过程,都会有所收获。

本次分享的iOS系统input快速聚焦和失焦导致页面抖动的解决方式,希望能帮到每一个有需要的开发者。共勉。


作者:非职业「传道授业解惑」的开发者叶一一简介:「趣学前端」、「CSS畅想」系列作者,华夏美食、国漫、古风重度爱好者,刑侦、无限流小说初级玩家。如果看完文章有所收获,欢迎点赞

标签:弹窗,实用功能,value,let,输入,卡号,input,光标
From: https://blog.51cto.com/u_15838863/8676333

相关文章

  • vue 弹窗组件
    vue弹窗<el-dialog></el-dialog>可以在其中编写所需的弹窗显示的内容也可以在其中放组件标签作为弹窗放一个组件的话,例:<el-dialogv-model="addGoodsDialog":title="addGoodsTitle"width="60%"destroy-on-close="true":close-on-p......
  • java后端实现前端弹窗
    Java后端实现前端弹窗教程简介在这篇文章中,我将教你如何使用Java后端实现前端弹窗。我们将使用SpringBoot框架来搭建后端服务,并通过前端发送请求来触发弹窗的显示。以下是整个实现过程的流程图:erDiagram程序员-->后端:创建后端服务后端-->前端:提供API前......
  • 当多个使用弹窗类组件,可使用这种方式封装组件。(以下使用antd-vue、vue3)
    1.代码点击查看代码<template><slot:openDialog="openDialog":closDialog="modalCancel"></slot><a-modalv-model:open="open"title="BasicModal"@cancel="modalCancel"><templat......
  • 一行代码解决IE停用后无法继续使用IE弹窗功能的问题
    微软在2023年2月14日通过Edge浏览器更新,彻底封死IE。WindowsUpdate中没有记录、开始菜单中的IE以及桌面IE图标双击自动打开Edge,默认程序设置了IE也没有任何效果,仅能通过Edge浏览器设置IE模式浏览。但是之前通过这种方式使用IE最近发现无法弹窗了,而有些IE应用要求必须弹窗,在网上尝......
  • 卡号系统
    #include<iostream>usingnamespacestd;structcard{//属性stringname;intid;stringclassroom;floatmoney;stringcreat_time;boollost=true;//方法//开卡boolcreat(inti,stringn,stringc){nam......
  • van-dialog弹窗异步关闭-校验表单
    van-dialog弹窗异步关闭有时候我们需要通过弹窗去处理表单数据,在原生微信小程序配合vant组件中有多种方式实现,其中UI美观度最高的就是通过van-dialog嵌套表单实现。通常表单涉及到是否必填,在van-dialog的确认事件中直接return是无法阻止对话框关闭的,你需要通过异步关闭对话框的......
  • ElementUI的Dialog弹窗实现拖拽移动功能
    在项目中使用el-dialog中发现不能够拖拽移动,因此网上找了相关资料,使用自定义指令实现拖拽功能。1、创建自定义指令:新建文件directive/el-drag-dialog/index.jsimportdragfrom"./drag";constinstall=function(Vue){Vue.directive("el-drag-dialog",drag);};if(wind......
  • element ui 设置el-dialog2级弹窗
    步骤1,通过<el-buttontype="text"@click="dialogTableVisible=true">添加活动</el-button>弹出第一层,themeData设置成你循环的数据<el-buttontype="text"@click="dialogTableVisible=true">添加活动</el-button><!--第一层弹......
  • layui弹框提示按回车事件一直不停弹窗
    如下界面,敲回车后一直不停弹窗,确定的事件也不执行 解决问题方法:在确认事件前面加上$(':focus').blur();如下所示,问题得到解决$(':focus').blur();layer.confirm(msg,{icon:3,title:'提示',success:function(){this.enterEsc=function......
  • elementplus弹窗可拖拽draggable,点击空白处不消失close-on-click-modal,modal是否去掉
    <el-dialog:modal="false"v-model="dialogVisible"title=""width="30%"draggable:close-on-click-modal="false"class="message-dialog"></el-dialog&g......