React + 项目(从基础到实战) -- 第七期

使用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>

总结

  1. 受控组件:
    值同步到state,使用value属性
  2. 非受控组件
    值不同步到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>

        <input

         type="checkbox"

         id="1"

         value="shanghai"

         checked={selectdIdList.includes("shanghai")}

         onChange={handleSelectd}

         />

          <label htmlFor="2">beijing</label>

            <input

            type="checkbox"

            id="2"

            value="beijing"

            checked={selectdIdList.includes("beijing")}

            onChange={handleSelectd}

         />

  

        <label htmlFor="3">chengdu</label>

            <input

            type="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();

    //获取url

    const {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>

            <Form

                name="basic"

                labelCol={{ span: 6 }}

                wrapperCol={{ span: 16 }}

                initialValues={{ remember: true }}

                autoComplete="off"

                onFinish={onfinish}

            >

                <Form.Item

                label="用户名"

                name="username"

                >

                <Input />

                </Form.Item>

  

                <Form.Item

                label="密码"

                name="password"

                >

                <Input.Password />

                </Form.Item>

  

                <Form.Item

                label="确认秘密"

                name="checkedPassword"

                >

                <Input.Password />

                </Form.Item>

  

                <Form.Item

                label="昵称"

                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>

            <Form

                name="basic"

                labelCol={{ span: 6 }}

                wrapperCol={{ span: 16 }}

                initialValues={{ remember: true }}

                autoComplete="off"

                onFinish={onfinish}

            >

                <Form.Item

                label="用户名"

                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.Item

                label="密码"

                name="password"

                rules={[

                    {required:true , message:'请输入密码'},

                ]}

                >

                <Input.Password />

                </Form.Item>

  

                <Form.Item

                label="确认秘密"

                name="confirm"

                dependencies={["password"]}// 依赖项,password 变化时触发validateField

                rules={[

                    {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.Item

                label="昵称"

                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

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值