javascript
Ext JS 5初探(二) ——Bootstrap.js
在Bootstrap.js文件中,總共有1500行(包含注釋和空行),使用編輯器的代碼折疊功能就如下圖可以一窺全貌了。
從代碼可以看到,這里主要定義了Ext.Boot、Ext.globalEval、Ext.Microloader和Ext.manifest這4個(gè)對(duì)象或?qū)傩浴jP(guān)鍵代碼是最后一句的調(diào)用Ext.Microloader的load方法,下面來(lái)研究一下這個(gè)load方法,代碼如下:
load: function (manifestDef) {var manifest = Microloader.initManifest(manifestDef),loadOrder = manifest.loadOrder,loadOrderMap = (loadOrder) ? Boot.createLoadOrderMap(loadOrder) : null,urls = [],js = manifest.js || [],css = manifest.css || [],resources = js.concat(css),resource, i, len, include,loadedFn = function () {_loaded = true;Microloader.notify();};for (len = resources.length, i = 0; i < len; i++) {resource = resources[i];include = true;if (resource.platform && !Microloader.filterPlatform(resource.platform)) {include = false;}if (include) {urls.push(resource.path);}}if (loadOrder) {manifest.loadOrderMap = loadOrderMap;}Boot.load({url: urls,loadOrder: loadOrder,loadOrderMap: loadOrderMap,sequential: true,success: loadedFn,failure: loadedFn}); },代碼第一句執(zhí)行了Microloader的initManifest方法,代碼如下:initManifest: function (manifest) {Microloader.init();var tmpManifest = manifest || Ext.manifest;if (typeof tmpManifest === "string") {var url = Boot.baseUrl + tmpManifest + ".json",content = Boot.fetchSync(url);tmpManifest = JSON.parse(content.content);}Ext.manifest = tmpManifest;return tmpManifest; },
根據(jù)load方法的調(diào)用,可以知道m(xù)anifest為null,不過(guò)這里第一句又先調(diào)用了Microloader的init方法,代碼如下:init: function () {Microloader.initPlatformTags();Ext.filterPlatform = Microloader.filterPlatform; },
又要跳到initPlatformTags方法,快給轉(zhuǎn)暈了,代碼如下:initPlatformTags: function () {Microloader.platformTags = Microloader.detectPlatformTags(Microloader.platformTags); },
還跳,這里省去n字,繼續(xù)去看detectPlatformTags方法,代碼如下:detectPlatformTags: function (tags) {var ua = navigator.userAgent,isMobile = tags.isMobile = /Mobile(\/|\s)/.test(ua),isPhone, isDesktop, isTablet, touchSupported, isIE10, isBlackberry,element = document.createElement('div'),uaTagChecks = ['iPhone','iPod','Android','Silk','Android 2','BlackBerry','BB','iPad','RIM Tablet OS','MSIE 10','Trident','Chrome','Tizen','Firefox','Safari','Windows Phone'],isEventSupported = function(name, tag) {if (tag === undefined) {tag = window;}var eventName = 'on' + name.toLowerCase(),isSupported = (eventName in element);if (!isSupported) {if (element.setAttribute && element.removeAttribute) {element.setAttribute(eventName, '');isSupported = typeof element[eventName] === 'function';if (typeof element[eventName] !== 'undefined') {element[eventName] = undefined;}element.removeAttribute(eventName);}}return isSupported;},uaTags = {},len = uaTagChecks.length, check, c;for (c = 0; c < len; c++) {check = uaTagChecks[c];uaTags[check] = new RegExp(check).test(ua);}isPhone =(uaTags.iPhone || uaTags.iPod) ||(!uaTags.Silk && (uaTags.Android && (uaTags['Android 2'] || isMobile))) ||((uaTags.BlackBerry || uaTags.BB) && uaTags.isMobile) ||(uaTags['Windows Phone']);isTablet =(!tags.isPhone) && (uaTags.iPad ||uaTags.Android ||uaTags.Silk ||uaTags['RIM Tablet OS'] ||(uaTags['MSIE 10'] && /; Touch/.test(ua)));touchSupported =// if the browser has touch events we can be reasonably sure the device has// a touch screenisEventSupported('touchend') ||// browsers that use pointer event have maxTouchPoints > 0 if the// device supports touch input// http://www.w3.org/TR/pointerevents/#widl-Navigator-maxTouchPointsnavigator.maxTouchPoints ||// IE10 uses a vendor-prefixed maxTouchPoints propertynavigator.msMaxTouchPoints;isDesktop = !isPhone && !isTablet;isIE10 = uaTags['MSIE 10'];isBlackberry = uaTags.Blackberry || uaTags.BB;apply(tags, Microloader.loadPlatformsParam(), {phone: isPhone,tablet: isTablet,desktop: isDesktop,touch: touchSupported,ios: (uaTags.iPad || uaTags.iPhone || uaTags.iPod),android: uaTags.Android || uaTags.Silk,blackberry: isBlackberry,safari: uaTags.Safari && isBlackberry,chrome: uaTags.Chrome,ie10: isIE10,windows: isIE10 || uaTags.Trident,tizen: uaTags.Tizen,firefox: uaTags.Firefox});if (Ext.beforeLoad) {tags = Ext.beforeLoad(tags);}return tags; },
好了,這次不用再跳了。代碼先調(diào)用navigator.userAgent返回了瀏覽器用于 HTTP 請(qǐng)求的用戶代理頭的值,這個(gè)值可用來(lái)檢查瀏覽器和版本號(hào)。如果值包含了字符串Mobile,說(shuō)明是移動(dòng)設(shè)備,這時(shí)候isMobile為true。在定義了一堆變量后,在頁(yè)面中添加了一個(gè)div元素。接下來(lái)的uaTagChecks根據(jù)變量名可以知道,這是要檢測(cè)的標(biāo)記了。
接下來(lái)定義了isEventSupported函數(shù),看名字就知道是用來(lái)檢測(cè)是否支持事件的。根據(jù)函數(shù)內(nèi)容,可以看到檢測(cè)方式有兩種,第一種就是檢測(cè)事件名是否在剛才創(chuàng)建的元素div內(nèi),如果在,說(shuō)明支持。第二種方法就是div元素上添加事件屬性,然后判斷元素對(duì)象內(nèi)的事件屬性是否為function,如果是,說(shuō)明支持,否則就是不支持了。
定義結(jié)束后,就開(kāi)始使用循環(huán)來(lái)檢測(cè)平臺(tái)屬性了,檢測(cè)結(jié)果將保存在uaTags對(duì)象中,對(duì)象中的屬性名稱就是uaTagChecks中的字符串,值就是檢測(cè)值。
檢測(cè)完之后就要給幾個(gè)變量賦值了,賦值完成后,會(huì)調(diào)用apply方法將對(duì)象的成員復(fù)制到tags中。在調(diào)用apply方法時(shí),還調(diào)用了loadPlatformsParam方法,該方法我就不列了,它的主要作用就是可通過(guò)訪問(wèn)地址的platformTags參數(shù)來(lái)自定義平臺(tái)參數(shù),這樣做的目的是可以通過(guò)瀏覽器做一些模擬效果,如桌面pc模擬平板的效果。
下一句判斷Ext.beforeLoad是否存在,在當(dāng)前情況是不存在的,所以,這段代碼可以忽略。最后是將平臺(tái)檢測(cè)結(jié)果返回了。
返回initPlatformTags方法,可以知道Microloader.platformTags現(xiàn)在指向的平臺(tái)檢測(cè)結(jié)果。再返回init方法,在計(jì)算出平臺(tái)檢測(cè)結(jié)果后,會(huì)將Ext.filterPlatform屬性指向Microloader.filterPlatform方法,也就是說(shuō),在調(diào)用Ext的filterPlatform方法時(shí),會(huì)執(zhí)行Microloader.的filterPlatform方法,該方法的主要作用就是把不需要的平臺(tái)過(guò)濾掉。
好了,現(xiàn)在返回initManifest方法,在執(zhí)行完init方法后,會(huì)給tmpManifest賦值,由于在當(dāng)前情況下,manifest為null,所以tmpManifes的值將會(huì)是Ext.manifest的值,而從圖中可以知道,Ext.manifes的值是bootstrap,也就是說(shuō),現(xiàn)在tmpManifes的值是bootstrap。接下來(lái)判斷tmpManifes是否為字符串,當(dāng)前情況下,tmpManifes是字符串,所以要執(zhí)行判斷語(yǔ)句內(nèi)的代碼。先給url賦值,這個(gè)由Boot.baseUrl、tmpManifest和“.json”三部分構(gòu)成,先不管Boot.baseUrl,可以知道,這里要找的是bootstrap.json文件。接下來(lái)會(huì)調(diào)用Boot.fetchSync方法,代碼如下:
fetchSync: function(url) {var exception, xhr, status, content;exception = false;xhr = new XMLHttpRequest();try {xhr.open('GET', url, false);xhr.send(null);} catch (e) {exception = true;}status = (xhr.status === 1223) ? 204 :(xhr.status === 0 && ((self.location || {}).protocol === 'file:' ||(self.location || {}).protocol === 'ionp:')) ? 200 : xhr.status;content = xhr.responseText;xhr = null; // Prevent potential IE memory leakreturn {content: content,exception: exception,status: status};},從代碼中的new XMLHttpRequest這語(yǔ)句就知道,這段代碼的主要作用就是使用Ajax去加載bootstrap.json文件了。現(xiàn)在假定能正確加載bootstrap.json文件并返回initManifest方法。
在initManifest方法內(nèi),接下來(lái)要做的是調(diào)用JSON.parse將返回的數(shù)據(jù)解析為JSON對(duì)象,并Ext.manifest屬性指向該對(duì)象。最后將JSON對(duì)象返回laod方法。
在load方法的第二句,會(huì)先從返回的對(duì)象中取出loadOrder的值。在bootstrap.json文件中,loadOrder是一個(gè)由對(duì)象組成的數(shù)組,而每一個(gè)對(duì)象包含path、requires、uses和idx這4個(gè)成員。如果對(duì)于Ext JS有一定理解,那么要理解這4個(gè)成員不難。成員paths的值就是Ext JS類的腳本的路徑,requires和uese指的是這個(gè)類所需要的類和使用到的類,而idx則是這個(gè)類的唯一標(biāo)識(shí)。在requires和uese中就是使用這個(gè)唯一標(biāo)識(shí)來(lái)指定所需或使用到的類文件的。
把這個(gè)loadOrder取出后,會(huì)調(diào)用Boot.createLoadOrderMap方法進(jìn)行處理,代碼如下:
代碼的作用只是把loadOrder數(shù)組轉(zhuǎn)換為對(duì)象,對(duì)象的屬性名稱就是類文件的路徑,值就是類對(duì)象本身。
返回到load方法,在處理完loadOrder數(shù)組后,會(huì)繼續(xù)從bootstrap.json文件中把js和css的值取出來(lái),然后合并到resources數(shù)組中。在當(dāng)前項(xiàng)目中,bootstrap.json文件中的js和css的定義如下:
"js":[{"path":"app.js"}], "css":[{"path":"bootstrap.css"}這樣對(duì)于理解后面的循環(huán)就容易多了,由于在定義中,沒(méi)有platform這個(gè)成員,所以循環(huán)中的第一個(gè)判斷就會(huì)被跳過(guò),直接執(zhí)行第二個(gè)判斷了,也就是把路徑信息推人urls數(shù)組中。
處理完這個(gè),就開(kāi)始調(diào)用Boot.load方法了,代碼如下:
load: function (request) {if (request.sync || _syncMode) {return this.loadSync(request);}// Allow a raw array of paths to be passed.if (!request.url) {request = {url: request};}// If there is a request in progress, we must// queue this new request to be fired when the current request completes.if (_currentRequest) {_suspendedQueue.push(request);} else {Boot.expandLoadOrder(request);var url = request.url,urls = url.charAt ? [ url ] : url,length = urls.length,i;// Start the counter here. This is reduced as we notify this fellow of script// loads.request.urls = urls;request.loaded = 0;request.loading = length;request.charset = request.charset || _config.charset;request.buster = (('cache' in request) ? !request.cache : _config.disableCaching) &&(_config.disableCachingParam + '=' + (+new Date()));_currentRequest = request;request.sequential = false;for (i = 0; i < length; ++i) {Boot.loadUrl(urls[i], request);}}return this; },在這段代碼中,前面的代碼都是與處理請(qǐng)求地址有關(guān),而當(dāng)這些都準(zhǔn)備好了以后,就會(huì)調(diào)用Boot.loadUrl方法去加載文件了。而在Boot.loadUrl方法內(nèi),會(huì)調(diào)用Boot.create方法去創(chuàng)建加載標(biāo)記,代碼如下:
create: function (url, key) {var css = url && cssRe.test(url),el = doc.createElement(css ? 'link' : 'script'),prop;if (css) {el.rel = 'stylesheet';prop = 'href';} else {el.type = 'text/javascript';if (!url) {return el;}prop = 'src';if(Boot.hasAsync) {el.async = false;}}key = key || url;return _items[key] = {key: key,url: url,css: css,done: false,el: el,prop: prop,loaded: false,evaluated: false};},從代碼doc.createElement這句就可以看到,在這里會(huì)創(chuàng)建SCRIPT或LINK標(biāo)記去加載腳本或樣式。
這么簡(jiǎn)單的東西搞得那么復(fù)雜的一個(gè)原因是要確保類的加載順序,以確保不會(huì)出現(xiàn)類初始化時(shí)找不到依賴類的情況。因而,在整個(gè)加載過(guò)程中,需要監(jiān)控每個(gè)腳本的加載情況,在依賴類沒(méi)有加載完成之前,不去加載該類。
在bootstrap.json文件中,已經(jīng)把a(bǔ)pp.js、bootstrap.css等文件加進(jìn)去了,所以,在index.html文件中,只需要加載bootstrap.js文件就行了。
至此,我們已經(jīng)基本了解了Ext JS 5的啟動(dòng)過(guò)程了。現(xiàn)在的問(wèn)題是,我們?cè)趺慈ゼ虞d本地化文件。
轉(zhuǎn)載于:https://www.cnblogs.com/hainange/p/6334168.html
總結(jié)
以上是生活随笔為你收集整理的Ext JS 5初探(二) ——Bootstrap.js的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 论文:进度管理
- 下一篇: SampleCaptures wires