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 相关文章推荐
php图像生成函数之间的区别分析
Dec 06 Javascript
Jquery easyui 实现动态树
Nov 17 Javascript
跟我学习javascript的for循环和for...in循环
Nov 18 Javascript
学习JavaScript设计模式之单例模式
Jan 19 Javascript
JS实现点击表头表格自动排序(含数字、字符串、日期)
Jan 22 Javascript
原生js仿浏览器滚动条效果
Mar 02 Javascript
vue-cli如何添加less 以及sass
Jul 06 Javascript
Vue底层实现原理总结
Feb 17 Javascript
angularJs中$scope数据序列化的实例
Sep 30 Javascript
javascript实现超好看的3D烟花特效
Jan 01 Javascript
Javascript Worker子线程代码实例
Feb 20 Javascript
Javascript ParentNode和ChildNode接口原理解析
Mar 16 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 SQLite类
2009/05/07 PHP
php修改NetBeans默认字体的大小
2013/07/02 PHP
php实现paypal 授权登录
2015/05/28 PHP
浅谈PHP值mysql操作类
2016/06/29 PHP
js资料toString 方法
2007/03/13 Javascript
FireFox与IE 下js兼容触发click事件的代码
2008/11/20 Javascript
将光标定位于输入框最右侧实现代码
2012/12/04 Javascript
javascript 动态创建表格的2种方法总结
2015/03/04 Javascript
神奇!js+CSS+DIV实现文字颜色渐变效果
2016/03/16 Javascript
详解微信小程序开发—你期待的分享功能来了,微信小程序序新增5大功能
2016/12/23 Javascript
JavaScript实现同一个页面打开多张图片
2016/12/29 Javascript
JavaScript 巧学巧用
2017/05/23 Javascript
记一次vue去除#问题处理经过小结
2019/01/24 Javascript
详解vue的数据劫持以及操作数组的坑
2019/04/18 Javascript
Element Cascader 级联选择器的使用示例
2020/07/27 Javascript
JavaScript实现拖拽和缩放效果
2020/08/24 Javascript
基于Vue3.0开发轻量级手机端弹框组件V3Popup的场景分析
2020/12/30 Vue.js
原生js实现无缝轮播图效果
2021/01/28 Javascript
python re正则表达式模块(Regular Expression)
2014/07/16 Python
python如何拆分含有多种分隔符的字符串
2018/03/20 Python
关于django 数据库迁移(migrate)应该知道的一些事
2018/05/27 Python
python读取文件名并改名字的实例
2019/01/07 Python
python给微信好友定时推送消息的示例
2019/02/20 Python
Python实现语音识别和语音合成功能
2019/09/20 Python
美国护肤咨询及美容产品电商:Askderm
2017/02/24 全球购物
伦敦的高级牛仔布专家:Trilogy
2018/08/06 全球购物
UNIX文件系统常用命令
2012/05/25 面试题
竞争上岗演讲稿
2014/01/05 职场文书
学生党员思想汇报范文
2014/01/09 职场文书
见习期自我鉴定
2014/01/31 职场文书
工作决心书
2014/03/11 职场文书
学习全国两会精神心得体会范文
2014/03/17 职场文书
求职自我推荐信
2014/06/25 职场文书
2014报到证办理个人委托书
2014/10/08 职场文书
总经理岗位职责范本
2015/04/01 职场文书
“5.12”护士节主持词
2015/07/04 职场文书