React实现点击删除列表中对应项


Posted in Javascript onJanuary 10, 2017

点击删除按钮,删除列表中对应项本来是React比较基础的应用,可是应用情况变得复杂了以后,我还真想了一会儿才搞定。

简化一下应用场景:点击新增按钮,增加一条输入框,点击输入框旁边的按钮,删除该输入框(不能删错了啊)。

先说第一种方法

问题刚上手,首先规划级别:一个输入框和对应删除按钮为一个子组件,整体为父组件即可方便处理。

注意的点:生成的一坨输入框是一个数组,为了准确删掉对应项,生成时要编号。点击删除按钮要反馈对应编号,然后进行删除。

现在的逻辑是:整个待展示列表(由子组件组成的数组)是个state,添加按钮会增加一个元素到这个state里面,添加的方法如下:

add(){
  var lists=this.state.lists;
  lists.push(<List key={this.state.lists.length} index={this.state.lists.length} delete={this.delete}/>);
  this.setState({lists:lists})
 }

注意一点,这个index属性是固定的,子组建生成后就固定了,这就为你未来挖了一个坑。

删除按钮当然就是从这个state列表里删除对应元素了,问题一来了,我怎么知道是第几个元素?一拍脑袋这还不简单,event.target 获取点击的标签,在标签上写个index属性告诉delete方法是第几个元素不就得了?试了发现不行,看看文档,event.target确实获取dom元素没毛病,但是index这个属性原生dom根本不承认啊,怎么办?data-index就行了,前面加 data- 就是dom承认的自定义属性了。

写完了又想起了两个方法,一个是在删除按钮绑定删除事件的时候,.bind(this,index),index是你准备删掉的是第几个或者表示出来你要删哪个就行。另一个是搞个闭包,就能把index参数传进去了(事件绑定一个立即执行的方程传入参数,该方程返回目标方程)。

第一个问题解决,删除的方法如下:

delete(e){
  var index=e.target.getAttribute("data-index");
  var lists=this.state.lists;
  lists.splice(index,1);
  this.setState({lists:lists})
 }

data-index告诉你要删除第几个元素,然后把它从state里踢出去就行了。这回掉进了一个真正意义上的坑:有时候删的不是对应的元素!乱套了!

好吧,我沉思了5分钟,想到了为什么:生成列表的时候index已经固定,但删除列表的时候我们只告诉他删除的是第index项!问题严重了,举个例子,有两项,index 0和1 你点0,好吧第0项删掉了,你再点1,疑?没反应了,因为你打算删除第1项,而列表中目前只有第0项(就是原来的第一项,原来的第0项删除后他就成了第0项)!这会导致各种乱套,考虑到生成列表的index是列表长度表示的就更乱了。

解决方式:delete方法里修改一行:

lists.splice(index,1,"");

好了,删除的元素我用空字符串代替,这样顺序和删除的项,还有以后添加的项的index都不会乱了,给自己点赞。到这里第一种方法实现了目标。

Code pen 地址:http://codepen.io/huanqingli/pen/dNyQez

完整代码:

class List extends React.Component {
 render() {
  return (<div><input type="text" defaultValue={this.props.index}/>
   <span onClick={this.props.delete} data-index={this.props.index}>X</span></div>)
 }
}
class Lists extends React.Component {
 constructor(props) {
  super(props);
  this.add=this.add.bind(this);
  this.delete=this.delete.bind(this);
  this.state={
   lists:[]
  }
 }
 add(){
  var lists=this.state.lists;
  lists.push(<List key={this.state.lists.length} index={this.state.lists.length} delete={this.delete}/>);
  this.setState({lists:lists})
 }
 delete(e){
  var index=e.target.getAttribute("data-index");
  var lists=this.state.lists;
  console.log(index)
  lists.splice(index,1);
  this.setState({lists:lists})
 }
 render() {
  return (<div>
   <span onClick={this.add}>添加</span>
   {this.state.lists}
   </div>)
 }
}
ReactDOM.render(
 <Lists/>,
 document.getElementById('lists')
);

这种方法有利有弊,所以我找到了第二种方法,具体情况择优使用。

第二种方法。总体来讲推荐这种方法。

在state里保存要展示的数据,在render里动态生成子组件组,然后添加删除都是操作保存数据的state,render里的子组件会自动刷新。这种方式应该是更贴近React思路的,用数据展现界面。如果你要展现一组数据,这种方法很自然,但如果展现的是一个动态的表单,稍微麻烦一点,但也可以做,而且我依然推荐用这种方式。

这种方法做个todolist就很简单,这里依然做上文的例子,稍微麻烦一点,也会理解的更深入一点。

整体结构和第一种方法一样,只不过这次state里面不是子组件,先用空字符串组成的数组代替,仅仅是为了render的时候知道有几个子组件而已。添加的时候也要push空字符串,等输入框输入数据后,更新state中的内容,做到数据和界面同步。

render子组件的部分:

{this.state.lists.map(function (item,index) {
    return <List key={index} index={index} delete={this.delete}/>
   }.bind(this))}

添加的方法变成:

add(){
  var lists=this.state.lists;
  lists.push("");
  this.setState({lists:lists})
 }

这就能跑了,这有个小坑,稍有不慎你发现你怎么删都是删列表的最后一项,其实数据操作没问题,关键是这个存在感比较低的key,必须特定项有给定的key你用动态的index他就懵了,不知道删哪个了,他就吧最后一个删了。废话不多说(该程序因为key键取值的问题有一个小问题):

Code pen 地址:http://codepen.io/huanqingli/pen/xgxNYN

整体代码:

