react学习笔记 item8 --- 表单

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014607184/article/details/53286791

表单是应用必不可少的一部分,只要需要用户输入,哪怕是最简单的输入,都离不开表单。一直以来,单页应用中的表单都很难处理好,因为表单中充斥着用户变化莫恻的状态。在 react 中,表单的处理也与原生的 JS 处理方法稍有不同。在 react 中,表单组件有两种类型:受限组件(约束组件)不受限组件(无约束组件)

受限组件

约束组件的模式与React 其他类型组件的模式一致。表单组件的状态交由React 组件控制,状态值被存储在React 组件的state 中。如果想要更好地控制表单组件,推荐使用约束组件。

先看下面一个例子

// 示例1
var MyForm = React.createClass({
    render:function(){
        return(
            <input type='text' value='defaultText' />
            );
    }
});

ReactDOM.render(
   <MyForm />,
  document.getElementById('example')
);

上面的代码将渲染出一个值为 defaultText 的 input 元素。用户在渲染出来的元素里输入任何值都不起作用,因为 React 已经赋值为 defaultText。通过运行,我们在 chrome 浏览器中查看到如下结果:

这里写图片描述

在控制台打印出了一条 warning, 提醒我们设置了 value 的时候需要同时提供 onChange 事件,不然表单是只读的。因此如果想响应更新用户输入的值,就得使用 onChange 事件:

// 示例2
var MyForm = React.createClass({
    getInitialState: function() {
        return {inputValue: 'defaultText'};
      },
    handleInputChange:function(e){
        this.setState({
            inputValue: e.target.value
        });
    },
    render:function(){
        return(
            <input type='text' value={this.state.inputValue} onChange={this.handleInputChange} />
            );
    }
});
ReactDOM.render(
   <MyForm />,
  document.getElementById('example')
);

示例 2 与示例 1 相比,最显著的变化就是<input/> 的值存储在父组件的 state 中,然后通过 onChange 事件去改变 state 。以下是示例2 的过程:

  • getlnitialState 设置defaultValue 。
  • < input/> 的值在渲染时被设置。
  • < input/ > 的值onChange 时, change 处理器被调用。
  • change 处理器更新state 。
  • 在重新撞染时更新< input/> 的值。

虽然与无约束组件相比,代码量增加了不少,但是现在可以控制数据流,在用户输入数据时更新state 。

在示例2 的基础上,我们改变handleInputChange,实现当用户输入时,把字符都转换成大写:

handleInputChange:function(e){
        this.setState({
            inputValue: e.target.value.toUpperCase()
        });
    },

你可能会注意到,在用户输入数据后,小写字符转成大写形式并添加到输入框时,并不会发生闪烁。这是因为React 拦截了浏览器原生的change 事件,在setState 被调用后, 这个组件就会重新渲染输入框。然后React 计算差异,更新输入框的值。

不受限组件

没有设置 value(或者设为 null) 的 <input> 组件是一个不受限组件。对于不受限的 <input>组件,渲染出来的元素直接反应用户输入。不受限组件的最大的特点就是表单组件的值是不受React 组件控制的,而是由<input>自己控制。

// 示例3
var MyForm = React.createClass({
    render:function(){
        return(
            <input type='text' defaultValue='defaultText' />
            );
    }
});

ReactDOM.render(
   <MyForm />,
  document.getElementById('example')
);

我们可以通过defaultValue 属性设置< input/ > 的默认值。组件的value 井非由父组件设置, 而是让<input/>自己控制自己的值。

对于一个无约束的组件,如果要访问DOM 节点的值,需要给<input/> 添加一个 ref 属性。ref 是一个不属于DOM 属性的特殊属性,用来标记DOM 节点,可以通过this 上下文访问这个节点。为了便于访问,组件中所有的ref 都添加到了this.refs 上。

// 示例4
var MyForm = React.createClass({
    submitHandler:function(e){
        e.preventDefault();
        var value = ReactDOM.findDOMNode(this.refs.myInput).value;
        alert(value);
    },
    render:function(){
        return(
            <form onSubmit={this.submitHandler}>
                <input ref="myInput" type='text' defaultValue='defaultText' />
                <button type='submit'>提交</button>
            </form>
            );
    }
});

ReactDOM.render(
   <MyForm />,
  document.getElementById('example')
);

在示例4 中,我们设置了<input />的 ref ,然后通过this.refs.myInput 获取到该节点,这样就能获取的节点的值了。

这里需要注意一下版本兼容性问题:

当使用时this.refs.myInput.getDOMNode(),时如果使用 react 版本是 0.14.8及以前的版本,可以正常运行,但是如果使用的是0.15.0后的版本时,可能会报错:

this.refs.myInput.getDOMNode is not a function(…)

这是需要用到 ReactDOM.findDOMNode(this.refs.myInput);。如果出现了相关的报错,可以先打印一下this.refs.myInput,查看是否找到相应的节点,然后再查看不同版本对应的方法。

常用表单元素

除了上面<input />,下面介绍一些表单中常用的其他表单元素。

< label/ >

Label 是表单元素中很重要的组件,通过Label 可以明确地向用户传达你的要求,提升单选框和复选框的可用性。但是在使用Label 时需要注意 for 属性,在React 中,与class 变成了className 类似, for 也变成了htmlFor :

<label htmlFor="name">Name:</label>

< textarea/ >

