加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

react入门——实现一个输入框组件

发布时间:2020-12-15 03:29:21 所属栏目:百科 来源:网络整理
导读:React组件化开发初试 按照官方文档和例程博客,实现了一个简单的输入框组件。 如果想了解官方案例,请参考深入理解 React 总结一下,一个简单的React.js应用应按照以下步骤构建: 设计组件原型和JSON API; 拆分用户界面为一个组件树; 利用React, 创建应用

React组件化开发初试

按照官方文档和例程博客,实现了一个简单的输入框组件。

如果想了解官方案例,请参考深入理解 React

总结一下,一个简单的React.js应用应按照以下步骤构建:

  1. 设计组件原型和JSON API;
  2. 拆分用户界面为一个组件树;
  3. 利用React, 创建应用的一个静态版本;
  4. 识别出最小的(但是完整的)代表UI的state;
  5. 确认state的生命周期;
  6. 添加反向数据流。

个人认为这里的难点在于如何拆分用户界面,粒度过大不利于组件化的重用,粒度过小的话,显得冗余过多,并且复杂度陡升。本人最开始尝试细化的拆分,尽量让一个组件只完成一个很小的功能需求,但最后反而不知道如何给每个组件分配其任务。

另一个难点来源于对state的判断,其实如果能够识别出最小的state,读者会发现一个复杂的组件所需的state数量其实很少。

在React.js中,有两种数据模型,state代表的是会动态变化的状态,props代表的是父级传递而来的属性,state会反过来更新UI,而props只是一次性设置填充。

第一步:构建原型

我们的组件要完成以下功能:

  1. 可以定制label和输入框的placeholder的内容
  2. 可以有个属性设置个正则,输入的文字不符合正则的时候输入框就标红
  3. 右侧的大叉icon点击后,消失并清楚输入框内容
  4. 组件需要开放3个对外方法,获取(获取值时trim),设置(设置值时trim),删除,输入框的内容。

原型比较简单,样式如下:

JSON接口数据如下:

{ 
labelText: "酒店地址",hinderText: "请填写酒店地址",buttonImgSrc:
regExp: /^w{5,8}$/
}

我们通过JSON数据设置输入框组件的label标签、Input的placeholder属性和对用户输入的正则验证。

第二步:拆分用户界面为一个组件树

在完成用户界面切分的过程中,最开始,如图原型图所示,做了非常细粒度的拆分,拆分结构如下:

  • LimitedInputBox
    • Title
    • InputBox
    • ClearButton

这里,将LimitedInputBox作为最外面的容器,包裹整个组件,子组件分为三部分,Title即是一个label标签,用来显示该输入框组件的名称(或者说标题),InputBox即是一个input标签,用来接收用户输入,ClearButton可以用一个img标签,用来清除input输入框内容。刚开始准备用另外一个容器包裹InputBoxClearButton,发现这样过于冗余于是两者还是和Title作为同一级组件比较好。

后来思来,觉得过于拆分了,最小单位与HTML原生标签同一级别,没有意义,因此,最后只保留了一个组件,就称之为LimitedInputBox。即:

  • LimitedInputBox

第三步:利用React, 创建应用的一个静态版本

首先,不需要考虑用户交互,直接将数据模型渲染到UI上。即将数据渲染和用户交互两个过程拆分开来。

这样做比较简单,因为构建静态版本的页面只需要大量的输入,而不需要思考;但是添加交互功能却需要大量的思考和少量的输入。

为了创建一个渲染数据模型的应用的静态版本,你将会构造一些组件,这些组件重用其它组件,并且通过 props 传递数据。 props 是一种从父级向子级传递数据的方式。

本例中,的props就是第一步构建的JSON数据。

考虑到第二步中我采取了两种拆分方式,这里给出相应的代码:

/** author : River He**/

//细分结构
var data = {
    labelText: "酒店地址",hinderText: "请填写酒店地址",buttonImgSrc: "eliminate.png",regExp: /^w{5,8}$/
};

var Title = React.creatClass({
    render: function() {
    return (
        <label>{this.props.labelText}</label>
    );
  }
});

var InputBox = React.createClass({
    render: function() {
  return (
    <input 
        placeholder={this.props.hinderText} 
        regExp={this.props.regExp}>
    </input>
  );
  }
});

var ClearButton = React.createClass({
    render: function() {
    return (
        <img src={this.props.buttonImgSrc}></>
    );
  }
});