class List extends React.Component {
 constructor(props){
  super(props);
  this.upData=this.upData.bind(this);
 }
 upData(e){
  this.props.upData(this.props.index,e.target.value)
 }
 render() {
  return (<div><input type="text" onBlur={this.upData} defaultValue={this.props.item?this.props.item:""}/>
   <span onClick={this.props.delete} data-index={this.props.index}>X</span></div>)
 }
}
class Lists extends React.Component {
 constructor(props) {
  super(props);
  this.add=this.add.bind(this);
  this.delete=this.delete.bind(this);
  this.upData=this.upData.bind(this);
  this.state={
   lists:[]
  }
 }
 add(){
  var lists=this.state.lists;
  lists.push("");
  this.setState({lists:lists})
 }
 delete(e){
  var index=e.target.getAttribute("data-index");
  var lists=this.state.lists;
  lists.splice(index,1);
  this.setState({lists:lists})
 }
 upData(i,x){
  var lists=this.state.lists;
  lists[i]=x;
  console.log(lists);
  this.setState({lists:lists});
 }
 render() {
  return (<div>
   <span onClick={this.add}>添加</span>
   {this.state.lists.map(function (item,index) {
    return <List key={item?item:index} index={index} delete={this.delete} upData={this.upData} item={item}/>
   }.bind(this))}
   </div>)
 }
}
ReactDOM.render(
 <Lists />, document.getElementById('lists')
)

这种方法经常也会有点小坑,也比较好解决。

总结:两种方法各有利弊,推荐第二种,符合REACT设计思路,但第一种有时候解决问题很方便。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
Jquery实战_读书笔记2 选择器
Jan 22 Javascript
JQuery 图片的展开和伸缩实例讲解
Apr 18 Javascript
js实现的map方法示例代码
Jan 13 Javascript
Windows 系统下安装和部署Egret的开发环境
Jul 31 Javascript
Uploadify上传文件方法
Mar 16 Javascript
原生JS京东轮播图代码
Mar 22 Javascript
JS SetInterval 代码实现页面轮询
Aug 11 Javascript
Node.js学习之查询字符串解析querystring详解
Sep 28 Javascript
Node.js调用fs.renameSync报错(Error: EXDEV, cross-device link not permitted)
Dec 27 Javascript
微信小程序开发实现的IP地址查询功能示例
Mar 28 Javascript
Vue的生命周期操作示例
Sep 17 Javascript
一篇文章带你使用Typescript封装一个Vue组件(简单易懂)
Jun 05 Javascript
微信小程序 radio单选框组件详解及实例代码
Jan 10 #Javascript
微信小程序 slider 详解及实例代码
Jan 10 #Javascript
微信小程序 switch组件详解及简单实例
Jan 10 #Javascript
微信小程序 textarea 组件详解及简单实例
Jan 10 #Javascript
微信小程序 picker-view 组件详解及简单实例
Jan 10 #Javascript
微信小程序 picker 组件详解及简单实例
Jan 10 #Javascript
微信小程序 label 组件详解及简单实例
Jan 10 #Javascript
You might like
记录mysql性能查询过程的使用方法
2013/05/02 PHP
PHP面相对象中的重载与重写
2017/02/13 PHP
php 替换文章中的图片路径,下载图片到本地服务器的方法
2018/02/06 PHP
PHP使用星号替代用户名手机和邮箱的实现代码
2018/02/07 PHP
jQuery中delegate与on的用法与区别示例介绍
2013/12/20 Javascript
Javascript动态引用CSS文件的2种方法介绍
2014/06/06 Javascript
AngularJS入门教程之控制器详解
2016/07/27 Javascript
JS作用域闭包、预解释和this关键字综合实例解析
2016/12/16 Javascript
实现一个简单的vue无限加载指令方法
2017/01/10 Javascript
解决Vue打包之后文件路径出错的问题
2018/03/06 Javascript
vue项目中使用tinymce编辑器的步骤详解
2018/09/11 Javascript
Vue 指令实现按钮级别权限管理功能
2019/04/23 Javascript
M2实现Nodejs项目自动部署的方法步骤
2019/05/05 NodeJs
浅谈vue websocket nodeJS 进行实时通信踩到的坑
2020/09/22 NodeJs
python字符串连接方式汇总
2014/08/21 Python
python的类变量和成员变量用法实例教程
2014/08/25 Python
JS设计模式之责任链模式实例详解
2018/02/03 Python
python scipy求解非线性方程的方法(fsolve/root)
2018/11/12 Python
对python内置map和six.moves.map的区别详解
2018/12/19 Python
Python数据类型之列表和元组的方法实例详解
2019/07/08 Python
详解pycharm连接不上mysql数据库的解决办法
2020/01/10 Python
在PyCharm中实现添加快捷模块
2020/02/12 Python
Python运行提示缺少模块问题解决方案
2020/04/02 Python
解决reload(sys)后print失效的问题
2020/04/25 Python
python如何利用paramiko执行服务器命令
2020/11/07 Python
香港永安旅游网:Wing On Travel
2017/04/10 全球购物
潘多拉意大利官方网上商城:网上选购PANDORA珠宝
2018/10/07 全球购物
皇家阿尔伯特英国官方商店:Royal Albert骨瓷
2019/03/25 全球购物
Miller Harris官网:英国小众香水品牌
2020/09/24 全球购物
简述数据库的设计过程
2015/06/22 面试题
群众路线教育党课主持词
2014/04/01 职场文书
三月学雷锋月活动总结
2014/04/28 职场文书
群众路线教育实践活动剖析材料
2014/09/30 职场文书
mysql的MVCC多版本并发控制的实现
2021/04/14 MySQL
Win11 Build 21996.1 Dev版怎么样? win11系统截图欣赏
2021/11/21 数码科技
mysql 获取时间方式
2022/03/20 MySQL