国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
啟動(dòng)和JQuery綁定--AngularJS學(xué)習(xí)筆記(二)

By

更新日期:

上一篇簡(jiǎn)單的分析了AngularJS的項(xiàng)目結(jié)構(gòu),后面就開(kāi)始分析具體的源代碼了。

從angularFiles.js中的定義可以看出有幾個(gè)文件直接位于src根目錄,并不是隸屬于某個(gè)模塊。這幾 個(gè)分別是minErr.js,Angular.js,loader.js,AngularPublic.js,jqLite.js,apis.js。

這幾個(gè)提供了AngularJS中很基礎(chǔ)的工具,比如angular.equals等,在文檔中它們中的部分被歸屬于 Global API中。

本文主要看看AngularJS的啟動(dòng)和JQuery綁定。

minErr.js

Javascript中有Error對(duì)象,用于表示運(yùn)行時(shí)錯(cuò)誤,但是它的功能比較單一,一般使用

1
new Error(message)

但是它的功能比較單一。而minErr是一個(gè)提供更豐富信息的工具。這樣生成的錯(cuò)誤信息將包含模塊名 稱和其他信息,同時(shí)還提供了模板功能。比如

1
2
3
var exampleMinErr = minErr('example');
var detailMinErr=exampleMinErr('one', 'This {0} is {1}', "v1", "v2");
detailMinErr.stack

顯示如下:

screenshot13

可以看出錯(cuò)誤還提供了對(duì)應(yīng)了文檔地址,不過(guò)其中的NG_VERSION_FULL看著有點(diǎn)奇怪,這里應(yīng)該顯示諸如1.2.7這樣的版本號(hào)。在 lib/grunt/utils.js中有一個(gè)處理,將NG_VERSION_FULL、NG_VERSION_MAJOR等替換了。

1
2
3
4
5
6
7
8
9
10
11
function(src, NG_VERSION, strict){
var processed = src
.replace(/"NG_VERSION_FULL"/g, NG_VERSION.full)
.replace(/"NG_VERSION_MAJOR"/, NG_VERSION.major)
.replace(/"NG_VERSION_MINOR"/, NG_VERSION.minor)
.replace(/"NG_VERSION_DOT"/, NG_VERSION.dot)
.replace(/"NG_VERSION_CDN"/, NG_VERSION.cdn)
.replace(/"NG_VERSION_CODENAME"/, NG_VERSION.codename);
if (strict !== false) processed = this.singleStrict(processed, '\n\n', true);
return processed;
}

這里的NG_VERSION信息是getVersion從package.json文件的version值中讀取的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function(){
if (version) return version;
var package = JSON.parse(fs.readFileSync('package.json', 'UTF-8'));
var match = package.version.match(/^([^\-]*)(?:\-(.+))?$/);
var semver = match[1].split('.');
var fullVersion = match[1];
if (match[2]) {
fullVersion += '-';
fullVersion += (match[2] == 'snapshot') ? getSnapshotSuffix() : match[2];
}
version = {
full: fullVersion,
major: semver[0],
minor: semver[1],
dot: semver[2].replace(/rc\d+/, ''),
codename: package.codename,
cdn: package.cdnVersion
};
return version;
}

現(xiàn)在來(lái)看看minErr的源碼,其實(shí)主要是模板替換功能。

1
2
3
message = prefix + template.replace(/\{\d+\}/g, function (match) {
...
}

這里的prefix是module名稱組成而成的,而這里使用了replace方法,匹配諸如{0},{1}的字符串,而 /g命令表示全局替換。而 function(match)是根據(jù)匹配的字符串生成對(duì)應(yīng)的替換字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function (match) {
var index = +match.slice(1, -1), arg;
if (index + 2 < templateArgs.length) {
arg = templateArgs[index + 2];
if (typeof arg === 'function') {
return arg.toString().replace(/ ?\{[\s\S]*$/, '');
} else if (typeof arg === 'undefined') {
return 'undefined';
} else if (typeof arg !== 'string') {
return toJson(arg);
}
return arg;
}
return match;
}

因?yàn)閭魅氲膮?shù)實(shí)質(zhì)上是類(lèi)似{0},{1}這樣的字符串,所以首先用slice(1,-1)去掉兩端的大括號(hào),然 后比較剩余的數(shù)字范圍是否正確,這里的+2是因?yàn)閭魅氲膮?shù)中第一個(gè)是code碼,第二個(gè)是模板,從第 三個(gè)開(kāi)始才是替換用的字符串。這里還針對(duì)不同的類(lèi)型有不同的處理。

Angular.js

