zoukankan      html  css  js  c++  java
  • React 点击删除列表中对应项(React 获取DOM中自定义属性)

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

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

    1. 先说第一种方法

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

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

    现在的逻辑是:整个待展示列表(由子组件组成的数组)是个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')
    
    );

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

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

    在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

    整体代码:

      1 class List extends React.Component {
      2 
      3     constructor(props){
      4 
      5         super(props);
      6 
      7         this.upData=this.upData.bind(this);
      8 
      9     }
     10 
     11    
     12 
     13     upData(e){
     14 
     15         this.props.upData(this.props.index,e.target.value)
     16 
     17     }
     18 
     19  
     20 
     21     render() {
     22 
     23         return (<div><input type="text" onBlur={this.upData} defaultValue={this.props.item?this.props.item:""}/>
     24 
     25             <span onClick={this.props.delete} data-index={this.props.index}>X</span></div>)
     26 
     27     }
     28 
     29 }
     30 
     31 class Lists extends React.Component {
     32 
     33     constructor(props) {
     34 
     35         super(props);
     36 
     37         this.add=this.add.bind(this);
     38 
     39         this.delete=this.delete.bind(this);
     40 
     41         this.upData=this.upData.bind(this);
     42 
     43         this.state={
     44 
     45             lists:[]
     46 
     47         }
     48 
     49     }
     50 
     51  
     52 
     53     add(){
     54 
     55         var lists=this.state.lists;
     56 
     57         lists.push("");
     58 
     59         this.setState({lists:lists})
     60 
     61     }
     62 
     63  
     64 
     65     delete(e){
     66 
     67         var index=e.target.getAttribute("data-index");
     68 
     69         var lists=this.state.lists;
     70 
     71         lists.splice(index,1);
     72 
     73         this.setState({lists:lists})
     74 
     75     }
     76 
     77  
     78 
     79     upData(i,x){
     80 
     81         var lists=this.state.lists;
     82 
     83         lists[i]=x;
     84 
     85         console.log(lists);
     86 
     87         this.setState({lists:lists});
     88 
     89     }
     90 
     91  
     92 
     93     render() {
     94 
     95         return (<div>
     96 
     97             <span onClick={this.add}>添加</span>
     98 
     99             {this.state.lists.map(function (item,index) {
    100 
    101                 return <List key={item?item:index} index={index} delete={this.delete} upData={this.upData}  item={item}/>
    102 
    103             }.bind(this))}
    104 
    105             </div>)
    106 
    107     }
    108 
    109 }
    110 
    111  
    112 
    113 ReactDOM.render(
    114 
    115   <Lists />, document.getElementById('lists')
    116 
    117 )

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

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

  • 相关阅读:
    四、java IO--使用字节流拷贝文件
    三、java IO--使用字节流写入文件
    二、java IO--使用字节流读取文件
    一、java--IO概念
    xml解析/读取--dom4j
    java程序执行顺序
    Flask学习——cookie操作
    Linux13 shell函数、数组及awk、awk中的数组
    Linux12 RPM 和yum的使用
    Linux11 IP网段划分及主机接入网络
  • 原文地址:https://www.cnblogs.com/lihuanqing/p/6269424.html
Copyright © 2011-2022 走看看