var LimitedInputBox = React.createClass({
    render: function() {
    return (
        <Title labelText={this.props.data.labelText} />
      <InputBox 
        hinderText={this.props.data.hinderText}
        regExp={this.props.data.regExp}
      />
      <ClearButton buttonImgSrc={this.props.data.buttonImgSrc} />
    );
  }
});

ReactDOM.render(
    <LimitedInputBox data={data} />,document.getElementById('example')
);
/** author : river he**/

//粗划分
var data = {
    labelText: "酒店地址",8}$/
};

var LimitedInputBox = React.createClass({
    render: function() {

        return (
            <div>
            <label >{this.props.data.labelText}</label>
            <input 
                placeholder={this.props.data.hinderText} 
                regExp={this.props.data.regExp}>
            </input>
            <img src={this.props.buttonImgSrc ></img>
            </div>
        );
    }
});

ReactDOM.render(
    <LimitedInputBox data={data} />,document.getElementById('example')
);

第四步:识别出最小的代表UI的state

为了使 UI 可交互,需要能够触发底层数据模型的变化。 React 通过 state 使这变得简单。

为了正确构建应用,首先需要考虑应用需要的最小的可变 state 数据模型集合。此处关键点在于精简:不要存储重复的数据。构造出绝对最小的满足应用需要的最小 state 是有必要的,并且计算出其它强烈需要的东西。

本案例较简单,state很明显是inputText,即input输入框中的值。

而对于一般情况,可以简单地对每一项数据提出三个问题:

  1. 是否是从父级通过props传入的?如果是,可能不是state。
  2. 是否会随着时间改变?如果不是,可能不是state。
  3. 能够根据组件中其他的state数据或者props计算出来吗?如果是,就不是state。

第五步:确认state的生命周期

找出了state之后,需要继续找出那些组件会被state更新,即哪些组件应该拥有state数据模型,本案例同样很简单,因为输入框input要判断用户输入是否符合正则表达式要求,因此与input相关的组件都应该拥有state。按照第一种细分,InputBox组件应该拥有state,按照第二个细分,因为只存在一个组件LimitedInputBox,故其应该拥有state

//细分结构
var data = {
    labelText: "酒店地址",8}$/
};

var Title = React.creatClass({
    render: function() {
    return (
        <label>{this.props.labelText}</label>
    );
  }
});

var InputBox = React.createClass({
    render: function() {
  return (
    <input 
        placeholder={this.props.hinderText}
        value={this.props.inputText} 
        regExp={this.props.regExp}>
    </input>
  );
  }
});

var ClearButton = React.createClass({
    render: function() {
    return (
        <img src={this.props.buttonImgSrc}></>
    );
  }
});

var LimitedInputBox = React.createClass({
  getInitialState: function() {
    return {
      inputText: ''
    };
  },render: function() {
    return (
        <Title labelText={this.props.data.labelText} />
      <InputBox 
        hinderText={this.props.data.hinderText}
        inputText={this.state.inputText}
        regExp={this.props.data.regExp}
      />
      <ClearButton buttonImgSrc={this.props.data.buttonImgSrc} />
    );
  }
});

ReactDOM.render(
    <LimitedInputBox data={data} />,8}$/
};

var LimitedInputBox = React.createClass({

    //初始化state
    getInitialState: function() {
        return {
            inputText: ''
        };
    },render: function() {

        return (
            <div>
            <label >{this.props.data.labelText}</label>
            <input 
                placeholder={this.props.data.hinderText}
                regExp={this.props.data.regExp}
                value={this.state.inputText}
                ></input>
            <img 
                src={this.props.data.buttonImgSrc}
            </img>
            </div>
        );
    }
});

ReactDOM.render(
    <LimitedInputBox data={data} />,document.getElementById('example')
);

第六步:添加反向数据流

前面构建了渲染正确的基于propsstate的沿着组件树从上至下单项数据流动的应用。然后我们需要构建反向的数据流动方式:组件树中层级很深的表单组件更新父级中的state

如果尝试在前面的输入框中输入,React会忽略你的输入。这是有意的,因为已经设置了inputvalue属性,使其总是和LimitedInputBox(对于粗分的情况,就是其本身)传递过来的state一致。

但是我们希望的是,无论用户何时改变了表单,都要更新state来反应用户的输入。由于组件只能更新自己的stateLimitedInputBox将会传递一个回调函数给InputBox,此函数将会在state应该被改变时触发。我们可以使用inputonChange事件来监听用户输入,从而确定何时触发回调函数。

LimitedInputBox传递的回调函数将会调用setState(),然后应用将会被更新。

/**author : River He*/

//细分结构
var data = {
    labelText: "酒店地址",8}$/
};