這個(gè)文件涉及到了AngularJS的初始化,還提供了若干基礎(chǔ)方法,比如大小寫(xiě)轉(zhuǎn)化,瀏覽器適配, forEach,Uid生成,淺復(fù)制,深復(fù)制等。

其實(shí)這些基礎(chǔ)方法比較簡(jiǎn)單,這里只分析nextUid方法。調(diào)用它可以生成一個(gè)供Angular使用的唯一ID 。初始的uid為

1
uid = ['0', '0', '0'];

Angular的uid不是單純的數(shù)字,而是字母和數(shù)字的組合,這樣就不會(huì)增長(zhǎng)太快,也不會(huì)超值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function nextUid() {
var index = uid.length;
var digit;
while(index) {
index--;
digit = uid[index].charCodeAt(0);
if (digit == 57 /*'9'*/) {
uid[index] = 'A';
return uid.join('');
}
if (digit == 90 /*'Z'*/) {
uid[index] = '0';
} else {
uid[index] = String.fromCharCode(digit + 1);
return uid.join('');
}
}
uid.unshift('0');
return uid.join('');
}

首先是獲取uid的長(zhǎng)度,然后獲取最后一位,如果是9就變成“A”,如果是Z就變成0,不 然就是直接+1。如果長(zhǎng)度不夠了就增加uid數(shù)組長(zhǎng)度。這樣首先生成的就是001,然后是002…然后 是00Z,接下來(lái)就是010。nextUid方法在Scope中會(huì)被使用。

然后AngularJS的啟動(dòng)了,這里就涉及了兩個(gè)比較重要的方法:angularInit和bootstrap。

AngularJS官方文檔的第一個(gè)列子就是一個(gè)數(shù)據(jù)綁定的例子,顯示Hello {yourName}。

例子中html標(biāo)簽中添加了執(zhí)行ng-app,文檔說(shuō)這是告知AngularJS,這里是它的管理范圍,而實(shí)現(xiàn)就在angularInit中。

ng-app是一個(gè)自動(dòng)初始化的指令,而且只能有一個(gè)自動(dòng)初始化,其他的需要調(diào)用angular.bootstrap 啟動(dòng)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function angularInit(element, bootstrap) {
var elements = [element],
appElement,
module,
names = ['ng:app', 'ng-app', 'x-ng-app', 'data-ng-app'],
NG_APP_CLASS_REGEXP = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;
function append(element) {
element && elements.push(element);
}
forEach(names, function(name) {
names[name] = true;
append(document.getElementById(name));
name = name.replace(':', '\\:');
if (element.querySelectorAll) {
forEach(element.querySelectorAll('.' + name), append);
forEach(element.querySelectorAll('.' + name + '\\:'), append);
forEach(element.querySelectorAll('[' + name + ']'), append);
}
});
forEach(elements, function(element) {
if (!appElement) {
var className = ' ' + element.className + ' ';
var match = NG_APP_CLASS_REGEXP.exec(className);
if (match) {
appElement = element;
module = (match[2] || '').replace(/\s+/g, ',');
} else {
forEach(element.attributes, function(attr) {
if (!appElement && names[attr.name]) {
appElement = element;
module = attr.value;
}
});
}
}
});
if (appElement) {
bootstrap(appElement, module ? [module] : []);
}
}

該函數(shù)首先匹配指令本身,有4種ng:app,ng-app,x-ng-app,data-ng-app。我最開(kāi)始挺好奇的為什么 有四種寫(xiě)法,只有一種不是挺好的嘛。網(wǎng)上搜尋了一番發(fā)現(xiàn)了原因。

首先是data-ng-app。在html5標(biāo)準(zhǔn)中定義了data-為自定義屬性,這樣頁(yè)面就可以通過(guò)驗(yàn)證。x-也 是基于相似的原理。不過(guò)ng:app是為啥我確實(shí)沒(méi)有找到…望知道的朋友點(diǎn)撥一下。ng:app是為了兼容XML,格式為namespace:name,其他三種依次為:none,HTML5,xHtml。

然后依次匹配這四種執(zhí)行,直到appElement被賦值位置。確定了html元素位置以后通過(guò)正則表達(dá)式解 析module的名稱,因?yàn)檫@是可選參數(shù),所以如果沒(méi)有提供就自動(dòng)使用[]。當(dāng)然具體的初始化實(shí)際上是有 bootstrap函數(shù)完成的。

首先是doBootstrap函數(shù):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var doBootstrap = function() {
element = jqLite(element);
if (element.injector()) {
var tag = (element[0] === document) ? 'document' : startingTag(element);
throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
}
modules = modules || [];
modules.unshift(['$provide', function($provide) {
$provide.value('$rootElement', element);
}]);
modules.unshift('ng');
var injector = createInjector(modules);
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
function(scope, element, compile, injector, animate) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
}]
);
return injector;
};

