React基础学习第三篇

184 阅读3分钟

前言

面对失败和挫折,一笑而过是一种乐观自信,然后重振旗鼓,这是一种勇气;面对误解和仇恨,一笑而过是一种坦然宽容,然后保持本色,这是一种达观;面对赞扬和激励,一笑而过是一种谦虚清醒,然后不断进取,这是一种力量;面对烦恼和忧愁,一笑而过是一种平和释然,然后努力化解,这是一种境界。

1.非受限组件

<div id="root"></div>
    <script type="text/babel">
        // 非受限(非受控)组件双向数据绑定,响应式数据处理
        class Hello extends React.Component {
            state = {
                value: 'hello'
            }
            change = (e) => {
                this.setState({
                    value: e.target.value
                })
            }
            render() {
                return <div>
                    <input type="text" />
                    <input type="text" defaultValue={this.state.value} onChange={this.change} />
                    <p>{this.state.value}</p>
                </div>
            }
        }
        ReactDOM.render(
            <Hello/>,
            document.getElementById("root")
        )
    </script>

    <div id="root2"></div>
    <script type="text/babel">
        class Rts extends React.Component {
            render() {
                return <div>
                    <label>空值:
                        <input type="radio" name='eat'/>吃饭
                        <input type="radio" name='eat'/>不吃饭
                    </label>
                    <label>默认值:
                        <input type="radio" name='sex' defaultChecked/>1
                        <input type="radio" name='sex' />2
                    </label>
                    <hr/>
                    <label>空值:
                        <input type="checkbox"/>香蕉
                        <input type="checkbox"/>苹果
                        <input type="checkbox"/>哈密瓜
                    </label>
                    <label>默认值:
                        <input type="checkbox" defaultChecked/>西瓜
                        <input type="checkbox" defaultChecked/>榴莲
                        <input type="checkbox" />菠萝蜜
                    </label>
                    <hr/>
                    <label>空值:
                        <select>
                            <option value="A">A</option>
                            <option value="B">B</option>
                            <option value="C">C</option>
                            <option value="D">D</option>
                        </select>
                    </label>
                    <label>默认值:
                        <select defaultValue="B">
                            <option value="A">A</option>
                            <option value="B">B</option>
                            <option value="C">C</option>
                            <option value="D">D</option>
                        </select>
                    </label>
                    <label>多个默认值:
                        <select multiple={true} defaultValue={['A', 'C']}>
                            <option value="A">A</option>
                            <option value="B">B</option>
                            <option value="C">C</option>
                            <option value="D">D</option>
                        </select>
                    </label>
                </div>
            }
        }
        ReactDOM.render(
            <Rts/>,
            document.getElementById("root2")
        )
    </script>

2.表单提交

   <div id="root"></div>
    <script type="text/babel">
        // 非受限(非受控)组件双向数据绑定,响应式数据处理
        class Hello extends React.Component {
            state = {
                name: '',
                sex: '1',
                select: 'A',
                select2: '',
                select3: '',
                text: 'hello world'
            }
            handleInput = (e) => {
                this.setState({name: e.target.value})
            }
            handleRadio = (e) => {
                this.setState({sex: e.target.value})
            }
            handleSelect = (e) => {
                this.setState({select: e.target.value})
            }
            handleSelect2 = (e) => {
                this.setState({select2: e.target.value})
            }
            handleSelect3 = (e) => {
                this.setState({select3: e.target.value})
            }
            handleText = (e) => {
                this.setState({text: e.target.value})
            }
            handleSubmit = () => {
                console.log(this.state)
            }
            
            render() {
                let { name, sex, select, select2, select3, text } = this.state
                let arr1 = ['D', 'E', 'F', 'G', 'H']
                let arr2 = [{id: 1, color: 'red'}, {id: 2, color: 'green'}, {id: 3, color: 'blue'}]
                return <div>
                    <form>
                        <label>姓名:<input type="text" defaultValue={name} onChange={this.handleInput} /></label><br/>
                        <label>性别:
                            <input type="radio" name='sex' value="1" 
                            onChange={this.handleRadio}/><input type="radio" name='sex' value="2" 
                            onChange={this.handleRadio}/></label><br/>
                        <label>写死的选项:
                            <select defaultValue={select} onChange={this.handleSelect}>
                                <option value="A">A</option>
                                <option value="B">B</option>
                                <option value="C">C</option>
                                <option value="D">D</option>
                            </select>
                        </label><br/>
                        <label>循环遍历出来的选项:
                            <select defaultValue={select2} onChange={this.handleSelect2}>
                                {
                                    arr1.map((item, index) =>
                                        <option key={index} value={item}>{item}</option>
                                    )
                                }
                            </select>
                        </label><br/>
                        <label>数组中是对象的数据循环遍历处理:
                            <select defaultValue={select3} onChange={this.handleSelect3}>
                                {
                                    arr2.map(item =>
                                        <option key={item.id} value={item.id}>{item.color}</option>
                                    )
                                }
                            </select>
                        </label><br/>
                        <label>备注信息:
                            <textarea defaultValue={text} onChange={this.handleText}></textarea>
                        </label>
                    </form>
                    <button onClick={this.handleSubmit}>点击提交</button>
                </div>
            }
        }
        ReactDOM.render(
            <Hello/>,
            document.getElementById("root")
        )
    </script>

