看了sea.js、requireJs那么完善的模块加载框架,今天尝试来自己写一下简单的加载功能,仅当作为自己学习练习,有很多考虑不周的地方请指出,主要就两个方法:
VM.define(‘模块名称’,‘模块路径’,‘模块依赖项[]’) 与 VM.use(‘模块名称’,‘回调函数callback’) ,一个是定义模块,一个是使用模块;使用的模块都必须先定义,
定义的时候不会加载模块,只有在使用的时候才加载模块;
1、处理循环依赖的问题,比如,模块A依赖模块B,模块B又依赖模块A;这种情况不会出现死循环的问题;
2、不会出现重复加载的模块,调用过的模块不会再append第二次,不能定义相同名字的模块;
3、依赖项可以是多个,从左到右加载;
4、支持链式调用
代码如下:
2
3 * Author : vvg
4
5 * version : 0.1
6
7 * name : myModule.js
8
9 **/
10
11 (function (window) {
12 // 调试提示
13 var log = function (content) {
14 if (typeof console.log === 'function') {
15 console.log(content);
16 } else {
17 alert(content);
18 }
19 }
20
21 var createScript = function (url) {
22 var script = document.createElement('script');
23 script.type = 'text/javascript';
24 script.src = url;
25 return script;
26 };
27
28 var head = document.getElementsByTagName('head')[0];
29
30 var vvgModule = {};
31
32 // 模块定义列表{name:[url,requireModule]},通过name来查找模块路径与依赖
33 vvgModule.defineQueue = {};
34
35 // 模块是否通过use注册过,避免多次use同一个模块的情况
36 vvgModule.isUse = {};
37
38 // 是否已经加载完毕,避免重复请求加载
39 vvgModule.isOnload = {};
40
41 // 回调队列
42 vvgModule.callBackQueue = {};
43
44 // 定义模块只是记录模块信息,并未产生加载,接受参数name-字符串,url-字符串,require-数组内字符串(依赖模块名)
45 vvgModule.define = function (name, url, require) {
46 if (typeof vvgModule.defineQueue[name] === 'undefined') {
47 // 加入定义队列
48 vvgModule.defineQueue[name] = [url, require];
49
50 } else {
51 log(name + '已经存在,请不要重复添加!');
52 }
53 return this;
54 };
55
56 // 模块加载
57 var _load = function (name, callback) {
58 var url, n, require;
59 // 如果此模块未被use加载过
60 if (!vvgModule.isUse[name]) {
61 vvgModule.isUse[name] = true;
62 n = vvgModule.defineQueue[name].length;
63 require = vvgModule.defineQueue[name][1];
64
65 // 回调队列,避免多次use同一个模块
66 if (!!callback) {
67 if (!vvgModule.callBackQueue[name]) vvgModule.callBackQueue[name] = [];
68 vvgModule.callBackQueue[name].push(callback);
69 }
70
71 // 判断是否有依赖项
72 if (typeof require !== 'undefined') {
73
CSS(Cascading Style Sheet) 层叠样式表:控制布局和显示效果。
1、行内样式
直接写在标签里面,使用style属性提供的样式
style属性的语法
style = "样式名字1:值1;样式2...;样式名字n:值n";
示例:
(1)层的样式
<div style = "
border-color:green;
border-weight:1px;
border-left-style:solid;
border-right-style:dashed;
border-top-style:dotted;
border-bottom-style:double;
width:150px;
height:50;
display:outline
">这是一个文本</div><br/>
(2)字体的样式
<div style = "
border:5px solid red;
background-color:pink;
font-family:微软雅黑;
font-size:28;
color:red;
">这是一个文本</div>
2、内嵌样式
直接写在head标签中使用的样式,直接作用所有标签里面的样式
语法:
<style type="text/css">
样式名1{
样式内容1;
样式内容2;
}
样式名2{
样式内容1;
样式内容2;
}
</style>
示例:
<head>
<title></title>
<style type="text/css">
ul{list-style-type:none}
li{
margin-right:10px;
float:left;
color:blue;
font-family:华文彩云;
font-size:20px;
}
</style>
</head>
<body style = "margin:0px padding:0px" >
<ul>
<li>主页1</li>
<li>>>网购1</li>
</ul>
<ul>
<li>主页2</li>
<li>>>网购2</li>
</ul>
</body>
3、外部样式
-> 可以将样式单独的写在一个style.css中
-> 使用link将其链接过来
<link type = "text/css" href = "./style.css" rel = "stylesheet"/>
示例:
<head>
<title></title>
<link type = "text/css" href = "./mystyle.css" rel = "stylesheet"/>
</head>
4、常见的样式
4.1、边框样式
边框方向:
->border-top
->border-top
->border-right
->border-bottom
边框属性:
-> 颜色border-color
-> 样式border-style
-> 粗细border-weight
语法格式:
<style type="text/css">
.test{
border:2px solid red;
}
</style>
细边框:
<style type="text/css">
.t{
border-collapse:collapse;
}
</style>
示例:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style type="text/css">
.test,tr,td{
border:2px solid red ;
border-collapse:collapse;
}
</style>
</head>
<body>
<table class ="test">
<tr>
<td>djflkdsaj</td>
<td>djflkdsaj</td>
</tr>
<tr>
<td>djflkdsaj</td>
<td>djflkdsaj</td>
</tr>
</table>
</body>
</html>
4.2、margin与padding
margin设置元素的外边距 padding设置元素的内边距
-> 如果是单值
margin:0px表示上下左右均为0
-> 如果是两个值
margin:10px 20px表示上下边距均为10px,而左右均为20px
-> 如果是三个值
margin:10px 20px 30px
表示上边距为10px
下边距为30px
左右均是20px
-> 如果是四个值
顺序为:top right bottom left
4.3、使用选择器
(1)标签选择器 作用于整个页面中的所有标签
标签名 { 样式名 : 值; }
(2)id选择器 规范id唯一性
#id名 { 样式名 : 值; }
使用处添加属性id="id名"
(3)类选择器
.类名 { 样式名 : 值; }
使用处添加属性
(4)伪选择器:设定标签样式的时候,根据状态设置不同的样式
<style>
a:link{
color:blue;
font-size:16px
}
a:hover{
color:yellow;
font-size:24px
}
a:active{
color:red;
font-size:36px
}
a:visited{
color:#9f365f;
}
tr:hover{
background-color:yellow;
}
</style>
<body>
<a href="#"><u>百度一下</u></a>
<a ><u>百度一下</u></a>
</body>
5、 Position 及脱离文档流
文档流就是堆砌如果需要控制其位置,需要考虑position属性设置其定位方式
(1)默认值 static
-> 按顺序的文档流堆砌
(2)相对定位 relative
-> 原来所在文档流中的位置一直占据
-> 设定left等参数的时候,相当于在原有文档流的位置基础之上左边偏移量
会由于偏移遮盖文本,但元素的位置与在文档流原本的位置是相对固定的
(*3)绝对定位 absolute
->该元素就脱离了文档流,可以设置其在浏览器窗体中的绝对位置;
->位置随滚动条滚动而改变(在浏览器窗体的位置固定了) ;
->当浏览器窗体不断缩小,最后导致元素位置会重叠,位置互换等情形的发生。
(*4)可视区固定 fixed
->该元素就脱离了文档流,可以设置其在浏览器可视区的绝对位置;
->位置不随滚动条滚动而改变;
->当浏览器窗体不断缩小,最后导致元素位置会重叠,位置互换等情形的发生。当可视区过小,元素可能"消失"。
以上几种定位的示例:
<head>
<style>
.d1{
border:2px solid black;
background-color:silver;
width:200px;
height:150px;
position:
bottom:30px;
right:30px;
}
.d21{
border:2px solid black ;
background-color:green;
width:100px;
height:50px;
position:relative;
top:20px;
left:20px;
}
.d22{
border:2px solid black ;
background-color:green;
width:100px;
height:50px;
position:relative;
top:20px;
left:20px;
}
.d31{
border:1px solid black ;
background-color:blue;
width:100px;
height:50px;
position:absolute;
top:5px;
left:5px;
z-index:50;
}
.d32{
border:1px solid black ;
background-color:green;
width:100px;
height:50px;
position:absolute;
top:5px;
right:5px;
z-index:100;
}
.d41{
border:1px solid black ;
background-color:red;
width:100px;
height:50px;
position:fixed;--不受滚动条影响,相对于浏览器
创建运行在手机上的web app时,鉴于手机用户的网络情况,我们需要考虑到用户离线使用的情况。
html5支持构建离线应用程序。使用它的本地缓存机制可以将应用所需的资源文件都缓存到本地,从而实现应用的离线使用。首先要说明的是,本地缓存和传动的浏览器网页缓存是不同的,网页缓存基于网页,也就是缓存一个网页的内容,而不是整个app。同时网页缓存并不可靠,我们不知道我们的app中哪个页面已经缓存,该页面的哪些资源已经缓存,而本地缓存对于缓存内容是完全可控的。
使用离线缓存,除了可以使应用可以离线使用外,还能帮助有效的加快网页加载速度(本地的自然更快),同时降低服务器负载(只需要下载更新的内容)。
正如之前所提到的,本地缓存可以指定要缓存的内容,这同过配置manifest来实现。可以为整个app配置manifest,也可以为单独某个页面来配置。
简单的manifest格式如下:
index.html
stylesheet.css
images/logo.png
scripts/main.js
文件的第一行必须是CACHE MANIFEST。
该manifest声明了需要缓存的html页面,css,图片以及js文件。
再看一个比较复杂的manifest文件:
# 指定一个版本号
# version 1
# 该类别指定要缓存的资源文件
CACHE:
/favicon.ico
index.html
stylesheet.css
images/logo.png
scripts/main.js
# 指定不进行缓存的资源文件
NETWORK:
login.php
http://foocoder.com
# 每行指定两个文件,第一个为在线时使用的资源,第二个是离线时使用的资源
FALLBACK:
/main.py /static.html
images/large/ images/offline.jpg
*.html /offline.html
其中#号开头的为注释。因为只有在manifest文件发生改变时才会更新,所以我们可以加个版本号方便控制。
从该文件中可以看到分为了三个类别:
CACHE类别指定需要被缓存的资源文件。
NETWORK类别指定不缓存的资源文件,即只在联网的情况下才能访问。
FALLBACK每一行都会指定两个文件,第一个为在线时使用的资源,第二个为离线时使用的备用资源。其中*为通配符,表示在线时使用所有的.html文件。
配置好manifest文件之后,我们只需要在页面上引用即可。如下,在html 标签的manifest属性下指定manifest文件的地址:
...
</html>
该地址可以是绝对地址也可以是相对地址,但是该文件的吗MIME 类型必须是text/cache-manifest,所以需要在服务器做相应配置对该类型添加支持,例如吗,对于apache服务器,需要在配置mime.types中添加如下内容:
AddType text/cache-manifest .manifest到这里为止,就完成了离线缓存的基本内容,在manifest文件发生变化时,浏览器会检查manifest文件并更新缓存。
我们不得不考虑一个问题,浏览器如何处理本地缓存?当服务端更新了应用程序后,用户打开时是不是会使用最新的资源了?答案是否定的。这需要了解下在使用离线缓存的情况下,浏览器与服务端的整个交互过程。
1.首次访问
在首次访问时,没有什么特别,浏览器解析index.html,请求所有的资源文件。随后就会处理manifest文件,请求所有的manifest中的资源文件,注意,即使之前已经请求过了所有的资源文件,这里必须进行重复请求。最后将这些文件缓存到本地。
2.再次访问
再次访问时,浏览器发现有本地缓存,所以会加载本地缓存内容。随后会向服务端请求manifest文件,如果manifest文件未更新,返回304代码,浏览器不做处理。如果manifest已经更新过,则请求所有manifest中的资源文件,重新对其缓存。
所以,即使服务端更新了manifest和其他资源,用户打开时扔是之前的页面。需要重新打开才能使用更新过后的资源。
有办法立刻更新缓存么?是可以的。我们可以使用applicationCache对象做到这一点。但是也只是能做到立刻更新缓存,还是需要用户重新打开也没才会生效。接下来就看看如何用applicationCache对象立刻更新缓存。
window.applicationCache下有个status属性。可以通过其知道当前的缓存状态
switch (appCache.status) {
case appCache.UNCACHED: // UNCACHED == 0
return 'UNCACHED';
break;
case appCache.IDLE: // IDLE == 1
return 'IDLE';
break;
case appCache.CHECKING: // CHECKING == 2
return 'CHECKING';
break;
case appCache.DOWNLOADING: // DOWNLOADING == 3
return 'DOWNLOADING';
break;
case appCache.UPDATEREADY: // UPDATEREADY == 4
return 'UPDATEREADY';
break;
case appCache.OBSOLETE: // OBSOLETE == 5
return 'OBSOLETE';
break;
default:
return 'UKNOWN CACHE STATUS';
break;
};
既然可以获得状态,我们只需要请求更新,随后在状态为appCache.UPDATEREADY时更新缓存时即可。
applicationCache.update()方法会尝试更新用户缓存,而applicationCache.swapCache()方法会对本地缓存进行更新:
appCache.update(); // 开始更新
if (appCache.status == window.applicationCache.UPDATEREADY) {
appCache.swapCache(); // 更新缓存
}
正如之前所说的,即使更新了缓存,还是需要重新加载才能使用最新的资源,此时可以提示用户更新。只需要监听onUpdateReady事件,该事件在缓存被下载到本地后出发,从而可以在此时提示用户:
window.applicationCache.addEventListener('updateready', function(e) {
if (window.applicationCache.status == window.applicationCache.UPDATEREADY) {
//更新本地缓存
window.applicationCache.swapCache();
if (confirm('已经有新的版本,是否立刻切换到最新版?'