首先先將元素轉(zhuǎn)為Jquery對(duì)象(如果沒(méi)有,則有jqLite提供Jquery的一個(gè)功能子集),然后判斷是否 有注入器了,是否已經(jīng)初始化了。然后判斷是否有modules,如果沒(méi)有就為空。然后根據(jù)modules生成注 入器,然后編譯。

jqLite.js

剛才啟動(dòng)的時(shí)候提到了將元素轉(zhuǎn)為JQuery對(duì)象,但是很明顯JQuery很流行,但不代表必須使用它。 AngularJS提供了jqLite,它提供了一個(gè)JQuery的子集,包含了addClass(),after(),append()等。當(dāng)然 針對(duì)AngularJS的特定,它還提供了controller(),injector()等方法。

首先有個(gè)小適配,針對(duì)不同的瀏覽器對(duì)應(yīng)事件的處理不同做了一個(gè)兼容:

1
2
3
4
5
6
addEventListenerFn = (window.document.addEventListener
function(element, type, fn) {element.addEventListener(type, fn, false);}
: function(element, type, fn) {element.attachEvent('on' + type, fn);}),
removeEventListenerFn = (window.document.removeEventListener
function(element, type, fn) {element.removeEventListener(type, fn, false); }
: function(element, type, fn) {element.detachEvent('on' + type, fn); });

其實(shí)主要是IE的問(wèn)題,如果沒(méi)有提供addEventListener方法,那么就使用attachEvent方法。

如果調(diào)用jqLite(element)方法,但是傳入的是一個(gè)String的話那么就會(huì)自動(dòng)生成一個(gè)html元素并插 入其中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if (isString(element)) {
var div = document.createElement('div');
// Read about the NoScope elements here:
// http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
div.innerHTML = '<div> </div>' + element; // IE insanity to make
NoScope elements work!
div.removeChild(div.firstChild); // remove the superfluous div
jqLiteAddNodes(this, div.childNodes);
var fragment = jqLite(document.createDocumentFragment());
fragment.append(this); // detach the elements from the temporary DOM div.
} else {
jqLiteAddNodes(this, element);
}

如果沒(méi)有使用JQuery,那么當(dāng)然好,所有功能由jqLite提供。如果使用JQuery,那么這個(gè)適配其實(shí)是 由Angular.js處理的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function bindJQuery() {
// bind to jQuery if present;
jQuery = window.jQuery;
// reset to jQuery or default to us.
if (jQuery) {
jqLite = jQuery;
extend(jQuery.fn, {
scope: JQLitePrototype.scope,
isolateScope: JQLitePrototype.isolateScope,
controller: JQLitePrototype.controller,
injector: JQLitePrototype.injector,
inheritedData: JQLitePrototype.inheritedData
});
// Method signature:
// jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArguments)
jqLitePatchJQueryRemove('remove', true, true, false);
jqLitePatchJQueryRemove('empty', false, false, false);
jqLitePatchJQueryRemove('html', false, false, true);
} else {
jqLite = JQLite;
}
angular.element = jqLite;
}

如果直接引用了JQuery,那么就會(huì)有一個(gè)window.jQuery。同時(shí)根據(jù)JQuery擴(kuò)展的原理,將 controller(),injector()等方法加入JQuery中,然后調(diào)用jqLitePatchJQueryRemove將JQuery的remove 等和$destroy等綁定。

結(jié)語(yǔ)

還有l(wèi)oader.js,AngularPublic.js,apis.js沒(méi)有分析,估摸著是下一篇的內(nèi)容。

附上幾個(gè)參考:

minError.js源碼

JavaScript replace() 方法

關(guān)于data-*的規(guī)定

關(guān)于IE的attachEvent和IE11支持addEventListener

版權(quán)聲明

《啟動(dòng)和JQuery綁定--AngularJS學(xué)習(xí)筆記(二)》黃云坤 創(chuàng)作,采用 知識(shí)共享 署名-相同方式共享 4.0 國(guó)際 許可協(xié)議進(jìn)行許可。

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
AngularJS 中的一些坑
ZH奶酪:JavaScript調(diào)用AngularJS的函數(shù)/$scope/變量
angularjs的$compile用法
jQuery和AngularJS的區(qū)別淺析
AngularJS實(shí)現(xiàn)長(zhǎng)按事件監(jiān)聽(tīng)(ng
jQuery函數(shù)attr()和prop()的區(qū)別
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服