赵走x博客
网站访问量:151955
首页
书籍
软件
工具
古诗词
搜索
登录
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
19、Excel:一个出色的表格组件:编辑数据
资源编号:76069
书籍
React快速上手开发
热度:78
接下来,我们要让用户可以在这个Excel 表格组件中编辑数据。
接下来,我们要让用户可以在这个Excel 表格组件中编辑数据。下面介绍的解决方案包括三个步骤。 * (1) 双击一个单元格。Excel 找出点击的单元格,并把表格内容从简单的文本变为一个预先填充了原内容的输入框(如图3-6 所示)。  图3-6:双击单元格时,内容变为一个数据框 * (2) 编辑内容(如图3-7 所示)。  图3-7:编辑内容 * (3) 敲下回车。输入框消失,表格数据更新为新输入内容(如图3-8 所示)。  图3-8:敲下回车后,修改原内容 # 1、可编辑单元格 首先要设置一个简单的事件监听器。当用户双击时,组件“记住”用户选择的单元格: ``` React.DOM.tbody({onDoubleClick: this._showEditor}, ....) ``` 这里并没有使用W3C 规范的ondblclick,而是使用了更友好、更易于阅读的onDoubleClick。 _showEditor 函数就像下面这样: ``` _showEditor: function(e) { this.setState({edit: { row: parseInt(e.target.dataset.row, 10), cell: e.target.cellIndex, }}); }, ``` 这里发生了什么? * 这个函数设置了this.state 中的edit 属性。该属性在进入编辑状态之前是null,之后则变为一个包含了属性row 和cell 的对象,这两个属性分别代表被编辑单元格的行索引值和列索引值。所以如果你点击的是最开始的单元格,this.state.edit 的值就是{row:0, cell: 0}。 * 为了算出单元格的索引值,和之前一样,你需要使用e.target.cellIndex,其中e.target指向的是被双击的单元格
。 * 在DOM 结构中没有直接获取rowIndex 的方法,你需要自己设定一个data- 自定义属性。每个单元格都应该包含data-row 属性,并设置为行索引值,然后你可以使用parseInt() 取得该索引值。 最后,还有一些说明和先决条件。首先,edit 属性在一开始是不存在的,所以要在getInitialState() 方法中进行初始化。现在的getInitialState() 方法应该如下所示: ``` getInitialState: function() { return { data: this.props.initialData, sortby: null, descending: false, edit: null, // {row: index, cell: index} }; }, ``` data-row 属性用于跟踪行索引。现在tbody() 的整个结构就像这样: ``` React.DOM.tbody({onDoubleClick: this._showEditor}, this.state.data.map(function(row, rowidx) { return ( React.DOM.tr({key: rowidx}, row.map(function(cell, idx) { var content = cell; // TODO - 如果idx和rowidx的值与当前单元格匹配, // 则把content变为一个输入框;否则只需展示文本内容 return React.DOM.td({ key: idx, 'data-row': rowidx }, content); }, this) ) ); }, this) ) ``` 最后需要完成TODO 中的未实现功能。我们需要在特定条件下生成一个文本框区域。由于调用setState() 方法设置了edit 属性,整个render() 方法会被再次调用。React 对表格进行重新渲染,给了你一个在双击表格时更新单元格内容的机会。 # 2、输入字段的单元格 现在把TODO 注释替换为具体代码。首先,我们需要取得编辑状态的state 值: ``` var edit = this.state.edit; ``` 判断edit 属性是否已设置。如果是,则判断当前单元格是否为待编辑单元格: ``` if (edit && edit.row === rowidx && edit.cell === idx) { // ... } ``` 如果匹配到目标单元格,就创建一个表单和一个输入框,并把内容填充到输入框中: ``` content = React.DOM.form({onSubmit: this._save}, React.DOM.input({ type: 'text', defaultValue: content, }) ); ``` 如你所见,这个表单仅有一个输入框,输入框里预填充了单元格的文本内容。当提交表单 时,会进入私有方法_save() 的调用中。 # 3、保存 要完成编辑功能,还需要在用户完成输入并提交表单(通过按下回车键)时,保存内容更改: ``` _save: function(e) { e.preventDefault(); // 进行保存 }, ``` 在避免浏览器默认行为后(目的是避免网页重新加载),你需要取得一个输入框的引用: ``` var input = e.target.firstChild; ``` 复制一份原有数据,避免直接操作this.state: ``` var data = this.state.data.slice(); ``` 使用新的值修改原有数据。单元格的行索引和列索引可以通过state 的edit 属性取得: ``` data[this.state.edit.row][this.state.edit.cell] = input.value; ``` 最后更新state,使视图重新渲染: ``` this.setState({ edit: null, // 完成编辑 data: data, }); ``` # 4、结论与虚拟DOM Diff 算法 现在,编辑功能已经完成了。这个功能不需要我们编写太多代码,你需要做的仅仅是: * 通过this.state.edit 属性跟踪需要编辑的单元格; * 在渲染时,如果单元格的行列索引匹配到用户双击的单元格,则在该单元格中显示输入框; * 从输入框获取新输入的值,更新表格数据的数组。 当你使用setState() 方法更新数据时,React 将会调用组件的render() 方法,让界面如魔术般地更新。也许仅仅因为一个单元格的变化而更新整个表格看起来不够高效,但React实际上只会修改一个单元格。 如果你打开浏览器开发工具,可以看到当你和应用进行交互时DOM 树的哪个部分得到了更新。在图3-9 中可以看到,当把The Lord of the Rings 的语言一栏从English 改为Engrish时,开发者工具会高亮显示DOM 结构的改变。  图3-9:高亮显示DOM 结构的改变 在幕后,React 调用了render() 方法,并根据预期DOM 结果创建了一个轻量级的树形表达。这被称为虚拟DOM 树。当再次调用render() 方法时(比如在调用setState() 方法之后),React 对于前后的虚拟树作出比较,计算出diff。基于diff,React 可以计算出改变浏览器DOM 结构所需的最小DOM 操作(比如appendChild()、textContent 等)。 在图3-9 中,单元格只发生了一处改变,因此没有必要重新渲染整个表格。React 通过计算改变的最小集合,批量进行DOM 操作。众所周知,DOM 操作是很耗时的(相比于纯JavaScript 操作、函数调用等),并且通常会成为大型Web 应用程序渲染性能的瓶颈,因此React 会尽量减少DOM 操作。 简而言之,对于性能和界面更新,React 通过以下方式给予你支持: * 轻量级操作DOM * 使用事件委托响应用户交互