赵走x博客
网站访问量:151958
首页
书籍
软件
工具
古诗词
搜索
登录
49、Flux:理念、回顾Whinepad
48、lint、Flow、测试与复验:测试
47、lint、Flow、测试与复验:Flow
46、lint、Flow、测试与复验:ESLint
45、lint、Flow、测试与复验:package.json
44、构建实例应用:<Whinepad>
43、构建实例应用:应用配置
43、构建实例应用:<Excel>:改进的新版本
42、构建实例应用:组件:对话框
41、构建实例应用:组件:Actions
39、构建实例应用:表单:Form
38、构建实例应用:表单:<FormInput>“工厂组件”
37、构建实例应用:表单:Rating组件
36、构建实例应用:表单:Suggest
35、构建实例应用:Button组件
34、构建实例应用:组件
33、构建实例应用:Whinepad v.0.0.1
32、发布
31、开始构建
30、安装必备工具
29、为应用开发做准备:一个模板应用
28、JSX 和表单
27、JSX 和HTML 的区别
26、在JSX 中返回多个节点
25、展开属性
24、HTML 实体
23、JSX入门
22、Excel:一个出色的表格组件:下载表格数据
21、Excel:一个出色的表格组件:即时回放
20、Excel:一个出色的表格组件:搜索
19、Excel:一个出色的表格组件:编辑数据
18、Excel:一个出色的表格组件:排序
17、Excel:一个出色的表格组件
16、 PureRenderMixin
15、 性能优化:避免组件更新
14、 生命周期示例:使用子组件
13、组件生命周期示例:使用mixin
12、组件:生命周期方法
11、中途改变属性
10、从外部访问组件
9、在初始化state 时使用props:一种反模式
8、 props 与state
7、关于DOM 事件的说明
6、组件:带状态的文本框组件
5、组件的state
4、组件的propTypes
3、组件的属性
2、组件的基础
1、Hello World
50、Flux:Store
20、Excel:一个出色的表格组件:搜索
资源编号:76070
书籍
React快速上手开发
热度:76
下一步,我们为Excel 组件增加一个搜索功能,允许用户过滤表格内容
下一步,我们为Excel 组件增加一个搜索功能,允许用户过滤表格内容。我们计划这样做: * 增加一个按钮作为这个新功能的开关(如图3-10 所示);  图3-10:搜索按钮 * 如果打开搜索功能,则在表格中新增一行输入框,每个输入框各自负责搜索对应的列(如图3-11 所示);  图3-11:一行用于搜索/ 筛选的输入框 * 当用户在输入框中输入内容时,对state.data 数组进行筛选,只显示匹配的内容(如图3-12 所示)。  图3-12:搜索结果 # 1、状态与界面 首先,要给this.state 对象添加一个search 属性,以追踪搜索功能是否打开: ``` getInitialState:function(){ return { data:this.props.initialData, sortby:null, descending:false, edit: null,// [行索引, 列索引], search:false } }, ``` 下一步是更新界面。为了让代码变得更加易于管理,我们要把render() 函数分隔成若干个专用的小代码块。目前render() 函数只渲染了一个表格。我们把它重命名为`_renderTable() `方法。接下来,搜索按钮将成为整个工具栏的一部分(很快还要添加一个“输出”功能),因此我们把按钮的渲染放在`_renderToolbar() `中,作为该方法的一部分。 目前的代码如下所示: ``` render: function() { return ( React.DOM.div(null, this._renderToolbar(), this._renderTable() ) ); }, _renderToolbar: function() { // TODO }, _renderTable: function() { // 和之前的render()方法功能相同 }, ``` 如你所见,新的render() 函数返回一个div 组件,包含两个子元素:工具栏和表格。你已经知道表格是如何渲染的了,而且工具栏目前仅需渲染一个按钮: ``` _renderToolBar:function(){ return React.DOM.button( {onClick: this._toggleSearch,className:'toolbar'}, 'search' ) } ``` 如果开启搜索功能(意味着this.state.search 的值被设置为true),你需要渲染一行输入框组件。我们使用`_renderSearch()` 来处理这件事情: ``` _renderSearch:function(){ if(!this.state.search){ return null } return (React.DOM.tr({onChange:this._search}, this.props.headers.map(function (_ignore, idx) { return React.DOM.td({key:idx}, React.DOM.input({type:'text','data-idx':idx}) ) }) )) }, ``` 如你所见,搜索功能关闭时,这个函数不需要渲染任何内容,因此函数返回null。当然还有另一种方法,就是让函数调用者根据搜索开关决定是否调用该函数。不过相比之下,前者有助于简化`_renderTable() `函数。现在只需要对`_renderTable() `函数进行如下修改即可。 修改前: ``` React.DOM.tbody({onDoubleClick: this._showEditor}, this.state.data.map(function(row, rowidx) { // ... ``` 修改后: ``` React.DOM.tbody({onDoubleClick: this._showEditor}, this._renderSearch(), this.state.data.map(function(row, rowidx) { // ... ``` 搜索输入框仅仅是data 主循环(负责创建表格的所有行列)前的另一个子节点。当`_renderSearch() `方法返回null 时,React 简单地跳过这个额外子节点,并进行接下来的表 格渲染。 目前我们已经完成了搜索功能的界面修改。接下来要关注搜索功能的实际业务逻辑了。 # 2、筛选内容 我们打算把搜索功能做得非常简单:接收一个内容数组,对其调用Array.prototype.filter() 方法进行筛选,然后返回一个经过过滤的数组,包含符合搜索字符串的所有元素。 界面依然使用this.state.data 进行渲染,但this.state.data 的内容会被过滤掉一部分。你需要在搜索之前复制一份完整的数据,避免在搜索之后丢失数据。这样用户可以回到整个表格中,也可以改变搜索关键词以获取不同的匹配数据。我们把这份数据的副本(实际上是一份引用)称为_preSearchData: ``` var Excel = React.createClass({ // 业务逻辑 _preSearchData: null, // 更多逻辑 }); ``` 当用户点击search 按钮进行搜索时,_toggleSearch() 方法会被调用。这个函数负责切换搜索功能的打开与关闭。具体逻辑如下: * 根据开关设置this.state.search 的值为true 或者false; * 在开启搜索功能时,“记住”原有数据; * 在关闭搜索功能时,恢复原有数据。 这个函数的具体逻辑如下所示: ``` _toggleSearch:function(){ if(this.state.search){ this.setState({ data:this._preSearchData, search:false }); this._preSearchData=null; }else{ this._preSearchData=this.state.data; this.setState({ search:true }); } }, ``` 最后还需要实现`_search()` 函数。每当搜索行中的内容发生改变,也就是用户在其中一个输入框里输入内容时,该函数会被调用。以下是函数的完整实现,以及一些详细说明: ``` _search:function(e){ var needle=e.target.value.toLowerCase(); if(!needle){ // 当搜索字符串被删除时 this.setState({ data:this._preSearchData }); return; } // 需要搜索的那一列的索引值 var idx=e.target.dataset.idx; var searchData=this._preSearchData.filter(function (row) { return row[idx].toString().toLowerCase().indexOf(needle)>-1; }); this.setState({ data:searchData }); }, ``` 你可以通过变化的事件目标(输入框)获取用户输入的字符串: ``` var needle = e.target.value.toLowerCase(); ``` 如果搜索字符串为空(用户删除了输入的内容),函数会把state 修改为缓存中的原始数据: ``` if (!needle) { this.setState({data: this._preSearchData}); return; } ``` 如果搜索字符串非空,则过滤原始数据,并把过滤结果作为data 的新state: ``` var idx = e.target.dataset.idx; var searchdata = this._preSearchData.filter(function(row) { return row[idx].toString().toLowerCase().indexOf(needle) > -1; }); this.setState({data: searchdata}); ``` 至此,搜索功能已经完成了。要实现该功能,你只需要: * 增加搜索界面; * 根据需要显示/ 隐藏新界面内容; * 实际“业务逻辑”,即一个简单的数组filter() 方法调用。 原本的表格渲染逻辑并不需要改变。和往常一样,你只需要关心数据的状态;不管数据状态如何改变,都只需要把渲染过程(以及所有繁杂的DOM 操作)交给React 实现就可以了。 # 3、如何改进搜索功能 这仅仅是一个用作演示的简单例子。不妨思考一下:如何改进搜索功能? 切换搜索按钮的标签文字是一项可改进的工作。比如当搜索功能打开时(this.state.search === true),提示用户“搜索完成”。 另一项可以尝试的工作是使用多个搜索框实现多重搜索,也就是筛选已经筛选过的数据。如果用户在语言一栏键入Eng,然后在另一个搜索框中输入内容,为何不能只在之前的搜索结果之上继续搜索呢?你会如何实现这个功能?