登录、注册、找回密码是前端项目经常遇到的需求。
光标自动定位到输入框、回车登录、图形验证码、邮箱验证码、60秒倒计时、字段校验、字段提示语、上传头像、密码显示隐藏这些功能都会在本文中详细介绍,【注意】使用的ui库是antd
目录
光标自动定位到输入框
回车登录
图形验证码
邮箱验证码
60秒倒计时
邮箱字段校验和字段提示语
上传头像
密码显示隐藏
截图
项目源代码
光标自动定位到输入框
使用autoFocus属性
<Input
addonBefore="邮箱/账号"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="邮箱/账号"
className="m-login-input"
autoFocus
/>
回车登录
<Input
addonBefore="验证码"
value={code}
maxLength={6}
onChange={(e) => setCode(e.target.value)}
onKeyUp={(e) => handleEnter(e)}
placeholder="验证码"
className="m-login-input"
/>
const handleEnter = (e) => {
if (e.keyCode === 13) {
handleLogin()
}
}
图形验证码
<div className="m-login-row">
<Input
addonBefore="验证码"
value={code}
maxLength={6}
onChange={(e) => setCode(e.target.value)}
onKeyUp={(e) => handleEnter(e)}
placeholder="验证码"
className="m-login-input"
/>
</div>
<div className="m-login-row">
<div
className="m-ai-login-code"
onClick={getCaptcha}
dangerouslySetInnerHTML={{ __html: captcha }}
></div>
</div>
const getCaptcha = () => {
Api.h5.userCaptcha({}).then((res) => {
if (res.code === 200) {
const { captchaId, captcha } = res.data
setCaptcha(captcha)
setCaptchaId(captchaId)
}
})
}
邮箱验证码
<Form.Item
label=""
name="username"
rules={[
{
required: true,
message: '请输入邮箱!',
},
{
validator: (e, value) => checkEmail(e, value),
},
]}
>
<Input
addonBefore="邮箱"
addonAfter={
<Popover
placement="left"
title={'提示'}
content={'某些用户的邮件会发送到垃圾箱'}
trigger="click"
>
<Icon
name="help"
className="m-ai-register-addon-after"
></Icon>
</Popover>
}
onPressEnter={(e) => e.preventDefault()}
/>
</Form.Item>
60秒倒计时
<Form.Item
label=""
name="emailCode"
rules={[
{
required: true,
message: '请输入邮箱验证码!',
},
{
len: 6,
message: '邮箱验证码为6位',
},
]}
>
<Input
addonBefore="邮箱验证码"
addonAfter={
<div>
<Button
type="link"
size="small"
disabled={isSendEmail}
className="m-ai-register-send-email-btn"
onClick={handleSendEmail}
>
{isSendEmail ? (
<span>{count}秒后重新发送</span>
) : (
<span>发送</span>
)}
</Button>
</div>
}
onPressEnter={(e) => e.preventDefault()}
/>
</Form.Item>
const handleSendEmail = () => {
const username = form.getFieldValue('username')
if (regExp.test(username)) {
Api.h5.userSendEmailCode({ username }).then((res) => {
if (res.code === 200) {
setEmailId(res.data.emailId)
message.success(res.message)
setCount(process.env.REACT_APP_MODE === 'dev' ? 6 : 180)
setIsSendEmail(true)
}
})
} else {
message.info('请输入正确的邮箱')
}
}
useEffect(() => {
clearTimeout(timer)
timer = setTimeout(() => {
if (count > 1) {
setCount(count - 1)
} else {
setIsSendEmail(false)
}
}, 1000)
// eslint-disable-next-line
}, [count])
邮箱字段校验和字段提示语
<Form.Item
label=""
name="username"
rules={[
{
required: true,
message: '请输入邮箱!',
},
{
validator: (e, value) => checkEmail(e, value),
},
]}
>
<Input
addonBefore="邮箱"
addonAfter={
<Popover
placement="left"
title={'提示'}
content={'某些用户的邮件会发送到垃圾箱'}
trigger="click"
>
<Icon
name="help"
className="m-ai-register-addon-after"
></Icon>
</Popover>
}
onPressEnter={(e) => e.preventDefault()}
/>
</Form.Item>
let regExp = /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/
const checkEmail = (e, value) => {
//let regExp = /\w+[@][a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)/
if (regExp.test(value)) {
return Promise.resolve()
} else {
return Promise.reject(new Error('请输入正确的邮箱'))
}
}
上传头像
<Form.Item label="头像" name="avatar">
<UploadImgToCNDMobile
type={'edit'}
imgDir={`img/userAvatar`}
filePrefix={'m=register'}
uploadType={2}
></UploadImgToCNDMobile>
</Form.Item>
import React, { useState } from 'react'
import { ImageUploader, Dialog } from 'antd-mobile'
import { v4 as uuidv4 } from 'uuid'
import {
imageUrlFormat,
uploadImgGetTokenFromLocalStorage,
uploadGetTokenFromLocalStorageForH5,
} from '../../utils/tools'
import urls from '../../api/urls'
import axios from 'axios'
export default function UploadImgToCND({
value = '',
msg,
type = 'add',
onChange,
accept = '.jpg,.png,.jpeg',
imgUrlCnd,
imgDir = 'img',
filePrefix = '',
uploadType = 1,
}) {
const imageUrl = imageUrlFormat(imgUrlCnd)
let defaultValue = {
uid: '-1',
name: imageUrl,
status: 'done',
url: imageUrl,
}
const [fileList, setFileList] = useState(value ? [defaultValue] : [])
const mockUpload = async (file) => {
const uid = uuidv4()
const reslutIndex = Array.from(file.name).findLastIndex(
(item) => item === '.'
)
const fileName = uid + file.name.slice(reslutIndex, file.name.length)
let token
if (uploadType === 1) {
token = uploadImgGetTokenFromLocalStorage()
} else if (uploadType === 2) {
token = uploadGetTokenFromLocalStorageForH5()
} else {
token = uploadImgGetTokenFromLocalStorage()
}
const data = new FormData()
data.append('file', file)
data.append(
'key',
`${imgDir}/${filePrefix ? filePrefix + '-' : ''}${fileName}`
)
data.append('fname', fileName)
data.append('token', token)
await axios({
url: urls.light.uploadToCDN,
method: 'post',
data,
}).then((res) => {
if (res.data.code === 200) {
typeof onChange === 'function' && onChange(res.data.data.key)
}
})
return {
url: URL.createObjectURL(file),
}
}
return (
<span>
{type !== 'check' ? (
<ImageUploader
value={fileList}
onChange={(info) => {
if (Array.isArray(info) && info.length === 0) {
typeof onChange === 'function' && onChange(undefined)
}
console.log(info)
setFileList(info)
}}
upload={mockUpload}
maxCount={1}
onDelete={() => {
return Dialog.confirm({
content: '是否确认删除',
})
}}
/>
) : value ? (
<img src={imageUrl} alt={imageUrl} className="m-upload-img-check"></img>
) : null}
</span>
)
}
密码显示隐藏
<Input.Password
addonBefore="密码"
value={password}
type="password"
onChange={(e) => setPassword(e.target.value)}
onKeyUp={(e) => handleEnter(e)}
placeholder="密码"
className="m-login-input"
/>
截图
项目源代码
https://github.com/xutongbao/learn-chatgpt
有问题可以评论区讨论