var Title = React.createClass({
    render: function() {
        return (
            <label>{this.props.labelText}</label>
        );
    }
});

var InputBox = React.createClass({

    handleChange: function() {
        this.props.onUserInput(
            this.refs.inputBox.value
        );
    },fitRegExp: function(inputText) {
        if(inputText.match(this.props.regExp) != null) {
            // console.log("true");
            return true;
        } else {
            // console.log("false");
            return false;
        }
    },render: function() {
        return (
            <input
                style={this.fitRegExp(this.props.inputText)?({border: '1px solid green'}):({border: '1px solid red'})} 
                placeholder={this.props.hinderText}
                value={this.props.inputText} 
                regExp={this.props.regExp}
                ref="inputBox"
                onChange={this.handleChange}>
            </input>
        );
    }
});

var ClearButton = React.createClass({

    handleClick: function() {
        this.props.onClear();
    },render: function() {
        return (
            <img 
                src={this.props.buttonImgSrc} 
                onClick={this.handleClick}
            />
        );
    }
});

var LimitedInputBox = React.createClass({
    getInitialState: function() {
        return {
          inputText: ''
        };
    },handleUserInput: function(inputText) {
        this.setState({
            inputText: inputText
        });
    },handleClear: function() {
        this.delText();
    },getText: function() {
        return this.state.inputText;
    },setText: function(text) {
        this.setState({
            inputText: text
        });
    },delText: function() {
        this.setState({
            inputText: ''
        });
    },render: function() {
        return (
            <div>
                <Title labelText={this.props.data.labelText} />
                <InputBox 
                    hinderText={this.props.data.hinderText}
                    inputText={this.state.inputText}
                    regExp={this.props.data.regExp}
                    onUserInput={this.handleUserInput}
                />
                <ClearButton 
                    buttonImgSrc={this.props.data.buttonImgSrc} 
                    onClear={this.handleClear}
                />
            </div>
        );
    }
});

ReactDOM.render(
    <LimitedInputBox data={data} />,document.getElementById('example')
);
/** author : river he**/

//粗分结构
var data = {
    labelText: "酒店地址",8}$/
};

var LimitedInputBox = React.createClass({

    //初始化state
    getInitialState: function() {
        return {
            inputText: ''
        };
    },// handleKeyUp: function(inputText) {
    // this.setState({
    // inputText: this.refs.input.value.trim()
    // });
    // },
    //处理输入框变化
    handleChange: function() {
        this.setState({
            inputText: this.refs.input.value.trim()
        });
    },//处理删除事件
    handleClear: function() {
        this.delText();
    },//删除方法
    delText: function() {
        // console.log(this.refs.input.text);
        this.setState({
            inputText: ''
        });
    },//获取用户输入
    getText: function() {
        return this.state.inputText;
    },//设置输入框内容
    setText: function(text) {
        this.setState({
            inputText: text.trim()
        });
    },//判断输入内容否符合设置的正则表达式
    fitRegExp: function(inputText) {
        // console.log("start fitRegExp");
        if(inputText.match(this.props.data.regExp) != null) {
            // console.log("true");
            return true;
        } else {
            // console.log("false");
            return false;
        }
    },render: function() {

        return (
            <div>
            <label >{this.props.data.labelText}</label>
            <input 
                style={this.fitRegExp(this.state.inputText)?
                ({border: '1px solid green'}):({border: '1px solid red'})} 
                placeholder={this.props.data.hinderText} 
                regExp={this.props.data.regExp}
                // onKeyUp={this.handleKeyUp}
                onChange={this.handleChange}
                value={this.state.inputText}
                ref='input'
                ></input>
            <img src="eliminate.png" onClick={this.handleClear}></img>
            </div>
        );
    }
});

ReactDOM.render(
    <LimitedInputBox data={data} />,document.getElementById('example')
);

以上就是一个简单的输入框组件,相应的html模板和css如下,没有什么样式,希望读者谅解,有时间改下css。

<!-- limitedInputBox.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="../build/react.js"></script>
    <script src="../build/react-dom.js"></script>
    <script src="../build/browser.min.js"></script>
    <!-- <script type="text/babel" src="limitedInputBox.js"></script> -->
    <script src="inputWidget.js" type="text/babel"></script>
    <link rel="stylesheet" href="limitedInputBox.css">
    <title>LimitedInputBox</title>
</head>
<body>
    <div id="example"></div>
</body>
</html>
//limitedInputBox.css
img {
    height: 14px;
    width: 14px;
}

JS Bin on jsbin.com

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读