很久以前,那时候还不懂写网页。在电视上看到一个外国人说他觉得现在网页太low了,很多东西都只能看,不能改,我要去努力改变这个现状,于是开始学习写代码。
网页可以自己想怎么改就怎么改,确实很有意思。今天由于脑洞一开,把自己的业务也做成了这样。
在这里,主要介绍一下我封装的指令,以及对上面问题的一些思考。
背景:
业务是这样的,我们要开发用户的个人中心页面,一开始是准备做两个页面,一个给用户看,一个给用户编辑。然后,我们考虑到这样好像太麻烦了,最好是让用户想修改啥就修改啥,而不是说看到一整个表单,输入框。然后就像,那我们在每个条目背后添加一个很小的修改按钮,点击修改的话,一开隐藏的输入框就会出现,显示信息的块就会隐藏,如此循环。这样看起来还不错。但是问题又来了,那么多按钮,看起来太奇怪了。那我把修改都去掉,直接让每个信息块都可以点,点一下就切换到可以改的状态。bingo,这个主意不错。于是开始实现了。
分析:
每个信息组有一个初始状态,一个修改状态。
- 初始状态显示label和span,点击span的话切换到修改状态
- 修改状态显示label和input,还有保存和取消按钮。保存按钮可以更新修改,然后回到初始状态,取消则是退回到初始状态。
修改结束后,检测表单中的值是否被改变,根据检测值提示用户要不要提交表单。
实现:
app.directive('inputGroup',function($compile){
return {
restrict : 'A',
require : 'ngModel',
link : function(scope,element,attrs,ngModel){
console.log(scope);
var subScope = scope.$new(true);
subScope.label = attrs.label;
function toggleHiden(params){
for(var i in params)
params[i]
&& params[i].toggleClass
&& params[i].toggleClass("hidden");
}
subScope.save = function(){
subScope.value = ngModel.$modelValue;
toggleHiden(elements);
}
subScope.cancel = function(){
//取消时,设置输入框的值为原子作用域获取到的值
element.val(subScope.value);
toggleHiden(elements);
}
var div = $compile('<div><div>')(subScope);
var label = $compile('<label>{{label}}</label>')(subScope);
var span = $compile('<span ng-click="save()">{{value|show}}</span>')(subScope);
var save = $compile('<button ng-click="save()">保存</button>')(subScope);
var cancer = $compile('<button ng-click="cancel()">取消</button>')(subScope);
var elements = [element,save,span,cancer];
var hiddens = [element,save,cancer];
toggleHiden(hiddens);
div.attr('class',attrs.classname);
element.wrap(div);
element.after(label);
label.after(element);
element.after(span);
span.after(save);
save.after(cancer);
scope.$watch(function(){
return true;
},function(){
subScope.value = ngModel.$modelValue;
});
}
}
});
一些辅助的css
.hidden{
display:none;
}
.anti{
}
.anti label{
display: inline-block;
width:50px;
}
.anti span{
}
.anti button{
margin:5px;
}
<body ng-app="app" ng-controller="testCtrl as vm">
<input type="text" ng-model="vm.a" input-group label="用户名" classname="anti">
<input type="text" ng-model="vm.b" input-group label="用户名" classname="anti">
</body>
效果展示
代码分析
inputGroup是一个装饰器型指令,会读取指令上的其他属性如:label、className。并依赖于ngModel指令。
在link函数中,我们利用$compile服务生成了5个活dom。分别添加在input指令的前面、后面、包裹。
为保存按钮绑定toggle事件和更新子作用域。
为取消按钮绑定toggle事件和更新input的值,从而改变model中的值。
存在的问题
1.解决不了的问题:只能适应单个input,不易于扩展。
2.丑陋的语法,由于在创建子作用域的时候,首次获取ngModel.$modelvalue的值是undefined,视图上就显示undefined。我就加了一个$watch,在监控函数中取值,这样好像就能达到在首次取出正确值得目的。但这种做法实在是挫。还需要我再深入学习Angular。
最后
和开头那个人的梦想相比,还差得远,不够由于他的启发,才产生了这样的想法,希望这个指令能让我少写很多代码。