使用ant design 表单组件,开发登录,注册,搜索功能
React 表单组件 ,受控组件
案列
使用defaultVlue属性
bug : 改变了数据源,但是页面未重新渲染
{/* 表单组件 */}<button onClick={()=>{console.log(text);}}>打印</button><button onClick={()=>[setText("hello"),]}>set</button>
使用value
const [text , setText] = useState("hello world");const handleChange=(e)=> {setText(e.target.value)}
--------------------------------------------<input value={text} onChange={handleChange}></input><button onClick={()=>{console.log(text);}}>打印</button><button onClick={()=>[setText("hello"),]}>set</button><button onClick={()=>[setText("hello"),]}>set</button>
总结
- 受控组件:
值同步到state,使用value属性 - 非受控组件
值不同步到state,使用default属性
常用表单组件
受控组件
import {FC} from "react";import { ChangeEvent, useState } from "react";const Demo : FC =()=>{const [text , setText] = useState<string>("hello world");const handleChange=(e : ChangeEvent<HTMLInputElement>)=> {setText(e.target.value)}//---------------------------------------------------------------------const [tarea , setTarea] = useState<string>("hello");const handleChange2=(e : ChangeEvent<HTMLTextAreaElement>)=> {setTarea(e.target.value);}function getHtml() {return {__html: tarea.replaceAll("\n", "<br>")}}//-------------------------------------------------------------------------const [gender , setGender] = useState<string>("male");const handleGeander=(e : ChangeEvent<HTMLInputElement>)=> {setGender(e.target.value)}//-------------------------------------------------------------------------const[selectdIdList,setSelectdIdList]=useState<string[]>([]);const handleSelectd=(e : ChangeEvent<HTMLInputElement>)=> {const city = e.target.value;if(selectdIdList.includes(city)){//移除setSelectdIdList(selectdIdList.filter(item=>item!==city))}else{//添加setSelectdIdList(selectdIdList.concat(city))// setSelectdIdList([...selectdIdList,city])}}//-------------------------------------------------------------------------const [lang , setLang] = useState<string>("1");const handleSelect=(e : ChangeEvent<HTMLSelectElement>)=> {setLang(e.target.value)}return (<div><h3>input 组件</h3><input value={text} onChange={handleChange}></input><button onClick={()=>{console.log(text);}}>打印</button><button onClick={()=>[setText("hello"),]}>set</button><h3>textarea 组件</h3><textarea value={tarea} onChange={handleChange2}></textarea>{/* {tarea}//没有换行 */}{/* {tarea.replaceAll("\n", "<br>")}//有xss注入的风险 */}<div dangerouslySetInnerHTML={getHtml()} />{/* 单选框 */}<h3>单选框 组件</h3>{/* 添加lable 实现点击文字也能选中效果 */}<label htmlFor="male">male</label><input type="radio" id="male" name="sex" value="male" checked={gender === "male"} onChange={handleGeander} /><label htmlFor="female">female</label><input type="radio" id="female" name="sex" value="female" checked={gender === "female"} onChange={handleGeander} />{/* 复选框 */}<h3>复选框 组件</h3><label htmlFor="1">shanghai</label><inputtype="checkbox"id="1"value="shanghai"checked={selectdIdList.includes("shanghai")}onChange={handleSelectd}/><label htmlFor="2">beijing</label><inputtype="checkbox"id="2"value="beijing"checked={selectdIdList.includes("beijing")}onChange={handleSelectd}/><label htmlFor="3">chengdu</label><inputtype="checkbox"id="3"value="chengdu"checked={selectdIdList.includes("chengdu")}onChange={handleSelectd}/>{JSON.stringify(selectdIdList)}{/* 下拉框 */}<h3>下拉框 组件</h3><select value={lang} onChange={handleSelect}><option value="1">1</option><option value="2">2</option><option value="3">3</option></select></div>)}export default Demo;
form 组件
import {FC,useState,useRef, useEffect} from 'react'const Demo:FC =()=>{const handleSubmit = (e)=>{e.preventDefault();//阻止默认行为// js 提交数据console.log(e.target.k1.value);console.log(e.target.k2.value);}return(<><h3>Form 组件</h3>{/* 点击提交会触发请求,请求的地址是:https://www.baidu.com?k1=k1&k2=k2 \提交的参数{k1:v1;k2:v2;}*/}<form action="https://www.baidu.com" method="get"><input name='k1' value='k1'/><br /><br /><input name='k2' value='k2' /><br /><br /><input type="submit" value="提交" /></form>{/* 添加onsubmit,阻止默认行为 */}<form action="https://www.baidu.com" method="get" onSubmit={handleSubmit}><input name='k1' value='k1'/><br /><br /><input name='k2' value='k2' /><br /><br /><input type="submit" value="提交" /></form></>)}export default Demo;
ant design 表单组件
封装LisSearch组件
import {FC , useState ,useEffect} from 'react'import { useNavigate , useLocation ,useSearchParams} from 'react-router-dom';import { Input } from "antd";//引入常量import {LIST_SEARCH_PARAM_KEY} from '../constant/index.js';const {Search} = Input; const ListSearch: FC = () => {//路由跳转const nav = useNavigate();//获取urlconst {pathname} = useLocation();//获取url参数,设置到搜索框中const [searchParams] = useSearchParams();useEffect(()=>{const searchVal = searchParams.get(LIST_SEARCH_PARAM_KEY) || "";//设置搜索框的值setVal(searchVal)},[searchParams])const handleSearch =(val : string )=>{//搜索时改变url,防止刷新丢失信息//跳转页面,增加url参数nav({pathname: pathname,search: `${LIST_SEARCH_PARAM_KEY}=${val}`})}//受控组件const [val, setVal] = useState<string>('');const handleChange =(e : React.ChangeEvent<HTMLInputElement>)=>{setVal(e.target.value)}return(<div><Search value={val} onChange={handleChange} placeholder="请输入关键字" style={{ width: 200 }} onSearch={handleSearch} /></div>)}export default ListSearch;
表单组件的校验
ant design rules
校验之前
const Register : FC = ()=>{const onfinish = (values) => {console.log('Received values of form: ', values);}return (<><div className={styles.container}><div><Space><Title level={2}><UserAddOutlined /> </Title><Title level={2}>注册新用户</Title></Space></div><div><Formname="basic"labelCol={{ span: 6 }}wrapperCol={{ span: 16 }}initialValues={{ remember: true }}autoComplete="off"onFinish={onfinish}><Form.Itemlabel="用户名"name="username"><Input /></Form.Item><Form.Itemlabel="密码"name="password"><Input.Password /></Form.Item><Form.Itemlabel="确认秘密"name="checkedPassword"><Input.Password /></Form.Item><Form.Itemlabel="昵称"name="nickname"><Input /></Form.Item><Form.Item wrapperCol={{ offset: 6, span: 16 }}><Space><Button type="primary" size='small' htmlType="submit">注册</Button><Link to={LOGIN_PATH}>已有账户, 登录</Link></Space></Form.Item></Form></div></div></>)}
校验之后
const Register : FC = ()=>{const onfinish = (values) => {console.log('Received values of form: ', values);}return (<><div className={styles.container}><div><Space><Title level={2}><UserAddOutlined /> </Title><Title level={2}>注册新用户</Title></Space></div><div><Formname="basic"labelCol={{ span: 6 }}wrapperCol={{ span: 16 }}initialValues={{ remember: true }}autoComplete="off"onFinish={onfinish}><Form.Itemlabel="用户名"name="username"rules={[{required:true , message:'请输入用户名'},{type: 'string', min : 5, max: 20 , message:'用户名长度为5-20'},{pattern : /^[a-zA-Z0-9_]+$/ , message:'用户名只能包含字母、数字、下划线'}]}><Input /></Form.Item><Form.Itemlabel="密码"name="password"rules={[{required:true , message:'请输入密码'},]}><Input.Password /></Form.Item><Form.Itemlabel="确认秘密"name="confirm"dependencies={["password"]}// 依赖项,password 变化时触发validateFieldrules={[{required:true , message:'请确认密码'},({getFieldValue}) => ({validator(_,val){if(!val || getFieldValue("password") === val){return Promise.resolve()}else{return Promise.reject(new Error('两次输入的密码不一致'))}}})]}><Input.Password /></Form.Item><Form.Itemlabel="昵称"name="nickname"><Input /></Form.Item><Form.Item wrapperCol={{ offset: 6, span: 16 }}><Space><Button type="primary" size='small' htmlType="submit">注册</Button><Link to={LOGIN_PATH}>已有账户, 登录</Link></Space></Form.Item></Form></div></div></>)}
第三方表单校验工具
react -hook-form
React Hook Form - performant, flexible and extensible form library (react-hook-form.com)
formik
Formik: Build forms in React, without the tears