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 相关文章推荐
JS 控制CSS样式表
Aug 20 Javascript
使用CSS和jQuery模拟select并附提交后取得数据的代码
Oct 18 Javascript
SinaEditor使用方法详解
Dec 28 Javascript
封装了一个支持匿名函数的Javascript事件监听器
Jun 05 Javascript
xcode中获取js文件的路径方法(推荐)
Nov 05 Javascript
BootStrap Table 后台数据绑定、特殊列处理、排序功能
May 27 Javascript
使用JavaScript实现表格编辑器(实例讲解)
Aug 02 Javascript
vue引入js数字小键盘的实现代码
May 14 Javascript
详解angular分页插件tm.pagination二次触发问题解决方案
Jul 20 Javascript
Angular4 Select选择改变事件的方法
Oct 09 Javascript
JQuery常见节点操作实例分析
May 15 jQuery
Vue 2.0 侦听器 watch属性代码详解
Jun 19 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
PHP.MVC的模板标签系统(二)
2006/09/05 PHP
神盾加密解密教程(三)PHP 神盾解密工具
2014/06/08 PHP
php读取csv文件并输出的方法
2015/03/14 PHP
PHP递归遍历多维数组实现无限分类的方法
2016/05/06 PHP
Javascript面象对象成员、共享成员变量实验
2010/11/19 Javascript
jQuery EasyUI API 中文文档 - ComboTree组合树
2011/10/11 Javascript
javascript获取select的当前值示例代码(兼容IE/Firefox/Opera/Chrome)
2013/12/17 Javascript
非常实用的12个jquery代码片段
2015/11/02 Javascript
两种js监听滚轮事件的实现方法
2016/05/13 Javascript
jQuery基于扩展简单实现倒计时功能的方法
2016/05/14 Javascript
JavaScript中的Array 对象(数组对象)
2016/06/02 Javascript
js判断所有表单项不为空则提交表单的实现方法
2016/09/09 Javascript
Vue.js之slot深度复制详解
2017/03/10 Javascript
jQuery遍历节点方法汇总(推荐)
2017/05/13 jQuery
Vue.js实现微信过渡动画左右切换效果
2017/06/13 Javascript
vue-router重定向不刷新问题的解决
2018/06/25 Javascript
Django的数据模型访问多对多键值的方法
2015/07/21 Python
Python使用微信SDK实现的微信支付功能示例
2017/06/30 Python
python实现手机通讯录搜索功能
2018/02/22 Python
python实现图片文件批量重命名
2020/03/23 Python
Python numpy实现二维数组和一维数组拼接的方法
2018/06/05 Python
pyspark.sql.DataFrame与pandas.DataFrame之间的相互转换实例
2018/08/02 Python
python selenium执行所有测试用例并生成报告的方法
2019/02/13 Python
对Python中画图时候的线类型详解
2019/07/07 Python
python中树与树的表示知识点总结
2019/09/14 Python
如何基于Python制作有道翻译小工具
2019/12/16 Python
解决python cv2.imread 读取中文路径的图片返回为None的问题
2020/06/02 Python
美国在线珠宝商店:SZUL
2017/02/11 全球购物
AMAVII眼镜官网:时尚和设计师太阳镜
2019/05/05 全球购物
Farfetch台湾官网:奢侈品牌时尚购物平台
2019/06/17 全球购物
应届生污水处理求职信
2013/11/06 职场文书
最新教师自我评价分享
2013/11/12 职场文书
应届毕业生求职信范文
2014/05/08 职场文书
在职证明书模板
2015/06/15 职场文书
田径运动会广播稿
2015/08/19 职场文书
Python实现学生管理系统并生成exe可执行文件详解流程
2022/01/22 Python