美文网首页Web前端之路让前端飞前端开发那些事
用angular写多选组件以及开发时的所思所想

用angular写多选组件以及开发时的所思所想

作者: 蚊子爸爸 | 来源:发表于2017-06-07 16:41 被阅读75次

    这里是demo

    我是一个angular1系列的重度爱好者,为什么喜欢它呢,因为我觉得angular1是接口设计的最漂亮的框架,虽然现在vue确实很火,但是我觉得vue的Expression部分并不足够智能。另外,可能是我的思维定势,我还是觉得Expression应该和一个对象互相绑定,就像我写的前端框架那样。怎么说呢,我坚持使用angular1,也许也是因为它的设计思路和我的思路更符合吧。当然,争论前端框架的优劣是很没意思的,所以其实在有的项目中,我也是选择了vue,没有什么原因,只是随心所欲而已。

    其实用angular1写组件(也就是指令)是几乎每个使用者都会的,不过这次我的所思所想并不只是如何写代码而已,这经历了三个过程:

    1. 多选框的最好形式是什么?真的是前面画对勾选中吗?
    2. 一个组件如何设计的优雅,让前端傻瓜都会用?
    3. 我的以上想法是不是多余的?

    1.多选框的最好形式是什么?真的是前面画对勾选中吗?

    其实对勾的多选框并不是一个很好的形式,因为它样式很烦人,前面一个input标签后面一个span或者label标签,看起来就很乱;垂直居中也不好调,动不动就出问题;每一个checkbox都要绑定一个ngModel,有时候就会觉得头很懵,因为有太多ngModel;如果checkbox很多的话,排版也很乱:

    这真的是多选吗?

    所以我觉得应该换一种思路去多选,我觉得标签这种东西其实更适合多选。

    2. 组件应该如何设计

    我个人觉得,组件的设计应该非常符合正常人的思路:
    既然是数据处理,那么组件作为一个黑盒,只需要让用户输入一个值,然后得到一个值就行。又既然是多选,那么让用户输入一个数组,然后得到一个新的数组就可以了。下面是一个数组:

    $scope.userList=[
            {
                name:'樱木花道',
                height:189.5
            },
            {
                name:'流川枫',
                height:187
            },
            {
                name:'三井寿',
                height:183
            },
            {
                name:'宫城良田',
                height:168
            },
            {
                name:'赤木刚宪',
                height:197
            },
        ]
    

    在组件中将上面的数组作为输入值:<ka-tags>是组件名称

    index.html
    <ka-tags input-list="userList"></ka-tags>
    
    ka-tags.html
    <div class="m-ka-tags">
        <div class="originData">
            <span ng-repeat="item in inputList">{{item}}</span>
        </div>
    </div>
    
    app.directive('kaTags',function(){
        return {
            templateUrl:'js/ka-tags.html',
            scope:{
                inputList:'=inputList'
            },
            link:function(){           
            }
        }
    })
    

    得到如下:

    image.png

    一般的业务逻辑都是:选择一些选项,然后将选好的选项发送给后台处理,所以就如上面所说,还需要一个outputList,也就是结果。在angular中,往往是一个controller负责一个业务逻辑,所以我希望输出的时候可以直接让controller得到数据:通常我会在scope上建立一个新的属性用于存放处理后的数据,然后通过ngModel把这个数据与组件抛出来的处理后的数据捆绑到一起,就可以无缝连接了。

    $scope.resultList=[];
    
    <ka-tags input-list="userList" ng-model="resultList"></ka-tags>
    

    接下来就是实现组件了,组件内部需要三个List,第一个是用户输入进来的原始List这个list要始终保持不动,第二个是原始List的拷贝,我在实际操作的时候只操作这个拷贝,这样就不会影响用户的原始数据,第三个是输出List,就是用户所有的选择项集合的list。

    link:function(scope){
                scope.outputList=[];//用于输出
                scope.oprateInputList=angular.copy(scope.inputList);//用于操作
            }
    

    接下来的事情就很简单了,每当用户选择的时候,就把用户选择的项目从oprateList中删除,加入到outputList中;如果用户从outputList中删除项目,就把删除的项目加入到oprateList中。这样一来就需要两个辅助方法,一个是addItemToArray(item,array),一个是removeItemFromArray(item,array)

    link:function(scope,element){
                scope.outputList=[];//用于输出
                scope.oprateInputList=angular.copy(scope.inputList);//用于操作,我不希望影响到用户传入的数组
                scope.addItemToArray=function(item,array){
                    array.push(item);
                }
                scope.removeItemFromArray=function(item,array,event){
                    var index;
                    for(var i=0;i<array.length;i++){
                        if(angular.equals(item,array[i])){
                            index=i;
                        }
                    }
                    array.splice(index,1);
                }
            }
    

    然后修改一下指令模板就行了

    <div class="m-ka-tags">
        <div class="outputData">
            <p class="tips" ng-if="!outputList.length">请从下面的标签选择</p>
            <span ng-repeat="item in outputList" ng-click="addItemToArray(item,oprateInputList);removeItemFromArray(item,outputList)">{{item}}<i class="subItemIcon">-</i></span>
        </div>
        <div class="originData">
            <span ng-repeat="item in oprateInputList" ng-click="addItemToArray(item,outputList);removeItemFromArray(item,oprateInputList)">{{item}} <i class="addItemIcon">+</i></span>
        </div>
    </div>
    

    现在就可以实现这种功能了:

    image.png

    剩下的就是做一个小完善:给组件传入一个值,让组件根据值来显示对象,比如我输入name,就显示人名,输入height,就显示身高

     scope:{
                inputList:'=inputList',
                displayKey:'@'
            },
    
    <ka-tags input-list="userList" ng-model="resultList" display-key="name"></ka-tags>
    
    <div class="m-ka-tags">
        <div class="outputData">
            <p class="tips" ng-if="!outputList.length">请从下面的标签选择</p>
            <span ng-repeat="item in outputList" ng-click="addItemToArray(item,oprateInputList);removeItemFromArray(item,outputList)">{{item[displayKey]}}<i class="subItemIcon">-</i></span>
        </div>
        <div class="originData">
            <span ng-repeat="item in oprateInputList" ng-click="addItemToArray(item,outputList);removeItemFromArray(item,oprateInputList)">{{item[displayKey]}} <i class="addItemIcon">+</i></span>
        </div>
    </div>
    

    最后把输出和外面的scope数据绑定一下就行了:

    app.directive('kaTags',function($compile,$timeout){
        return {
            templateUrl:'js/ka-tags.html',
            scope:{
                inputList:'=inputList',
                displayKey:'@',
                outputList:'=ngModel'
            },
            link:function(scope,element){
                scope.oprateInputList=angular.copy(scope.inputList);//用于操作,我不希望影响到用户传入的数组
                scope.addItemToArray=function(item,array){
                    array.push(item);
                }
                scope.removeItemFromArray=function(item,array,event){
                    var index;
                    for(var i=0;i<array.length;i++){
                        if(angular.equals(item,array[i])){
                            index=i;
                        }
                    }
                    array.splice(index,1);
                }
            }
        }
    })
    

    我把demo传到git上面,如果要是有幸能被哪位大哥看到,希望可以指出我的不足,以及指点指点我如何提高自己对组件的认识,谢谢!

    github地址

    相关文章

      网友评论

        本文标题:用angular写多选组件以及开发时的所思所想

        本文链接:https://www.haomeiwen.com/subject/bzpofxtx.html