AngularJS指令可以為給你的訪問者提供更好的用戶體驗,比如通過展示用戶頭像來使頁面看起來更具個性化。在你的注冊表單中,可以在電子郵箱地址一欄的旁邊展示一個頭像,指示用戶輸入的是否是一個正確的郵件地址。如果在你的表單中有可選輸入項,你可以默認隱藏它們,當用戶點擊時再展示出來,並且立刻自動將焦點對准第一個輸入框。這些方法非常容易實現,並且可以通過指令來獲得復用。
你有許多方式來構建AngularJS指令。關於如果創建用戶指令已經有非常多的教程和指導(所以我不打算在此描述一些基本的東西):
AngularJS:開發者指南
Sidepoint:實用指南
...
我這裡選取了三條對於提升用戶體驗非常有幫助的指令,並且我很早就將其應用在產品中。
為了在你的應用中展示頭像圖片,你需要使用用戶的電子郵件地址,將地址轉換為小寫並使用md5加密該字符串。所以聰明的做法是使用指令來做到這些,並且可以復用。
/*
* A simple Gravatar Directive
* @example
* <gravatar-image email="[email protected]" size="50"></gravatar-image>
*/
app.directive(
'gravatarImage'
,
function
() {
return
{
restrict:
'AE'
,
replace:
true
,
required:
'email'
,
template:
'<img ng-src="https://www.gravatar.com/avatar/{{hash}}?s={{size}}&d=identicon" />'
,
link:
function
(scope, element, attrs) {
attrs.$observe(
'email'
,
function
(value) {
if
(!value) {
return
; }
// MD5 (Message-Digest Algorithm) by WebToolkit
var
md5=
function
(s){
function
L(k,d){
return
(k<<d)|(k>>>(32-d));}
function
K(G,k){
var
I,d,F,H,x;F=(G&2147483648);H=(k&2147483648);I=(G&1073741824);d=(k&1073741824);x=(G&1073741823)+(k&1073741823);
if
(I&d){
return
(x^2147483648^F^H);}
if
(I|d){
if
(x&1073741824){
return
(x^3221225472^F^H);}
else
{
return
(x^1073741824^F^H);}}
else
{
return
(x^F^H);}}
function
r(d,F,k){
return
(d&F)|((~d)&k);}
function
q(d,F,k){
return
(d&k)|(F&(~k));}
function
p(d,F,k){
return
(d^F^k);}
function
n(d,F,k){
return
(F^(d|(~k)));}
function
u(G,F,aa,Z,k,H,I){G=K(G,K(K(r(F,aa,Z),k),I));
return
K(L(G,H),F);}
function
f(G,F,aa,Z,k,H,I){G=K(G,K(K(q(F,aa,Z),k),I));
return
K(L(G,H),F);}
function
D(G,F,aa,Z,k,H,I){G=K(G,K(K(p(F,aa,Z),k),I));
return
K(L(G,H),F);}
function
t(G,F,aa,Z,k,H,I){G=K(G,K(K(n(F,aa,Z),k),I));
return
K(L(G,H),F);}
function
e(G){
var
Z;
var
F=G.length;
var
x=F+8;
var
k=(x-(x%64))/64;
var
I=(k+1)*16;
var
aa=Array(I-1);
var
d=0;
var
H=0;
while
(H<F){Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=(aa[Z]|(G.charCodeAt(H)<<d));H++;}Z=(H-(H%4))/4;d=(H%4)*8;aa[Z]=aa[Z]|(128<<d);aa[I-2]=F<<3;aa[I-1]=F>>>29;
return
aa;}
function
B(x){
var
k=
""
,F=
""
,G,d;
for
(d=0;d<=3;d++){G=(x>>>(d*8))&255;F=
"0"
+G.toString(16);k=k+F.substr(F.length-2,2);}
return
k;}
function
J(k){k=k.replace(/rn/g,
"n"
);
var
d=
""
;
for
(
var
F=0;F<k.length;F++){
var
x=k.charCodeAt(F);
if
(x<128){d+=String.fromCharCode(x);}
else
{
if
((x>127)&&(x<2048)){d+=String.fromCharCode((x>>6)|192);d+=String.fromCharCode((x&63)|128);}
else
{d+=String.fromCharCode((x>>12)|224);d+=String.fromCharCode(((x>>6)&63)|128);d+=String.fromCharCode((x&63)|128);}}}
return
d;}
var
C=Array();
var
P,h,E,v,g,Y,X,W,V;
var
S=7,Q=12,N=17,M=22;
var
A=5,z=9,y=14,w=20;
var
o=4,m=11,l=16,j=23;
var
U=6,T=10,R=15,O=21;s=J(s);C=e(s);Y=1732584193;X=4023233417;W=2562383102;V=271733878;
for
(P=0;P<C.length;P+=16){h=Y;E=X;v=W;g=V;Y=u(Y,X,W,V,C[P+0],S,3614090360);V=u(V,Y,X,W,C[P+1],Q,3905402710);W=u(W,V,Y,X,C[P+2],N,606105819);X=u(X,W,V,Y,C[P+3],M,3250441966);Y=u(Y,X,W,V,C[P+4],S,4118548399);V=u(V,Y,X,W,C[P+5],Q,1200080426);W=u(W,V,Y,X,C[P+6],N,2821735955);X=u(X,W,V,Y,C[P+7],M,4249261313);Y=u(Y,X,W,V,C[P+8],S,1770035416);V=u(V,Y,X,W,C[P+9],Q,2336552879);W=u(W,V,Y,X,C[P+10],N,4294925233);X=u(X,W,V,Y,C[P+11],M,2304563134);Y=u(Y,X,W,V,C[P+12],S,1804603682);V=u(V,Y,X,W,C[P+13],Q,4254626195);W=u(W,V,Y,X,C[P+14],N,2792965006);X=u(X,W,V,Y,C[P+15],M,1236535329);Y=f(Y,X,W,V,C[P+1],A,4129170786);V=f(V,Y,X,W,C[P+6],z,3225465664);W=f(W,V,Y,X,C[P+11],y,643717713);X=f(X,W,V,Y,C[P+0],w,3921069994);Y=f(Y,X,W,V,C[P+5],A,3593408605);V=f(V,Y,X,W,C[P+10],z,38016083);W=f(W,V,Y,X,C[P+15],y,3634488961);X=f(X,W,V,Y,C[P+4],w,3889429448);Y=f(Y,X,W,V,C[P+9],A,568446438);V=f(V,Y,X,W,C[P+14],z,3275163606);W=f(W,V,Y,X,C[P+3],y,4107603335);X=f(X,W,V,Y,C[P+8],w,1163531501);Y=f(Y,X,W,V,C[P+13],A,2850285829);V=f(V,Y,X,W,C[P+2],z,4243563512);W=f(W,V,Y,X,C[P+7],y,1735328473);X=f(X,W,V,Y,C[P+12],w,2368359562);Y=D(Y,X,W,V,C[P+5],o,4294588738);V=D(V,Y,X,W,C[P+8],m,2272392833);W=D(W,V,Y,X,C[P+11],l,1839030562);X=D(X,W,V,Y,C[P+14],j,4259657740);Y=D(Y,X,W,V,C[P+1],o,2763975236);V=D(V,Y,X,W,C[P+4],m,1272893353);W=D(W,V,Y,X,C[P+7],l,4139469664);X=D(X,W,V,Y,C[P+10],j,3200236656);Y=D(Y,X,W,V,C[P+13],o,681279174);V=D(V,Y,X,W,C[P+0],m,3936430074);W=D(W,V,Y,X,C[P+3],l,3572445317);X=D(X,W,V,Y,C[P+6],j,76029189);Y=D(Y,X,W,V,C[P+9],o,3654602809);V=D(V,Y,X,W,C[P+12],m,3873151461);W=D(W,V,Y,X,C[P+15],l,530742520);X=D(X,W,V,Y,C[P+2],j,3299628645);Y=t(Y,X,W,V,C[P+0],U,4096336452);V=t(V,Y,X,W,C[P+7],T,1126891415);W=t(W,V,Y,X,C[P+14],R,2878612391);X=t(X,W,V,Y,C[P+5],O,4237533241);Y=t(Y,X,W,V,C[P+12],U,1700485571);V=t(V,Y,X,W,C[P+3],T,2399980690);W=t(W,V,Y,X,C[P+10],R,4293915773);X=t(X,W,V,Y,C[P+1],O,2240044497);Y=t(Y,X,W,V,C[P+8],U,1873313359);V=t(V,Y,X,W,C[P+15],T,4264355552);W=t(W,V,Y,X,C[P+6],R,2734768916);X=t(X,W,V,Y,C[P+13],O,1309151649);Y=t(Y,X,W,V,C[P+4],U,4149444226);V=t(V,Y,X,W,C[P+11],T,3174756917);W=t(W,V,Y,X,C[P+2],R,718787259);X=t(X,W,V,Y,C[P+9],O,3951481745);Y=K(Y,h);X=K(X,E);W=K(W,v);V=K(V,g);}
var
i=B(Y)+B(X)+B(W)+B(V);
return
i.toLowerCase();};
scope.hash = md5(value.toLowerCase());
scope.size = attrs.size;
if
(angular.isUndefined(scope.size)) {
scope.size = 60;
// default to 60 pixels
}
});
}
};
});
2. Focus-Me
It is really just a small directive, but it’s awesome. In the example below the user clicks on a link, where he makes an input visible, which gets automatically focused. So he doesn’t need to click
in
the input field when it shows up.
/**
* Sets focus to this element if the value of focus-me is true.
* @example
* <a ng-click="addName=true">add name</a>
* <input ng-show="addName" type="text" ng-model="name" focus-me="{{addName}}" />
*/
app.directive(
'focusMe'
, [
'$timeout'
,
function
($timeout) {
return
{
scope: { trigger:
'@focusMe'
},
link:
function
(scope, element) {
scope.$watch(
'trigger'
,
function
(value) {
if
(value ===
"true"
) {
$timeout(
function
() {
element[0].focus();
});
}
});
}
};
}]);
這其實是一個非常簡短的指令,但是非常棒。在下面的例子中,用戶點擊了一個鏈接,顯示的輸入框需要能夠自動獲得焦點。這樣,用戶在頁面顯示時不必再手動點擊文本域。
/**
* Sets focus to this element if the value of focus-me is true.
* @example
* <a ng-click="addName=true">add name</a>
* <input ng-show="addName" type="text" ng-model="name" focus-me="{{addName}}" />
*/
app.directive(
'focusMe'
, [
'$timeout'
,
function
($timeout) {
return
{
scope: { trigger:
'@focusMe'
},
link:
function
(scope, element) {
scope.$watch(
'trigger'
,
function
(value) {
if
(value ===
"true"
) {
$timeout(
function
() {
element[0].focus();
});
}
});
}
};
}]);
我們使用contenteditable而不是textarea元素的最主要原因在於使用前者可以在布局和UI中沒有限制。我們在編輯器中使用這條指令可以實現將contenteditable元素的html和ng-model進行一個雙向綁定。目前,在contenteditable元素中並沒有支持ng-model。
/**
* Two-way data binding for contenteditable elements with ng-model.
* @example
* <p contenteditable="true" ng-model="text"></p>
*/
app.directive(
'contenteditable'
,
function
() {
return
{
require:
'?ngModel'
,
link:
function
(scope, element, attrs, ctrl) {
// Do nothing if this is not bound to a model
if
(!ctrl) {
return
; }
// Checks for updates (input or pressing ENTER)
// view -> model
element.bind(
'input enterKey'
,
function
() {
var
rerender =
false
;
var
html = element.html();
if
(attrs.noLineBreaks) {
html = html.replace(/<div>/g,
''
).replace(/<br>/g,
''
).replace(/<\/div>/g,
''
);
rerender =
true
;
}
scope.$apply(
function
() {
ctrl.$setViewValue(html);
if
(rerender) {
ctrl.$render();
}
});
});
element.keyup(
function
(e){
if
(e.keyCode === 13){
element.trigger(
'enterKey'
);
}
});
// model -> view
ctrl.$render =
function
() {
element.html(ctrl.$viewValue);
};
// load init value from DOM
ctrl.$render();
}
};
});
結論:AngularJS指令可用於改善用戶體驗
我希望經過文中的介紹,你會感悟到AngularJS指令的有用之處。
對我而言,指令是AngularJS中最激動人心的特性。創建可重用的組件,並可以將其添加到純粹的HTML應用程序庫,這是多麼難以置信並且強大的功能。由於指令實用,並且大部分指令書寫難度不高,許多開發者早已對於目前受歡迎的庫開發了許多指令。舉例來說,AngularJS團隊已經為Bootstrap創建了一系列的指令(難道還有人不用它嗎?),被稱作UI Bootstrap。
帶你走近AngularJS系列:
如何在 AngularJS 中對控制器進行單元測試 http://www.linuxidc.com/Linux/2013-12/94166.htm
在 AngularJS 應用中通過 JSON 文件來設置狀態 http://www.linuxidc.com/Linux/2014-07/104083.htm
AngularJS 之 Factory vs Service vs Provider http://www.linuxidc.com/Linux/2014-05/101475.htm
AngularJS —— 使用 ngResource、RESTful APIs 和 Spring MVC 框架提交數據 http://www.linuxidc.com/Linux/2014-07/104402.htm
AngularJS 的詳細介紹:請點這裡
AngularJS 的下載地址:請點這裡