3.简单表单的封装

<div id="root"></div>
    <script type="text/babel">
        // 非受限(非受控)组件双向数据绑定,响应式数据处理
        class Hello extends React.Component {
            state = {
                name: '',
                password: '',
                address: ''
            }
            // 复用的方法很简单,只需要给不同的标签定义不同的name,然后根据这个name进行值的设定
            // handleInput = (e) => {
            //     console.log(e.target.name);
            //     this.setState({name: e.target.value})
            // }
            // handlePassword = (e) => {
            //     console.log(e.target.name);
            //     this.setState({password: e.target.value})
            // }
            // handleAddress = (e) => {
            //     console.log(e.target.name);
            //     this.setState({address: e.target.value})
            // }

            handleChange = (e) => {
                // console.log(e.target.name);
                // let names = e.target.name
                // this.setState({[names]: e.target.value})
                this.setState({[e.target.name]: e.target.value})
            }

            handleSubmit = () => {
                console.log(this.state)
            }
            
            render() {
                let { name, password, address } = this.state
                return <div>
                    <form>
                        <label>姓名:<input type="text" name="name"
                            defaultValue={name} onChange={this.handleChange} />
                        </label><br/>
                        <label>密码:<input type="password" name="password"
                            defaultValue={password} onChange={this.handleChange} />
                        </label><br/>
                        <label>地址:<input type="text" name="address"
                            defaultValue={address} onChange={this.handleChange} />
                        </label><br/>
                    </form>
                    <button onClick={this.handleSubmit}>点击提交</button>
                </div>
            }
        }
        ReactDOM.render(
            <Hello/>,
            document.getElementById("root")
        )
    </script>

4.复杂表单封装

<div id="root"></div>
    <script type="text/babel">
        // 非受限(非受控)组件双向数据绑定,响应式数据处理
        class Hello extends React.Component {
            state = {
                name: '',
                sex: '2',
                select: 'A',
                select2: '',
                select3: '',
                text: 'hello world'
            }
            handleChange = (e) => {
                let name = e.target.name
                this.setState({[name]: e.target.value})
            }
            handleSubmit = () => {
                console.log(this.state)
            }
            
            render() {
                let { name, sex, select, select2, select3, text } = this.state
                let arr1 = ['D', 'E', 'F', 'G', 'H']
                let arr2 = [{id: 1, color: 'red'}, {id: 2, color: 'green'}, {id: 3, color: 'blue'}]
                return <div>
                    <form>
                        <label>姓名:<input type="text" name="name" defaultValue={name} onChange={this.handleChange} /></label><br/>
                        <label>性别:
                            <input type="radio" name='sex' value="1"
                            defaultChecked={sex === '1' ? true : false}
                            onChange={this.handleChange}/><input type="radio" name='sex' value="2"
                            defaultChecked={sex === '2' ? true : false}
                            onChange={this.handleChange}/></label><br/>
                        <label>写死的选项:
                            <select name="select" defaultValue={select} onChange={this.handleChange}>
                                <option value="A">A</option>
                                <option value="B">B</option>
                                <option value="C">C</option>
                                <option value="D">D</option>
                            </select>
                        </label><br/>
                        <label>循环遍历出来的选项:
                            <select name="select2" defaultValue={select2} onChange={this.handleChange}>
                                {
                                    arr1.map((item, index) =>
                                        <option key={index} value={item}>{item}</option>
                                    )
                                }
                            </select>
                        </label><br/>
                        <label>数组中是对象的数据循环遍历处理:
                            <select name="select3" defaultValue={select3} onChange={this.handleChange}>
                                {
                                    arr2.map(item =>
                                        <option key={item.id} value={item.id}>{item.color}</option>
                                    )
                                }
                            </select>
                        </label><br/>
                        <label>备注信息:
                            <textarea name="text" defaultValue={text} onChange={this.handleChange}></textarea>
                        </label>
                    </form>
                    <button onClick={this.handleSubmit}>点击提交</button>
                </div>
            }
        }
        ReactDOM.render(
            <Hello/>,
            document.getElementById("root")
        )
    </script>