对 HTML 而言,让开发者设置多行的值很容易。但是,React 是 JavaScript,没有字符限制,可以使用 \n 实现换行。<textarea /> 被改得更像<input />了,允许我们设置value 和defaultValue 。

//非约束的
<textarea defaultValue="Hello World" />
// 约束的
<textarea value={this.state.textareaValue} onChange={this.handleChange} />

< select/ >

HTML 中<select>通常使用 <option> 的 selected 属性设置选中状态;React 为了更方面的控制组件,<select />现在接受 value 和defaultValue 来设置已选项,我们可以更容易地对它的值进行操作。

//非约束的
<select defaultValue="B">
    <option value="A">First Option</option>
    <option value="B">Second Option</option>
    <option value="C">Third Option</option>
</select>
// 约束的
<select value={this.state . helloTo} onChange={this.handleChange}>
    <option value="A">First Option</option>
    <option value="B 与Second Option</option>
    <option value="C">Third Option</option>
</select>

< checkbox / >

复选框和单选框使用的则是另外一种完全不同的控制方式。在HTML 中,类型为checkbox 或 radio 的 < input/ > 与类型为text 的< input/> 的行为完全不一样。通常,复选框或者单选框的值是不变的,只有checked 状态会变化。要控制复选框或者单选框,就要控制它们的checked 属性。

我们先看一个简单的示例:

// 示例5
var MyForm = React.createClass({
    getInitialState: function() {
        return {
            checked: true
        };
    },

    handleChange: function(event) {
        this.setState({
            checked: event.target.checked
        });
    },

    submitHandler: function(event) {
        event.preventDefault();
        alert(this.state.checked);
    },
    render: function() {
        return (
            <form onSubmit={this.submitHandler}>
                <input type="checkbox" value="A" checked={this.state.checked} onChange={this.handleChange} />
                <br/>
                <button type="submit">提交</button>
            </form>
        );
    }
});

上述<input/ > 的值一直都是A ,只有checked 的状态在变化。我们把 checked 的状态保存在 state 中,通过 state 的更新去渲染页面效果。

一个简单的表单示例

// 示例6
var MyForm = React.createClass({
    getInitialState:function(){
        return {
            inputValue: 'input value',
            selectValue: 'A',
            radioValue:'',
            checkValues:[],
            textareaValue:'some text here,,,,,'             
        }
    },
    handleSubmit:function(e){
        e.preventDefault();
        var formData = {
            input: ReactDOM.findDOMNode(this.refs.goodInput).value,
            select: ReactDOM.findDOMNode(this.refs.goodSelect).value,
            textarea: ReactDOM.findDOMNode(this.refs.goodTextarea).value,
            radio: this.state.radioValue,
            check: this.state.checkValues,
        }

        console.log('the form result is:')
        console.log(formData);

        this.refs.RadioButtons.saySomething();

    },
    handleRadio:function(e){
        this.setState({
            radioValue: e.target.value,
        })
    },
    handleCheck:function(e){
        var checkValues = this.state.checkValues.slice();
        var newVal = e.target.value;
        var index = checkValues.indexOf(newVal);
        if( index == -1 ){
            checkValues.push( newVal )
        }else{
            checkValues.splice(index,1);
        }

        this.setState({
            checkValues: checkValues,
        })
    },
    render: function(){
        return (
            <form onSubmit={this.handleSubmit}>
                <input ref="goodInput" type="text" defaultValue={this.state.inputValue }/>
                <br/>
                选项:
                <select defaultValue={ this.state.selectValue } ref="goodSelect">
                    <option value="A">A</option>
                    <option value="B">B</option>
                    <option value="C">C</option>
                    <option value="D">D</option>
                    <option value="E">E</option>
                </select>
                <br/>
                <p>radio button!</p>
                <RadioButtons ref="RadioButtons" handleRadio={this.handleRadio} />
                <br/>

                <Checkboxes handleCheck={this.handleCheck} />
                <br/>
                <textarea defaultValue={this.state.textareaValue} ref="goodTextarea"></textarea>
                <button type="submit">提交</button>

            </form>
        )
    }
});

var RadioButtons = React.createClass({
    saySomething:function(){
        alert("RadioButtons saying....");
    },
    render:function(){
        return (
            <span>
                A
                <input onChange={this.props.handleRadio} name="goodRadio" type="radio" value="A"/>
                B
                <input onChange={this.props.handleRadio} name="goodRadio" type="radio" value="B"/>
                C
                <input onChange={this.props.handleRadio} name="goodRadio" type="radio" value="C"/>
            </span>
        )
    }
});

var Checkboxes = React.createClass({
    render: function(){
        return (
            <span>
                A
                <input onChange={this.props.handleCheck}  name="goodCheckbox" type="checkbox" value="A"/>
                B
                <input onChange={this.props.handleCheck} name="goodCheckbox" type="checkbox" value="B" />
                C
                <input onChange={this.props.handleCheck} name="goodCheckbox" type="checkbox" value="C" />
            </span>
        )
    }
})

示例6 中将<radio/><checkbox/>封装成了独立的组件,提交表单时,利用this.refs 获取对应的表单元素的值。这样就不需要为每一个组件写一个获取组件value 的函数了。渲染结果如下:

这里写图片描述

猜你喜欢

转载自blog.csdn.net/u014607184/article/details/53286791
今日推荐