是这样的,要创建一个登录用的东西,但卡在自定义指令上。
登录要求有一个账号输入框,一个密码输入框。
因为要兼容IE8,所以PLACEHOLDER属性不能直接用。需要使用自定义指令来完成。
账号可以是手机,也可以是邮箱,也可以是普通账号。
邮箱需要自动生成后缀,所以也需要自定义指令。可以设定是否需要在输入了@
之后再显示邮箱提示。
账号需要可以自己验证,这又要引入自定义指令来写验证(从angular官网上看到的方法,自定义验证器)。
现在要使用多重自定义指令,来完成这个东西(如果大家有更好的办法,也可以不用这个,请告诉我,谢谢)。
我的想法是,先定义一个自定义指令,可以让它的PLACEHOLDER在需要的时候显示出来。然后在此基础上定义一个EMAIL指令,当输入账号的时候,自动给它加上各种域名的后缀,以供选择。最后再在这个基础上,定义一个PASSPORT指令,可以判断当前输入的内容是不是可用的账号(手机/邮箱/普通用户名)。
但是问题来了,如果要在同一个作用域中使用多个这种自定义指令的话,指令就必须是分离作用域,但是这三层的自定义指令,没办法都定分离作用域,会报错。如果要使各个此种指令分离的话,想到使用ng-repeat,但是ng-repeat生成的class又没办法在生成之后,自动编译成正常的指令……
我知道我说的有点儿乱,如果大家有别的好办法,请交流一下,谢谢。最后上代码……
主文件
<body ng-app="Main">
<form novalidate name="LoginForm">
<p ng-form class="dir-text-placeholder dir-text-email dir-text-passport"
ng-init="needAt=true;
name='user_passport';
id='user_passport';
placeholder='用户名/邮箱/手机';">
</p>
</form>
</body>
angular.module('Main', [])
.directive('dirTextPlaceholder', [function () {
return {
restrict: 'C',
priority:111,
controller:function(){
console.info('in textPlaceholder')
},
link: function (scope, iElement, iAttrs) {
var input=iElement.find('input').eq(0);
scope.$watch("value",function(newValue,oldValue){
if(!!newValue && !oldValue)
input.addClass("chi-full").removeClass("chi-empty");
else if(!newValue && !!oldValue)
input.addClass("chi-empty").removeClass("chi-full");
});
},
templateUrl:"text-placeholder.html"
};
}])
.directive('dirTextEmail', ['$compile','$timeout',function ($compile,$timeout) {
var hosts='126.com|163.com|qq.com|sina.com|yeah.net'.split('|');
return {
restrict: 'C',
priority:11,
require: '?dirTextPlaceholder',
controller:function(){
console.info('in textEmail')
},
link: function (scope, iElement, iAttrs) {
iElement.append("<ul></ul>")
var input=iElement.find('input').eq(0),
ul=iElement.find('ul').eq(0),
li=angular.element('<li ng-repeat="email in emails | filter:host" ng-click="setEmail(email)">{{email}}</li>');
$compile(li)(scope);
ul.append(li);
scope.$watch("value",function(newValue){
if(newValue===undefined) return false;
var indexAt=newValue.indexOf('@');
if(scope.needAt && !~indexAt) return false;
scope.host=newValue.substring(indexAt);
var passport=newValue.substring(0,indexAt);
var emails=[];
for(var n=0;n<hosts.length;n++) emails.push(passport+'@'+hosts[n]);
scope.emails=emails;
emails=null;
$timeout(function(){
if(ul.children().length==1 && ul.children().eq(0).html()==newValue)
ul.hide();
else ul.show();
});
});
scope.setEmail=function(email){
scope.value=email;
}
}
};
}])
.directive('dirTextPassport', ['$rootScope',function ($rootScope) {
return {
restrict: 'C',
priority:1,
require: '?dirTextEmail',
controller: function(){
console.info('in textPassport')
},
link: function (scope, iElement, iAttrs) {
var ptr=/^\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}|(13\d|14[57]|15[^4,\D]|17[678]|18\d)\d{8}|170[059]\d{7}$/,
input=iElement.find('input').eq(0),
controller=angular.element(iElement).scope();
console.log($rootScope)
//写到这儿的时候,想起来,账号跟密码要放在同一个作用域下,
//所以第一个指令不采用分离作用域是不行的,但是分离之后,
//后续的跟它作用在同一DOM上的其它指令又不能再用分离作用域,我就不会了……
}
};
}])
模板文件text-placeholder.html
<input type="{{type}}" name="{{name}}" id="{{id}}" ng-model="value" autocomplete="off">
<label for="{{id}}">{{placeholder}}</label>
これは IE8 プレースホルダー互換性に対する解決策です。
個人的には、ロジックが複雑すぎるため、ニーズを完了するための手順を書くことはお勧めしません。 Angular のハイライトが命令であるという意味ではなく、命令はエクスポートする必要があります。単なるログインインターフェースであり、コントローラに検証ロジックを書き込むと、コード量が少なくとも2倍になり、可読性も良くありません。
学校を辞めました^^