这里是demo
我是一个angular1系列的重度爱好者,为什么喜欢它呢,因为我觉得angular1是接口设计的最漂亮的框架,虽然现在vue确实很火,但是我觉得vue的Expression部分并不足够智能。另外,可能是我的思维定势,我还是觉得Expression应该和一个对象互相绑定,就像我写的前端框架那样。怎么说呢,我坚持使用angular1,也许也是因为它的设计思路和我的思路更符合吧。当然,争论前端框架的优劣是很没意思的,所以其实在有的项目中,我也是选择了vue,没有什么原因,只是随心所欲而已。
其实用angular1写组件(也就是指令)是几乎每个使用者都会的,不过这次我的所思所想并不只是如何写代码而已,这经历了三个过程:
- 多选框的最好形式是什么?真的是前面画对勾选中吗?
- 一个组件如何设计的优雅,让前端傻瓜都会用?
- 我的以上想法是不是多余的?
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上面,如果要是有幸能被哪位大哥看到,希望可以指出我的不足,以及指点指点我如何提高自己对组件的认识,谢谢!
网友评论