javascript
Ext JS 5初探(二) ——Bootstrap.js
在Bootstrap.js文件中,總共有1500行(包含注釋和空行),使用編輯器的代碼折疊功能就如下圖可以一窺全貌了。
從代碼可以看到,這里主要定義了Ext.Boot、Ext.globalEval、Ext.Microloader和Ext.manifest這4個對象或屬性。關鍵代碼是最后一句的調用Ext.Microloader的load方法,下面來研究一下這個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}); },代碼第一句執行了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; },
根據load方法的調用,可以知道manifest為null,不過這里第一句又先調用了Microloader的init方法,代碼如下:init: function () {Microloader.initPlatformTags();Ext.filterPlatform = Microloader.filterPlatform; },
又要跳到initPlatformTags方法,快給轉暈了,代碼如下:initPlatformTags: function () {Microloader.platformTags = Microloader.detectPlatformTags(Microloader.platformTags); },
還跳,這里省去n字,繼續去看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; },
好了,這次不用再跳了。代碼先調用navigator.userAgent返回了瀏覽器用于 HTTP 請求的用戶代理頭的值,這個值可用來檢查瀏覽器和版本號。如果值包含了字符串Mobile,說明是移動設備,這時候isMobile為true。在定義了一堆變量后,在頁面中添加了一個div元素。接下來的uaTagChecks根據變量名可以知道,這是要檢測的標記了。
接下來定義了isEventSupported函數,看名字就知道是用來檢測是否支持事件的。根據函數內容,可以看到檢測方式有兩種,第一種就是檢測事件名是否在剛才創建的元素div內,如果在,說明支持。第二種方法就是div元素上添加事件屬性,然后判斷元素對象內的事件屬性是否為function,如果是,說明支持,否則就是不支持了。
定義結束后,就開始使用循環來檢測平臺屬性了,檢測結果將保存在uaTags對象中,對象中的屬性名稱就是uaTagChecks中的字符串,值就是檢測值。
檢測完之后就要給幾個變量賦值了,賦值完成后,會調用apply方法將對象的成員復制到tags中。在調用apply方法時,還調用了loadPlatformsParam方法,該方法我就不列了,它的主要作用就是可通過訪問地址的platformTags參數來自定義平臺參數,這樣做的目的是可以通過瀏覽器做一些模擬效果,如桌面pc模擬平板的效果。
下一句判斷Ext.beforeLoad是否存在,在當前情況是不存在的,所以,這段代碼可以忽略。最后是將平臺檢測結果返回了。
返回initPlatformTags方法,可以知道Microloader.platformTags現在指向的平臺檢測結果。再返回init方法,在計算出平臺檢測結果后,會將Ext.filterPlatform屬性指向Microloader.filterPlatform方法,也就是說,在調用Ext的filterPlatform方法時,會執行Microloader.的filterPlatform方法,該方法的主要作用就是把不需要的平臺過濾掉。
好了,現在返回initManifest方法,在執行完init方法后,會給tmpManifest賦值,由于在當前情況下,manifest為null,所以tmpManifes的值將會是Ext.manifest的值,而從圖中可以知道,Ext.manifes的值是bootstrap,也就是說,現在tmpManifes的值是bootstrap。接下來判斷tmpManifes是否為字符串,當前情況下,tmpManifes是字符串,所以要執行判斷語句內的代碼。先給url賦值,這個由Boot.baseUrl、tmpManifest和“.json”三部分構成,先不管Boot.baseUrl,可以知道,這里要找的是bootstrap.json文件。接下來會調用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這語句就知道,這段代碼的主要作用就是使用Ajax去加載bootstrap.json文件了。現在假定能正確加載bootstrap.json文件并返回initManifest方法。
在initManifest方法內,接下來要做的是調用JSON.parse將返回的數據解析為JSON對象,并Ext.manifest屬性指向該對象。最后將JSON對象返回laod方法。
在load方法的第二句,會先從返回的對象中取出loadOrder的值。在bootstrap.json文件中,loadOrder是一個由對象組成的數組,而每一個對象包含path、requires、uses和idx這4個成員。如果對于Ext JS有一定理解,那么要理解這4個成員不難。成員paths的值就是Ext JS類的腳本的路徑,requires和uese指的是這個類所需要的類和使用到的類,而idx則是這個類的唯一標識。在requires和uese中就是使用這個唯一標識來指定所需或使用到的類文件的。
把這個loadOrder取出后,會調用Boot.createLoadOrderMap方法進行處理,代碼如下:
代碼的作用只是把loadOrder數組轉換為對象,對象的屬性名稱就是類文件的路徑,值就是類對象本身。
返回到load方法,在處理完loadOrder數組后,會繼續從bootstrap.json文件中把js和css的值取出來,然后合并到resources數組中。在當前項目中,bootstrap.json文件中的js和css的定義如下:
"js":[{"path":"app.js"}], "css":[{"path":"bootstrap.css"}這樣對于理解后面的循環就容易多了,由于在定義中,沒有platform這個成員,所以循環中的第一個判斷就會被跳過,直接執行第二個判斷了,也就是把路徑信息推人urls數組中。
處理完這個,就開始調用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; },在這段代碼中,前面的代碼都是與處理請求地址有關,而當這些都準備好了以后,就會調用Boot.loadUrl方法去加載文件了。而在Boot.loadUrl方法內,會調用Boot.create方法去創建加載標記,代碼如下:
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這句就可以看到,在這里會創建SCRIPT或LINK標記去加載腳本或樣式。
這么簡單的東西搞得那么復雜的一個原因是要確保類的加載順序,以確保不會出現類初始化時找不到依賴類的情況。因而,在整個加載過程中,需要監控每個腳本的加載情況,在依賴類沒有加載完成之前,不去加載該類。
在bootstrap.json文件中,已經把app.js、bootstrap.css等文件加進去了,所以,在index.html文件中,只需要加載bootstrap.js文件就行了。
至此,我們已經基本了解了Ext JS 5的啟動過程了。現在的問題是,我們怎么去加載本地化文件。
轉載于:https://www.cnblogs.com/hainange/p/6334168.html
總結
以上是生活随笔為你收集整理的Ext JS 5初探(二) ——Bootstrap.js的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 论文:进度管理
- 下一篇: 五个小例子教你搞懂 JavaScript