5.注册表单验证

 <div id="root"></div>
    <script type="text/babel">
        // 非受限(非受控)组件双向数据绑定,响应式数据处理
        class Hello extends React.Component {
            state = {
                name: '',
                password: '',
                sex: '1',
                phone: '',
                select: ''
            }

            // 姓名校验处理
            nameChange = (e) => {
                let rule = /^[a-zA-Z0-9]{4,10}$/
                let value = e.target.value
                let error = ''
                if(!value) {
                    error = '请输入昵称'
                } else if (!rule.test(value)) {
                    error = '请输入4-10位昵称'
                } else {
                    error = ''
                }
                this.setState({
                    name: value,
                    nameError: error
                })
            }
            
            passChange = (e) => {
                let rule = /^\S*(?=\S{6,12})(?=\S*\d)(?=\S*[A-Z])(?=\S*[a-z])(?=\S*[!@#$%^&*? ])\S*$/
                let value = e.target.value
                let error = ''
                if(!value) {
                    error = '请输入密码'
                } else if (!rule.test(value)) {
                    error = '请输入6-12需要包含大小写字母和数字以及特殊符号'
                } else {
                    error = ''
                }
                this.setState({
                    password: value,
                    passwordError: error
                })
            }

            phoneChange = (e) => {
                let rule = /^(?:(?:\+|00)86)?1[3-9]\d{9}$/
                let value = e.target.value
                let error = ''
                if(!value) {
                    error = '请输入手机号'
                } else if (!rule.test(value)) {
                    error = '请输入格式正确的手机号'
                } else {
                    error = ''
                }
                this.setState({
                    phone: value,
                    phoneError: error
                })
            }

            handleClick = (e) => {
                let name = e.target.name
                this.setState({[name]: e.target.value})
            }

            handleSubmit = () => {
                console.log(this.state)
            }
            
            render() {
                let { name, nameError, password, passwordError, sex, phone, phoneError, select } = this.state
                let arr = [
                    {id: 1, city: '北京'},
                    {id: 2, city: '上海'},
                    {id: 3, city: '广州'},
                    {id: 4, city: '深圳'},
                    {id: 5, city: '武汉'}
                ]
                return <div>
                    <form>
                        <label>姓名:<input type="text" name="name"
                            defaultValue={name} onChange={this.nameChange} />
                            <span className='danger'>{nameError}</span>
                        </label><br/>
                        <label>密码:<input type="password" name="password"
                            defaultValue={password} onChange={this.passChange} />
                            <span className='danger'>{passwordError}</span>
                        </label><br/>
                        <label>性别:
                        <input type="radio" name="sex" value="1"
                            checked={sex === '1' ? true : false} onChange={this.handleClick} />
                        <input type="radio" name="sex" value="2"
                            checked={sex === '2' ? true : false} onChange={this.handleClick} />
                        </label><br/>
                        <label>手机号:<input type="text" name="phone"
                            defaultValue={phone} onChange={this.phoneChange} />
                            <span className='danger'>{phoneError}</span>
                        </label><br/>
                        <label>选择城市:
                            <select name="select" defaultValue={select} onChange={this.handleClick}>
                                {
                                    arr.map(item => {
                                        return <option key={item.id} value={item.id}>{item.city}</option>
                                    })
                                }
                            </select>
                        </label><br/>
                    </form>
                    <button onClick={this.handleSubmit}>点击提交</button>
                </div>
            }
        }
        ReactDOM.render(
            <Hello/>,
            document.getElementById("root")
        )
    </script>

总结

表单元素

<input>、<textarea>、<option>这样的表单元素不同于其他元素,因为他们可以通过用户交互发生变化。这些元素提供的界面使响应用户交互的表单数据处理更加容易。

  • 交互属性,用户对以下元素做出交互时通过onChange回调函数来监听组件变化。表单元素支持几个受用户交互影响的属性:
    • value用于<input>、<textarea>
    • checked用于<checkbox>、<radio>
    • selected用于<option>
受限组件和不受限组件
  • 受限组件 设置了value的<input>是一个受限组件,对于受限的<input>,渲染出来的HTML元素始终保持value属性的值,此时用户在渲染出来的组件里输入任何值都不起作用。
    return <input type='text' value='hello' />
    
    return <textarea name="description" value="demo" />
    
  • 不受限组件 没有设置value(或者设为null)的<input>组件是一个不受限组件。对于不受限的<input>组件,渲染出来的元素直接反应用户输入。
    return <input type='text' />
    
    上面是一个空值输入框,如果想设置一个非空的初始值,可以使用defaultValue属性。
    return <input type="text" defaultValue="Hello" />
    
    上面的代码渲染出来的元素和受限组件一样有一个初始值,但这个值用户可以改变并会反应到界面上。 类型为radio、checkedinput支持defaultChecked属性,<select>支持defaultValue属性。
    <input type='radio' name='sex' defaultChecked />1
    <input type='radio' name='sex' />2
    <select defaultValue="C">
      <option value="A">A</option>
      <option value="B">B</option>
      <option value="C">C</option>
    </select>
    
    HTML中<select>通常使用<option>的selected属性设置选中状态;React为了更方便的控制组件,使用value替代了,如果是不受限组件则使用defaultValue。 如果给value属性传递一个数组,可以选中多个选项:<select multiple={true} value={['B', 'C']}></select>
常用表单数据绑定

通过以上的学习我们已经能够掌握常用的表单数据的绑定了,接下来要处理的是关于表单中双向数据绑定的事件方法封装。 通过现有的知识点,我们知道如果要对表单数据进行双向数据绑定的话需要设置对应的事件函数:

handleClick = (e) => {
  this.setState({name: e.target.value})
}

但是我们的表单中不可能只有一个数据需要进行双向数据绑定,所以最好的办法肯定是我们对这个函数进行复用,这里我们封装这个函数的时候就需要考虑到我们是通过动态的name值去进行设置的,因此我们需要把函数这样封装:

handleChange = (e) => {
  // 这里要注意我们一定要用[]进行包裹,因为这里我们拿到的name是一个字符串
  let name = e.target.name
  // this.setState({ [name]: e.target.value })
  this.setState({ [e.target.name]: e.target.value })
}
注册功能实现

注册功能中,双向数据绑定和验证都是我们需要考虑到的,因此在实现注册功能的时候,我们还需要在原有的双向数据绑定功能上集成我们的正则匹配验证功能以及错误提示信息。类似下面这样的:

// 姓名校验处理
nameChange = (e) => {
  let rule = /^[a-zA-Z0-9_-]{4,10}$/
  let value = e.target.value
  let error = ''
  if(!value) {
    error = '请输入昵称'
  } else if (!rule.test(value)) {
    error = '请输入4-10位昵称'
  } else {
    error = ''
  }
  this.setState({
    name: value,
    nameError: error
  })
}
<label>昵称:
  <input type="text" name="name" 
  value={name} onChange={this.nameChange}/>
  <span className="danger">{nameError}</span>
</label>