在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 screen
isEventSupported('touchend') ||
// browsers that use pointer event have maxTouchPoints > 0 if the
// device supports touch input
// http://www.w3.org/TR/pointerevents/#widl-Navigator-maxTouchPoints
navigator.maxTouchPoints ||
// IE10 uses a vendor-prefixed maxTouchPoints property
navigator.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 leak return {
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方法进行处理,代码如下:

createLoadOrderMap: function(loadOrder) {
var len = loadOrder.length,
loadOrderMap = {},
i, element; for(i = 0; i < len; i++) {
element = loadOrder[i];
loadOrderMap[element.path] = element;
} return loadOrderMap;
},

代码的作用只是把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的启动过程了。现在的问题是,我们怎么去加载本地化文件。

Ext JS 5初探(二) ——Bootstrap.js的更多相关文章

  1. bootstrap.js 文件使用指南

    介绍 使用 Bootstrap v3.3.7 时,需要引入三个脚本文件. https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.m ...

  2. 关于 ajax 动态返回数据 css 以及 js 失效问题(动态引入JS)

    ajax 毕竟是异步的 所以动态加载出来的数据 难免遇到 css 或者 js 失效的问题,所以要动态加载 css ji等文件了 1.公共方法 load //动态加载 js /css function ...

  3. 初探JavaScript(二)——JS如何动态操控HTML

    除去五一三天,我已经和<JavaScript Dom编程艺术>磨合了六天,第一印象很好.慢慢的,我发现这是一块排骨,除了肉还有骨头.遇到不解的地方就会多看几遍,实在不懂的先跳过,毕竟,初次 ...

  4. Ext JS 5初探(三)

    在上文提到了本地化文件的问题,然后在Ext JS 5的包里找了找,居然还没包含本地化包.我估计目前还不到考虑本地化的时候.在Sencha Touch中,是没有本地化包的,但是要让Ext JS也不包含本 ...

  5. Ext JS 5初探(一)

    在开始前,先安装好Sencha Cmd 5.然后输入以下命令创建一个测试用的应用程序: sencha -sdk c:\ext5 generate app TestExt5 C:\TestExt5 想不 ...

  6. JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有)

    前言:最近园子里多了许多谈语言.谈环境.谈逼格(格局)的文章,看看笑笑过后,殊不知其实都是然并卵.提升自己的技术才是王道.之前博主分享过多篇bootstrap组件的文章,引起了很多园友的关注和支持,看 ...

  7. JS组件系列——基于Bootstrap Ace模板的菜单Tab页效果优化

    前言:之前发表过一篇  JS组件系列——基于Bootstrap Ace模板的菜单和Tab页效果分享(你值得拥有) ,收到很多园友的反馈,当然也包括很多诟病,因为上篇只是将功能实现了,很多细节都没有处理 ...

  8. 转战JS(1) 初探与变量类型、运算符、常用函数与转换

    转战JS(1)初探与变量类型.运算符.常用函数与转换 做为一名.NET后台开发人员,正考滤向Web前端开发转型,之前也写过一代前端代码,可是当再回头看JS,并有转向它的意愿的时候,突然发现:原来JS不 ...

  9. ExtJS 4.2 教程-02:bootstrap.js 工作方式

    转载自起飞网,原文地址:http://www.qeefee.com/extjs-course-2-bootstrap-js ExtJS 4.2 教程-01:Hello ExtJS ExtJS 4.2 ...

随机推荐

  1. Java中的Lock锁

    Lock锁介绍: 在java中可以使用 synchronized 来实现多线程下对象的同步访问,为了获得更加灵活使用场景.高效的性能,java还提供了Lock接口及其实现类ReentrantLock和 ...

  2. 安卓高级 WebView的使用到 js交互

    我们先来学习 怎么使用再到用js和安卓源生方法交互 WebView简单使用 此部分转载并做了补充 原博客 原因:比较简单不是很想在写,我只要写js交互部分 WebView可以使得网页轻松的内嵌到app ...

  3. Java程序员的Golang入门指南(下)

    Java程序员的Golang入门指南(下) 4.高级特性 上面介绍的只是Golang的基本语法和特性,尽管像控制语句的条件不用圆括号.函数多返回值.switch-case默认break.函数闭包.集合 ...

  4. Linux文件编辑命令详细整理

    刚接触Linux,前几天申请了个免费体验的阿里云服务器,选择的是Ubuntu系统,配置jdk环境变量的时候需要编辑文件. vi命令编辑文件,百度了一下,很多回答不是很全面,因此编辑文件话了一些时间. ...

  5. 带有进度条的WebView

    带有进度条的WebView 本篇继于WebView的使用 效果图 自定义一个带有进度条的WebView package com.kongqw.kbox.view; import android.con ...

  6. cassandra 概述

    摘要 本篇文章主要是介绍cassandra与其他NoSQL的区别以及自身的特点与应用场景.在关系数据库我们没必要选择数据库,通常需要适配oracle/mysql/sql server/db2 等多种数 ...

  7. HOG OpenCV 代码片段

    直接上代码: #include <opencv2/opencv.hpp> using namespace cv; #include <cmath> using namespac ...

  8. Xcode7.3.1中SKAudioNode在Scene转换后无声的问题

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 在新的Xcode中之前可以正常运行的SKAudioNode代码 ...

  9. GDAL库三个读取Jpeg2000格式驱动测试

    0.目的 GDAL库中提供了四五种读取Jpeg2000的驱动,但是各个驱动读取数据的效率各不相同,下面就针对三种读取jpeg2000的效率进行测试. GDAL库中提供的读取Jpeg2000的驱动有下面 ...

  10. Android7.0 多窗口你值得拥有

    Android7.0 多窗口你值得拥有 什么是多窗口分屏? 多窗口分屏其实在国内并不陌生,已经有一些手机和平板搭载了"分屏多任务"和"APP窗口化"功能,但这些 ...