");
40 | }
41 | content += "提交 ";
42 | ulForm.innerHTML = content;
43 | var inputs = ulForm.getElementsByTagName("input");
44 | for (var n = 0, nlen = inputs.length; n < nlen; n++) {
45 | switch(inputs[n].id) {
46 | case "inputName"://名称
47 | inputName.addEventListener("focus",onFocus);
48 | inputName.addEventListener("blur",onBlur);
49 | break;
50 | case "inputPwd1"://密码
51 | inputPwd1.addEventListener("focus",onFocus);
52 | inputPwd1.addEventListener("blur",onBlur);
53 | break;
54 | case "inputPwd2"://确认密码
55 | inputPwd2.addEventListener("focus",onFocus);
56 | inputPwd2.addEventListener("blur",onBlur);
57 | break;
58 | case "mail"://邮箱
59 | mail.addEventListener("focus",onFocus);
60 | mail.addEventListener("blur",onBlur);
61 | break;
62 | case "tel"://手机
63 | tel.addEventListener("focus",onFocus);
64 | tel.addEventListener("blur",onBlur);
65 | break;
66 | default: break;
67 |
68 | }
69 | }
70 | btn.addEventListener("click",function() {
71 | var spans = ulForm.getElementsByTagName("span");
72 | var str = "格式正确密码可用";
73 | for (var k = 0, klen = spans.length; k < klen; k++) {
74 | if (spans[k].innerHTML == "") {
75 | alert("提交失败");
76 | return;
77 | }
78 | else if (str.indexOf(spans[k].innerHTML) == -1) {
79 | alert("提交失败");
80 | return;
81 | }
82 | }
83 | alert("提交成功");
84 | });
85 | }
86 |
87 | //检测名称 取得label中的值
88 | function onFocus(event) {
89 | var label = event.target.parentNode.children[0]; //名称
90 | var span = event.target.parentNode.children[3]; //SPAN的提示信息
91 | switch(label.innerHTML) {
92 | case "名称": span.innerHTML = "长度必须为4~16个字符";
93 | break;
94 | case "密码": span.innerHTML = "长度必须为4~16个字符";
95 | break;
96 | case "确认密码": span.innerHTML = "两次密码必须一致";
97 | break;
98 | case "邮箱": span.innerHTML = "邮箱格式为带@的字符集合";
99 | break;
100 | case "手机": span.innerHTML = "长度必须为11个数字";
101 | break;
102 | default: break;
103 | }
104 | }
105 |
106 | function onBlur(event) {
107 | var label = event.target.parentNode.children[0]; //名称
108 | var span = event.target.parentNode.children[3]; //SPAN的提示信息
109 | var str = event.target.value.trim();
110 | if (!str) {
111 | span.innerHTML = label.innerHTML + "不能为空";
112 | event.target.style.border = "2px solid red";
113 | span.style.color = "red";
114 | }
115 | var len;
116 | var tempArry = str.match(re);
117 | str = str.replace(re, "");
118 | if (tempArry) { //检测是否有中文
119 | len = tempArry.length*2 + str.length;
120 | }
121 | else {
122 | len = str.length;
123 | }
124 | //验证格式
125 | switch(label.innerHTML) {
126 | case "名称": formatName(event.target,span,len);
127 | break;
128 | case "密码": formatName(event.target,span,len);
129 | break;
130 | case "确认密码": formatPwd(event.target,span,len);
131 | break;
132 | case "邮箱": formatMail(event.target,span,str);
133 | break;
134 | case "手机": formatTel(event.target,span,str);
135 | break;
136 | default: break;
137 | }
138 | }
139 | //验证名字格式
140 | function formatName(obj,span,len) {
141 | if (len < 4 || len > 16 ) {
142 | span.innerHTML = "长度必须为4~16个字符";
143 | obj.style.border = "2px solid red";
144 | span.style.color = "red";
145 | }
146 | else {
147 | span.innerHTML = "格式正确";
148 | obj.style.border = "2px solid lightgreen";
149 | span.style.color = "lightgreen";
150 | }
151 | }
152 | //验证密码格式
153 | function formatPwd(obj,span,len) {
154 | if ((inputPwd1.value.trim() == inputPwd2.value.trim()) && len < 17 && len >3) {
155 | span.innerHTML = "密码可用";
156 | obj.style.border = "2px solid lightgreen";
157 | span.style.color = "lightgreen";
158 | }
159 | else {
160 | span.innerHTML = "两次密码必须一致";
161 | obj.style.border = "2px solid red";
162 | span.style.color = "red";
163 | }
164 | }
165 | //验证邮箱格式
166 | function formatMail(obj,span,str) {
167 | var re = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
168 | if (re.test(str)) {
169 | span.innerHTML = "格式正确";
170 | obj.style.border = "2px solid lightgreen";
171 | span.style.color = "lightgreen";
172 | }
173 | else {
174 | span.innerHTML = "邮箱格式不正确";
175 | obj.style.border = "2px solid red";
176 | span.style.color = "red";
177 | }
178 | }
179 | //验证手机格式
180 | function formatTel(obj,span,str) {
181 | var re = /^\d{11}$/;
182 | if (re.test(str)) {
183 | span.innerHTML = "格式正确";
184 | obj.style.border = "2px solid lightgreen";
185 | span.style.color = "lightgreen";
186 | }
187 | else {
188 | span.innerHTML = "手机格式不正确";
189 | obj.style.border = "2px solid red";
190 | span.style.color = "red";
191 | }
192 | }
193 | creatBtn.addEventListener("click",creatForm);
194 |
195 | //提交的时候验证所有格式
196 |
197 |
198 |
--------------------------------------------------------------------------------
/part2/task33/README.md:
--------------------------------------------------------------------------------
1 | 33任务目的
2 |
3 | 练习JavaScript在DOM、字符串处理相关知识
4 | 练习对于复杂UI,如何进行数据机构建模
5 | 任务描述
6 | 实现一个类似棋盘的格子空间,每个格子用两个数字可以定位,一个红正方形的DOM在这个空间内,正方形中的蓝色边表示这是他的正面,有一个input输入框
7 | 在输入框中允许输入如下指令,按下按钮后,使得正方形做相应动作
8 | GO:向蓝色边所面向的方向前进一格(一格等同于正方形的边长)
9 | TUN LEF:向左转(逆时针旋转90度)
10 | TUN RIG:向右转(顺时针旋转90度)
11 | TUN BAC:向右转(旋转180度)
12 | 移动不能超出格子空间
13 | 任务注意事项
14 |
15 | 实现功能的同时,请仔细学习JavaScript相关的知识
16 | 请注意代码风格的整齐、优雅
17 | 代码中含有必要的注释
18 | 建议不使用任何第三方库、框架
--------------------------------------------------------------------------------
/part2/task33/task33.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 听指令的小方块(一)
6 |
28 |
29 |
30 |
31 |
32 |
33 | 1
34 | 2
35 | 3
36 | 4
37 | 5
38 | 6
39 | 7
40 | 8
41 | 9
42 | 10
43 |
44 |
45 | 1
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 | 2
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | 3
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 | 4
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | 5
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | 6
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | 7
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | 8
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | 9
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | 10
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 | 执行
176 | R向右转 B向反方向转 L向左转 GO为前进 不区分大小写
177 |
178 |
179 |
--------------------------------------------------------------------------------
/part2/task33/task33.js:
--------------------------------------------------------------------------------
1 | var $ = function(id) {
2 | return document.getElementById(id);
3 | };
4 | var table= $("table").children[0],
5 | input = $("input"),
6 | button = $("button"),
7 | className = "smallBox",
8 | block = {
9 | x: 5,
10 | y: 5,
11 | index: 3,// 0上 1右 2下 3左 代表四个方向
12 | now: getBlock(5,5)
13 | };
14 | //初始化设置小方块
15 | setDiv(block.now);
16 | divDirection(block.now, className);
17 | block.now.style.transform = "rotateZ(0deg)";
18 | //获取小方块位置
19 | function getBlock(x, y) {
20 | return table.children[y].children[x];
21 | }
22 | //小方块里面蓝色方块
23 | function setDiv(block) {
24 | block.innerHTML = "
";
25 | }
26 | function divDirection(block, className) {
27 | block.className = className;
28 | }
29 | //点击旋转时 改变角度
30 | function setDirection(degree) {
31 | var preDegree = parseInt((block.now.style.transform).match(/[-]*\d+/g));
32 | block.now.style.transform = "rotateZ(" + (degree + preDegree) + "deg)";
33 | }
34 | button.onclick = function () {
35 | switch(input.value.toUpperCase()) {
36 | case "GO": go();
37 | break;
38 | case "R": setDirection(90);
39 | block.index = (block.index + 1) % 4;
40 | break;
41 | case "B": setDirection(180);
42 | block.index = (block.index + 2) % 4;
43 | break;
44 | case "L": setDirection(-90);
45 | block.index = ((block.index - 1) >= 0? (block.index-1):3) % 4;
46 | break;
47 | default: break;
48 | }
49 | }
50 | //当小广场向前移动时 取得下一个位置的小方块 并把原来的小方块隐藏掉 然后把下一个小方块重新赋值给block
51 | function repeatSet(blockNext) {
52 | setDiv(blockNext);
53 | divDirection(blockNext, className);
54 | divDirection(block.now, "");
55 | blockNext.style.transform = block.now.style.transform;
56 | block.now = blockNext;
57 | }
58 | //移动函数
59 | function go() {
60 | switch(block.index) {
61 | case 0: if (block.y > 1) {
62 | block.y--;
63 | blockNext = getBlock(block.x, block.y);
64 | repeatSet(blockNext);
65 | }
66 | break;
67 | case 1: if (block.x < 10) {
68 | block.x++;
69 | blockNext = getBlock(block.x, block.y);
70 | repeatSet(blockNext);
71 | }
72 | break;
73 | case 2: if (block.y < 10) {
74 | block.y++;
75 | blockNext = getBlock(block.x, block.y);
76 | repeatSet(blockNext);
77 | }
78 | break;
79 | case 3: if (block.x > 1) {
80 | block.x--;
81 | blockNext = getBlock(block.x, block.y);
82 | repeatSet(blockNext);
83 | }
84 | break;
85 | default: break;
86 | }
87 | }
--------------------------------------------------------------------------------
/part2/task34/README.md:
--------------------------------------------------------------------------------
1 | 34任务目的
2 |
3 | 练习JavaScript在DOM、字符串处理相关知识
4 | 练习对于复杂UI,如何进行数据机构建模
5 | 任务描述
6 |
7 | 对于正方形的移动增加相应动画,包括移动和旋转
8 | 每个指令的执行时间是1s(可以自己调整)
9 | 增加新的指令如下:
10 | TRA LEF:向屏幕的左侧移动一格,方向不变
11 | TRA TOP:向屏幕的上面移动一格,方向不变
12 | TRA RIG:向屏幕的右侧移动一格,方向不变
13 | TRA BOT:向屏幕的下面移动一格,方向不变
14 | MOV LEF:方向转向屏幕左侧,并向屏幕的左侧移动一格
15 | MOV TOP:方向转向屏幕上面,向屏幕的上面移动一格
16 | MOV RIG:方向转向屏幕右侧,向屏幕的右侧移动一格
17 | MOV BOT:方向转向屏幕下面,向屏幕的下面移动一格
18 | 任务注意事项
19 |
20 | 实现功能的同时,请仔细学习JavaScript相关的知识
21 | 请注意代码风格的整齐、优雅
22 | 代码中含有必要的注释
23 | 建议不使用任何第三方库、框架
--------------------------------------------------------------------------------
/part2/task34/task34.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 听指令的小方块(二)
6 |
32 |
33 |
34 |
37 |
38 |
39 |
40 | 1
41 | 2
42 | 3
43 | 4
44 | 5
45 | 6
46 | 7
47 | 8
48 | 9
49 | 10
50 |
51 |
52 | 1
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | 2
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 | 3
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | 4
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 | 5
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 | 6
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 | 7
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 | 8
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | 9
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 | 10
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | 执行
183 | 0向上进一格 1向右进一格 2向下进一格 3向左进一格
184 | TT方向转向上并进一格 RT方向转向右并进一格 BT方向转向下并进一格 LT方向转向左并进一格
185 |
186 |
187 |
--------------------------------------------------------------------------------
/part2/task34/task34.js:
--------------------------------------------------------------------------------
1 | //看了其他团队的代码 学习到了另一种方法 任务34和任务33分别用了不同的方法 感觉任务34这种比较简单直观并且实现了动画效果
2 | var $ = function(id) {
3 | return document.getElementById(id);
4 | };
5 | var input = $("input"),
6 | smallBox = $("smallBox"),
7 | index = "3", //数字标志方向 0上 1右 2下 3左
8 | button = $("button");
9 | //初始化设置小方块
10 | smallBox.style.transform = "rotateZ(0deg)";
11 | smallBox.style.top = "208px";
12 | smallBox.style.left = "208px";
13 | //点击旋转时 改变角度
14 | function setDirection(degree) {
15 | smallBox.style.transform = "rotateZ(" + degree + "deg)";
16 | }
17 | button.onclick = function () {
18 | switch(input.value.toUpperCase()) {
19 | case "TT": setDirection(90);
20 | index = "0";
21 | go(index);
22 | break;
23 | case "RT": setDirection(180);
24 | index = "1";
25 | go(index);
26 | break;
27 | case "BT": setDirection(270);
28 | index = "2";
29 | go(index);
30 | break;
31 | case "LT": setDirection(0);
32 | index = "3";
33 | go(index);
34 | break;
35 | default: if (/[0123]/.test(input.value)) {
36 | go(input.value);
37 | }
38 | }
39 | }
40 | //移动函数
41 | function go(index) {
42 | switch(index) {
43 | case "0": if (smallBox.style.top == "48px")
44 | break;
45 | smallBox.style.top = (parseInt(smallBox.style.top) - 40) + "px";
46 | break;
47 | case "1": if (smallBox.style.left == "408px")
48 | break;
49 | smallBox.style.left = (parseInt(smallBox.style.left) + 40) + "px";
50 | break;
51 |
52 | case "2": if (smallBox.style.top == "408px")
53 | break;
54 | smallBox.style.top = (parseInt(smallBox.style.top) + 40) + "px";
55 | break;
56 | case "3": if (smallBox.style.left == "48px")
57 | break;
58 | smallBox.style.left = (parseInt(smallBox.style.left) - 40) + "px";
59 | break;
60 | default: break;
61 | }
62 | }
--------------------------------------------------------------------------------
/part2/task35/README.md:
--------------------------------------------------------------------------------
1 | 35任务目的
2 |
3 | 练习JavaScript在DOM、字符串处理相关知识
4 | 练习对于复杂UI,如何进行数据机构建模
5 | 任务描述
6 |
7 | 命令输入框由input变为textarea,可以允许输入多条指令,每一行一条
8 | textarea左侧有一列可以显示当前行数的列(代码行数列),列数保持和textarea中一致
9 | 当textarea发生上下滚动时,代码行数列同步滚动
10 | 能够判断指令是否合法,不合法的指令给出提示(如图)
11 | 点击执行时,依次逐条执行所有命令
12 | 对于GO,TRA以及MOV指令增加可以移动格子数量的参数,例如
13 | GO 3:向当前方向前进三格
14 | TRA TOP 2:向屏幕上方平移两格
15 | MOV RIG 4:方向转向屏幕右侧,向屏幕的右侧移动四格
16 | 任务注意事项
17 |
18 | 实现功能的同时,请仔细学习JavaScript相关的知识
19 | 请注意代码风格的整齐、优雅
20 | 代码中含有必要的注释
21 | 建议不使用任何第三方库、框架
--------------------------------------------------------------------------------
/part2/task35/task35.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 听指令的小方块(三)
6 |
56 |
57 |
58 |
61 |
62 |
63 |
64 | 1
65 | 2
66 | 3
67 | 4
68 | 5
69 | 6
70 | 7
71 | 8
72 | 9
73 | 10
74 |
75 |
76 | 1
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | 2
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | 3
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | 4
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 | 5
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | 6
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | 7
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 | 8
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 | 9
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | 10
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 | 执行
207 | 清空命令
208 |
209 |
210 |
211 |
212 |
213 | 0向上进一格 1向右进一格 2向下进一格 3向左进一格
214 | TT方向转向上并进一格 RT方向转向右并进一格 BT方向转向下并进一格 LT方向转向左并进一格
215 | 注: 每输完一条命令必须按回车另起一行输入命令 否则会报错 输完所有命令点击“执行”开始执行 指令+空格+数字代表执行次数
216 |
217 |
218 |
--------------------------------------------------------------------------------
/part2/task35/task35.js:
--------------------------------------------------------------------------------
1 | // 看了其他团队的代码 学习到了另一种方法 任务34和任务33分别用了不同的方法 感觉任务34这种比较简单直观并且实现了动画效果
2 | // 先看前面16行代码 再从button点击事件开始看
3 | var $ = function(id) {
4 | return document.getElementById(id);
5 | };
6 | var input = $("input"), // 命令输入框
7 | smallBox = $("smallBox"), // 小方块
8 | index = "3", // 数字标志方向 0上 1右 2下 3左
9 | refresh = $("refresh"), // 命令清空按钮
10 | timer = null, // 计时器
11 | button = $("button"), // 执行命令按钮
12 | disRow = $("disRow");
13 | // 初始化设置小方块
14 | smallBox.style.transform = "rotateZ(0deg)";
15 | smallBox.style.top = "208px";
16 | smallBox.style.left = "208px";
17 | // 点击旋转时 改变角度
18 | function setDirection(degree) {
19 | smallBox.style.transform = "rotateZ(" + degree + "deg)";
20 | }
21 | button.onclick = function () {
22 | if (timer) { // 清除计数器
23 | clearInterval(timer);
24 | }
25 | var inputArry = input.value.trim().toUpperCase().split("\n"),
26 | i = 0,
27 | len = inputArry.length,
28 | divs = disRow.getElementsByTagName("div");
29 | timer = setInterval(function(){
30 | if (i < len) {
31 | var tempArry = inputArry[i].split(" ");
32 | console.log(tempArry[1]);
33 | if (tempArry[1]) {
34 | checkCommand(tempArry[0], i, tempArry[1], divs);
35 | i++;
36 | }
37 | else {
38 | checkCommand(tempArry[0], i, 1, divs);
39 | i++;
40 | }
41 | }
42 | },500);
43 | };
44 | // 检查指令后面是否有执行次数 四个参数依次为命令 命令所在数组的索引 执行次数 左边标注行数的DIV
45 | function checkCommand(value, i, num, divs) {
46 | while (num) {
47 | switch(value) {
48 | case "TT": setDirection(90);
49 | index = "0"; // 为了在向前移动的时候判断当前朝向
50 | go(index);
51 | break;
52 | case "RT": setDirection(180);
53 | index = "1";
54 | go(index);
55 | break;
56 | case "BT": setDirection(270);
57 | index = "2";
58 | go(index);
59 | break;
60 | case "LT": setDirection(0);
61 | index = "3";
62 | go(index);
63 | break;
64 | default: if (/[0123]/.test(value)) {
65 | go(value);
66 | }
67 | else {
68 | divs[i].style.background = "red";
69 | }
70 | break;
71 | }
72 | num--;
73 | }
74 | }
75 | // 移动函数
76 | function go(index) {
77 | switch(index) {
78 | case "0": if (smallBox.style.top == "48px")
79 | break;
80 | smallBox.style.top = (parseInt(smallBox.style.top) - 40) + "px";
81 | break;
82 | case "1": if (smallBox.style.left == "408px")
83 | break;
84 | smallBox.style.left = (parseInt(smallBox.style.left) + 40) + "px";
85 | break;
86 |
87 | case "2": if (smallBox.style.top == "408px")
88 | break;
89 | smallBox.style.top = (parseInt(smallBox.style.top) + 40) + "px";
90 | break;
91 | case "3": if (smallBox.style.left == "48px")
92 | break;
93 | smallBox.style.left = (parseInt(smallBox.style.left) - 40) + "px";
94 | break;
95 | default: break;
96 | }
97 | }
98 | // 清空命令
99 | refresh.onclick = function() {
100 | input.value = null;
101 | disRow.innerHTML = "";
102 | };
103 | // 监听文本域键盘事件
104 | input.addEventListener("keyup", function() {
105 | rowHasChange();
106 | });
107 | function rowHasChange() {
108 | var rows = input.value.trim().toUpperCase().split("\n"),
109 | arr = [],
110 | top = input.scrollTop;
111 | for (var i = 0; i < rows.length; i++) {
112 | arr.push("
" + (i + 1) + "
");
113 | }
114 | disRow.innerHTML = arr.join("");
115 | disRow.scrollTop = top;
116 | }
--------------------------------------------------------------------------------
/part3/task37/README.md:
--------------------------------------------------------------------------------
1 | 37任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 练习对于代码的抽象与封装
5 | 为第四阶段的RIA任务做准备
6 | 任务描述
7 |
8 | 实现一个浮出层的UI组件实现
9 |
10 | 浮出层的中心默认在屏幕正中
11 | 当浮出层显示时,屏幕滚动时,浮出层始终保持位置固定在屏幕正中,不随屏幕滚动而变化位置。或者禁止页面在有浮出层出现时滚动
12 | 当浮出层显示时,点击浮出层以外的部分,默认为关闭浮出层。可以实现一个半透明的遮罩来挡住浮出层外的部分
13 | 浮出层的样式、内容和逻辑尽量解耦
14 | 提供使用JavaScript控制浮出层展现和关闭的接口
15 | 浮出层的窗口大小可以是一个默认固定值,也可以是随内容变化而自适应变化,也可以是通过接口参数进行调整,自行根据自己能力进行选择
16 | 有能力的同学可以实现浮出层的拖拽移动浮出窗口位置以及拖拽边缘来放大缩小浮出窗口的功能
17 | 任务注意事项
18 |
19 | 请注意代码风格的整齐、优雅
20 | 代码中含有必要的注释
21 | 可以合理选择使用其它第三方类库,但不建议
--------------------------------------------------------------------------------
/part3/task37/task37.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UI组件之浮出层
6 |
57 |
58 |
59 | 登陆
60 |
61 |
62 |
这是一个浮出层
63 | 这是一个浮出层
64 | 确定
65 | 取消
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/part3/task37/task37.js:
--------------------------------------------------------------------------------
1 | // 兼容的事件方法
2 | function addEvent(ele, event, hanlder) {
3 | if (ele.addEventListener) {
4 | ele.addEventListener(event, hanlder, false);
5 | } else if (ele.attachEvent) {
6 | ele.attachEvent('on' + event, hanlder);
7 | } else {
8 | ele['on' + event] = hanlder;
9 | }
10 | }
11 | function removeEvent(ele, event, hanlder) {
12 | if (ele.removeEventListener) {
13 | ele.removeEventListener(event, hanlder, false);
14 | } else if (ele.detachEvent) {
15 | ele.detachEvent('on' + event, hanlder);
16 | } else {
17 | ele['on' + event] = null;
18 | }
19 | }
20 |
21 | function $(id) {
22 | return document.getElementById(id);
23 | }
24 |
25 | // 创建一个对象 参数是遮罩层和浮出层的节点
26 | function MaskLayer(maskNode, floNode) {
27 | this.mask = maskNode;
28 | this.flo = floNode;
29 | }
30 | // 原型方法
31 | MaskLayer.prototype = {
32 | init: function() {
33 | this.mask.style.width = window.screen.width + "px";
34 | this.mask.style.height = window.screen.height + "px";
35 | this.drag(this.flo);
36 | this.show();
37 | },
38 | show: function() {
39 | this.mask.style.display = "block";
40 | },
41 | hide: function() {
42 | this.mask.style.display = "none";
43 | },
44 | drag: function(node) {
45 | node.style.cursor = "move"
46 | addEvent(node, "mousedown", function(event) {
47 | var disX = event.clientX - node.offsetLeft,
48 | disY = event.clientY - node.offsetTop;
49 | function move(event) {
50 | node.style.left = event.clientX - disX + "px";
51 | node.style.top = event.clientY - disY + "px";
52 | }
53 | addEvent(document, "mousemove", move);
54 | addEvent(document, "mouseup", function(){
55 | removeEvent(document, "mousemove", move);
56 | });
57 | });
58 | }
59 | }
60 |
61 | function creatMaskLayer(maskNode, floNode) {
62 | return new MaskLayer(maskNode, floNode);
63 | }
64 |
65 | (function() {
66 | var maskLayer = creatMaskLayer($("mask"), $("floatLayer"));
67 | maskLayer.init();
68 |
69 | addEvent($("floatLayer"), "click", function(event) {
70 | event.stopPropagation();
71 | });
72 | addEvent($("mask"), "click", function() {
73 | maskLayer.hide();
74 | });
75 | addEvent($("sure"), "click", function() {
76 | maskLayer.hide();
77 | });
78 | addEvent($("cancel"), "click", function() {
79 | maskLayer.hide();
80 | });
81 | addEvent($("login"), "click", function() {
82 | maskLayer.show();
83 | });
84 | })();
--------------------------------------------------------------------------------
/part3/task38/README.md:
--------------------------------------------------------------------------------
1 | 38任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 练习对于代码的抽象与封装
5 | 为第四阶段的RIA任务做准备
6 | 任务描述
7 |
8 | 实现一个支持列排序的表格组件
9 |
10 | 提供生成表格的接口,表格中的数据,表格样式尽量低耦合
11 | 可以配置对哪些列支持排序功能,并在表头进行排序按钮的显示,图中的样式为示意参考,可自行设定样式及交互方式
12 | 提供点击排序按钮后的响应接口,并提供默认的排序方法,当提供的接口没有具体实现时,按默认的排序方法进行排序操作,并更新表格中的数据显示。
13 | 任务注意事项
14 |
15 | 请注意代码风格的整齐、优雅
16 | 代码中含有必要的注释
17 | 可以合理选择使用其它第三方类库,但不建议
--------------------------------------------------------------------------------
/part3/task38/task38.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UI组件之排序表格
6 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/part3/task38/task38.js:
--------------------------------------------------------------------------------
1 | // 兼容的事件方法
2 | function addEvent(ele, event, hanlder) {
3 | if (ele.addEventListener) {
4 | ele.addEventListener(event, hanlder, false);
5 | } else if (ele.attachEvent) {
6 | ele.attachEvent('on' + event, hanlder);
7 | } else {
8 | ele['on' + event] = hanlder;
9 | }
10 | }
11 |
12 | function $(id) {
13 | return document.getElementById(id);
14 | }
15 |
16 | function ce(nodeName) {
17 | return document.createElement(nodeName);
18 | }
19 |
20 | // 随机产生分数
21 | function randomData(n) {
22 | var arry = [],
23 | sum = 0;
24 | for (var i = 0; i < n; i++) {
25 | var num = Math.floor(Math.random()*100)+1;
26 | sum += num;
27 | arry.push(num);
28 | }
29 | arry.push(sum);
30 | return arry;
31 | }
32 |
33 | var sourceData = {
34 | "小明": randomData(3),
35 | "小红": randomData(3),
36 | "小亮": randomData(3),
37 | "小华": randomData(3),
38 | "小花": randomData(3)
39 | };
40 | var object = ["姓名", "语文", "数学", "英语", "总分"];
41 |
42 | function SortTable(data, object, table) {
43 | this.table = table;
44 | this.data = data;
45 | this.object = object;
46 | this.name = null;
47 | }
48 |
49 | SortTable.prototype = {
50 | init: function() {
51 | this.name = [];
52 | for (var i in this.data) {
53 | this.name.push(i);
54 | }
55 | this.render();
56 | },
57 | render: function() { // 按照名字的排序方式来渲染表格
58 | var content = "";
59 | content += "";
60 | for (var i in this.object) {
61 | content += "" + this.object[i] + " ";
62 | }
63 | content += " ";
64 | for (var j in this.name) {
65 | content += "" + "" + this.name[j] + " ";
66 | for(var k in this.data[this.name[j]]) {
67 | content += "" + this.data[this.name[j]][k] + " ";
68 | }
69 | content += " ";
70 | }
71 | this.table.innerHTML = content;
72 | this.addArrow();
73 | },
74 | addArrow: function() {
75 | var self = this;
76 |
77 | // 给每个三角箭头赋上点击事件 点击的时候排序
78 | function addSortEvent(index) {
79 | var container = ce("div"),
80 | divUp = ce("div"),
81 | divDown = ce("div");
82 |
83 | divUp.className = "up";
84 | divDown.className = "down";
85 | container.className = "container";
86 | container.appendChild(divUp);
87 | container.appendChild(divDown);
88 | self.table.children[0].children[0].children[i].appendChild(container); // 取得th节点 再把三角箭头添加进去
89 |
90 | addEvent(divUp, "click", function(event) {
91 | self.name.sort(function(a, b){
92 | return self.data[b][index - 1] - self.data[a][index - 1];
93 | });
94 | self.render();
95 | });
96 | addEvent(divDown, "click", function(event) {
97 | self.name.sort(function(a, b){
98 | return self.data[a][index - 1] - self.data[b][index - 1];
99 | });
100 | self.render();
101 | });
102 | }
103 |
104 | // 在这先把索引值弄好 再把值传到addSortEvent函数 这样索引值就固定不变
105 | for(var i = 1, len = self.object.length; i < len; i++) {
106 | addSortEvent(i);
107 | }
108 | }
109 | }
110 | var sortTab = new SortTable(sourceData, object, $("tab"));
111 | sortTab.init();
--------------------------------------------------------------------------------
/part3/task39/README.md:
--------------------------------------------------------------------------------
1 | 39任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 练习对于代码的抽象与封装
5 | 为第四阶段的RIA任务做准备
6 | 任务描述
7 |
8 | 实现一个支持首行冻结的表格组件
9 |
10 | 当页面向下滚动,使得第一行已经在屏幕外时,则第一行则变成始终固定在屏幕最上方
11 | 当整个表格都滚动出屏幕时,固定的第一行也消失
12 | 任务注意事项
13 |
14 | 请注意代码风格的整齐、优雅
15 | 代码中含有必要的注释
16 | 可以合理选择使用其它第三方类库,但不建议
--------------------------------------------------------------------------------
/part3/task39/task39.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UI组件之冻结行列表格
6 |
61 |
62 |
63 |
64 | .
.
65 | .
.
66 | .
.
67 | .
.
68 | .
.
69 | .
.
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/part3/task39/task39.js:
--------------------------------------------------------------------------------
1 | // 兼容的事件方法
2 | function addEvent(ele, event, hanlder) {
3 | if (ele.addEventListener) {
4 | ele.addEventListener(event, hanlder, false);
5 | } else if (ele.attachEvent) {
6 | ele.attachEvent('on' + event, hanlder);
7 | } else {
8 | ele['on' + event] = hanlder;
9 | }
10 | }
11 |
12 | function $(id) {
13 | return document.getElementById(id);
14 | }
15 |
16 | function ce(nodeName) {
17 | return document.createElement(nodeName);
18 | }
19 |
20 | // 随机产生分数
21 | function randomData(n) {
22 | var arry = [],
23 | sum = 0;
24 | for (var i = 0; i < n; i++) {
25 | var num = Math.floor(Math.random()*100)+1;
26 | sum += num;
27 | arry.push(num);
28 | }
29 | arry.push(sum);
30 | return arry;
31 | }
32 |
33 | var sourceData = {
34 | "小明": randomData(3),
35 | "小红": randomData(3),
36 | "小亮": randomData(3),
37 | "小华": randomData(3),
38 | "小a": randomData(3),
39 | "小b": randomData(3),
40 | "小c": randomData(3),
41 | "小d": randomData(3),
42 | "小e": randomData(3),
43 | "小f": randomData(3),
44 | "小h": randomData(3),
45 | "小1": randomData(3),
46 | "小1": randomData(3),
47 | "小11": randomData(3),
48 | "小111": randomData(3),
49 | "小21": randomData(3),
50 | "小121": randomData(3),
51 | "小122": randomData(3),
52 | "小1231": randomData(3),
53 | "小31": randomData(3),
54 | "小1411": randomData(3)
55 | };
56 | var object = ["姓名", "语文", "数学", "英语", "总分"];
57 |
58 | function SortTable(data, object, table) {
59 | this.table = table;
60 | this.data = data;
61 | this.object = object;
62 | this.name = null;
63 | }
64 |
65 | SortTable.prototype = {
66 | init: function() {
67 | this.name = [];
68 | for (var i in this.data) {
69 | this.name.push(i);
70 | }
71 | this.render();
72 | },
73 | render: function() { // 按照名字的排序方式来渲染表格
74 | var content = "";
75 | content += "";
76 | for (var i in this.object) {
77 | content += "" + this.object[i] + " ";
78 | }
79 | content += " ";
80 | for (var j in this.name) {
81 | content += "" + "" + this.name[j] + " ";
82 | for(var k in this.data[this.name[j]]) {
83 | content += "" + this.data[this.name[j]][k] + " ";
84 | }
85 | content += " ";
86 | }
87 | this.table.innerHTML = content;
88 | this.addArrow();
89 | },
90 | addArrow: function() {
91 | var self = this;
92 |
93 | addEvent(document, "scroll", function(event) {
94 | console.log(self.table.offsetHeight);
95 | if (document.body.scrollTop >= self.table.offsetHeight) {
96 | self.table.children[0].children[0].style.position = "relative";
97 | }
98 | else {
99 | self.table.children[0].children[0].style.position = "fixed";
100 | }
101 | });
102 |
103 | // 给每个三角箭头赋上点击事件 点击的时候排序
104 | function addSortEvent(index) {
105 | var container = ce("div"),
106 | divUp = ce("div"),
107 | divDown = ce("div");
108 |
109 | divUp.className = "up";
110 | divDown.className = "down";
111 | container.className = "container";
112 | container.appendChild(divUp);
113 | container.appendChild(divDown);
114 | self.table.children[0].children[0].children[i].appendChild(container); // 取得th节点 再把三角箭头添加进去
115 |
116 | addEvent(divUp, "click", function(event) {
117 | self.name.sort(function(a, b){
118 | return self.data[b][index - 1] - self.data[a][index - 1];
119 | });
120 | self.render();
121 | });
122 | addEvent(divDown, "click", function(event) {
123 | self.name.sort(function(a, b){
124 | return self.data[a][index - 1] - self.data[b][index - 1];
125 | });
126 | self.render();
127 | });
128 | }
129 |
130 | // 在这先把索引值弄好 再把值传到addSortEvent函数 这样索引值就固定不变
131 | for(var i = 1, len = self.object.length; i < len; i++) {
132 | addSortEvent(i);
133 | }
134 | },
135 |
136 | }
137 | var sortTab = new SortTable(sourceData, object, $("tab"));
138 | sortTab.init();
--------------------------------------------------------------------------------
/part3/task40/README.md:
--------------------------------------------------------------------------------
1 | 40任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 练习对于代码的抽象与封装
5 | 为第四阶段的RIA任务做准备
6 | 任务描述
7 |
8 | 实现一个日历选择组件
9 |
10 | 组件默认一直呈显示状态
11 | 通过某种方式选择年、月,选择了年月后,日期列表做相应切换
12 | 通过单击某个具体的日期进行日期选择
13 | 组件初始化时,可配置可选日期的上下限。可选日期和不可选日期需要有样式上的区别
14 | 提供设定日期的接口,指定具体日期,日历面板相应日期选中
15 | 提供获取日期的接口,获取日历面板中当前选中的日期,返回一个日期对象(或其他形式,自定)
16 | 任务注意事项
17 |
18 | 示例图仅为参考,样式及交互方式不需要完全实现一致
19 | 可以使用JQuery等类库,不可直接使用现成的日历组件
20 | 请注意代码风格的整齐、优雅
21 | 代码中含有必要的注释
--------------------------------------------------------------------------------
/part3/task40/task40.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UI组件之日历组件(一)
6 |
46 |
47 |
48 |
49 |
50 |
51 | <
52 | <
53 |
54 | >
55 | >
56 |
57 |
58 |
59 | Sun
60 | Mon
61 | Tue
62 | Wed
63 | Thu
64 | Fri
65 | Sat
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/part3/task40/task40.js:
--------------------------------------------------------------------------------
1 | function $(id) {
2 | return document.getElementById(id);
3 | }
4 |
5 | // 构造函数
6 | function Calender(table) {
7 | this.table = table;
8 | }
9 |
10 | // 原型方法
11 | Calender.prototype = {
12 | init: function() { // 初始化并获取当前年月
13 | var now = new Date();
14 | var y = now.getFullYear();
15 | var m = now.getMonth();
16 | this.repeat(y, m);
17 | },
18 | repeat: function(y, m) { // 获取当月1号是星期几
19 | var start = new Date(y, m, 1);
20 | var indexDay = start.getDay();
21 | var currentDate = $("currentDate");
22 | currentDate.innerHTML = y + "年" + (m+1) + "月"; // 把当前日期显示在caption
23 | this.creatTab(); // 绘制表格
24 | this.renderTab(y, m, indexDay); // 渲染表格
25 | this.returnDate(y, m); // 点击日期的时候把日期显示在INPUT当中
26 | this.chooseDate(y, m); // 为SPAN添加点击事件 可以显示上年 上月 下年 下月的日期
27 | },
28 | creatTab: function() {
29 | var tbody = this.table.tBodies[0]; // 获取tbody的内容
30 | tbody.innerHTML = ""; // 初始化
31 | for (var i = 0; i < 6; i++) { // 创建6行TR 每行TR 7个TD
32 | var tr = document.createElement("tr");
33 | tbody.appendChild(tr);
34 | for (var j = 0; j < 7; j++) {
35 | var td = document.createElement("td");
36 | td.innerHTML = " ";
37 | td.className = "hover";
38 | tr.appendChild(td);
39 | }
40 | }
41 | },
42 | renderTab: function(y, m, indexDay) { // 渲染表格 为表格添加内容
43 | var trs = this.table.tBodies[0].rows;
44 | var count = 1;
45 | var allDay;
46 | var tmp = new Date();
47 | var tmpY = tmp.getFullYear();
48 | var tmpM = tmp.getMonth();
49 | var tmpD = tmp.getDate();
50 | var tempIndex = indexDay;
51 | while (tempIndex > 0) { // 日期1号前面没有日期的格子不设置样式 所以将类名设置为空
52 | tempIndex--;
53 | trs[0].cells[tempIndex].className = "";
54 | }
55 | for (; indexDay < 7; indexDay++) { // 第一行的日期
56 | trs[0].cells[indexDay].innerHTML = count;
57 | count++;
58 | }
59 | for (var i = 1; i < 6; i++) { // 后续行的日期
60 | for (var j = 0; j < 7; j++) {
61 | trs[i].cells[j].innerHTML = count;
62 | count++;
63 | }
64 | }
65 |
66 | switch(m) { // 判断月份并设置当月的天数
67 | case 0:
68 | case 2:
69 | case 4:
70 | case 6:
71 | case 7:
72 | case 9:
73 | case 11:
74 | allDay = 31;
75 | break;
76 | case 3:
77 | case 5:
78 | case 8:
79 | case 10:
80 | allDay = 30;
81 | break;
82 | case 1:
83 | if ((y%400 == 0) || (y%4 == 0 && y%100 != 0))
84 | allDay = 29; // 闰年
85 | else
86 | allDay = 28; // 平年
87 | break;
88 | default: break;
89 | }
90 | for (var k = 0; k < 6; k++) { // 将超过当月天数的TD 内容设为空
91 | for (var n = 0; n < 7; n++) {
92 | if (trs[k].cells[n].innerHTML > allDay) {
93 | trs[k].cells[n].innerHTML = " ";
94 | trs[k].cells[n].className = "";
95 | }
96 | else if (trs[k].cells[n].innerHTML == tmpD && y == tmpY && m == tmpM) {
97 | trs[k].cells[n].style.color = "blue"; // 当天日期高亮显示
98 | }
99 | }
100 | }
101 | },
102 | returnDate: function(y, m) { // 点击日期时将日期的内容显示在INPUT
103 | var trs = this.table.tBodies[0].rows;
104 | var input = $("date");
105 | for (var i = 0; i < 6; i++) {
106 | for (var j = 0; j < 7; j++) {
107 | trs[i].cells[j].onclick = function() {
108 | var d = this.innerHTML;
109 | if (d != " ") {
110 | input.value = y + "-" + (m+1) + "-" + d;
111 | }
112 | }
113 | }
114 | }
115 | },
116 | chooseDate: function(y, m) { // 为SPAN添加点击事件
117 | var self = this;
118 | var spans = document.getElementsByTagName("span");
119 | for (var i = 0, len = spans.length; i < len; i++) {
120 | spans[i].index = i; // 如果不将I这样赋值给spans[i].index 后面的点击事件绑定的全是I的最大值
121 | spans[i].onclick = function() {
122 | switch(this.index) {
123 | case 0:
124 | m--;
125 | break;
126 | case 1:
127 | y--;
128 | break;
129 | case 3:
130 | y++;
131 | break;
132 | case 4:
133 | m++;
134 | break;
135 | default: break;
136 | }
137 | if (m < 0) { // 如果M为1月 在点击上一月时 自动减一年 将月份设为12月
138 | y--;
139 | m = 11;
140 | }
141 | if (m > 11) { // 如果M为12月 在点击下一月时 自动加一年 将月份设为1月
142 | y++;
143 | m = 0;
144 | }
145 | if (y < 1970 || y > 2030) {
146 | alert("当前日历只能显示1970-2030年"); // 设定日期上限下限 超过将弹窗提示
147 | y = 2017;
148 | return;
149 | }
150 | self.repeat(y, m);
151 | }
152 | }
153 | }
154 | }
155 |
156 | function creatCalender(table) { // 创建一个函数来创建对象
157 | return new Calender(table);
158 | }
159 | (function() { // 在打开页面的同时创建对象并执行init();
160 | var calender = creatCalender($("tab"));
161 | calender.init();
162 | })();
--------------------------------------------------------------------------------
/part3/task41/README.md:
--------------------------------------------------------------------------------
1 | 41任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 练习对于代码的抽象与封装
5 | 为第四阶段的RIA任务做准备
6 | 任务描述
7 |
8 | 基于任务40,进行升级
9 |
10 | 日期选择面板默认隐藏,会显示一个日期显示框和一个按钮,点击这两个部分,会浮出日历面板。再点击则隐藏。
11 | 点击选择具体日期后,面板隐藏,日期显示框中显示选取的日期
12 | 增加一个接口,用于当用户选择日期后的回调处理
13 | 任务注意事项
14 |
15 | 示例图仅为参考,样式及交互方式不需要完全实现一致
16 | 可以使用JQuery等类库,不可直接使用现成的日历组件
17 | 请注意代码风格的整齐、优雅
18 | 代码中含有必要的注释
--------------------------------------------------------------------------------
/part3/task41/task41.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UI组件之日历组件(二)
6 |
56 |
57 |
58 |
59 | 显示日历
60 |
61 |
62 | <
63 | <
64 |
65 | >
66 | >
67 |
68 |
69 |
70 | Sun
71 | Mon
72 | Tue
73 | Wed
74 | Thu
75 | Fri
76 | Sat
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/part3/task41/task41.js:
--------------------------------------------------------------------------------
1 | function $(id) {
2 | return document.getElementById(id);
3 | }
4 |
5 | // 构造函数
6 | function Calender(table) {
7 | this.table = table;
8 | }
9 |
10 | // 原型方法
11 | Calender.prototype = {
12 | init: function() { // 初始化并获取当前年月
13 | var self = this;
14 | var btn = $("btn");
15 | btn.onclick = function () { // 为BUTTON添加一个事件 点击将显示或隐藏日历
16 | if (self.table.style.visibility == "visible") {
17 | self.table.style.visibility = "hidden";
18 | btn.innerHTML = "显示日历";
19 | }
20 | else {
21 | self.table.style.visibility = "visible";
22 | btn.innerHTML = "隐藏日历";
23 | }
24 | }
25 |
26 | var now = new Date();
27 | var y = now.getFullYear();
28 | var m = now.getMonth();
29 | this.repeat(y, m);
30 | },
31 | repeat: function(y, m) { // 获取当月1号是星期几
32 | var start = new Date(y, m, 1);
33 | var indexDay = start.getDay();
34 | var currentDate = $("currentDate");
35 | currentDate.innerHTML = y + "年" + (m+1) + "月"; // 把当前日期显示在caption
36 | this.creatTab(); // 绘制表格
37 | this.renderTab(y, m, indexDay); // 渲染表格
38 | this.returnDate(y, m, null); // 点击日期的时候把日期显示在INPUT当中
39 | this.chooseDate(y, m); // 为SPAN添加点击事件 可以显示上年 上月 下年 下月的日期
40 | },
41 | creatTab: function() {
42 | var tbody = this.table.tBodies[0]; // 获取tbody的内容
43 | tbody.innerHTML = ""; // 初始化
44 | for (var i = 0; i < 6; i++) { // 创建6行TR 每行TR 7个TD
45 | var tr = document.createElement("tr");
46 | tbody.appendChild(tr);
47 | for (var j = 0; j < 7; j++) {
48 | var td = document.createElement("td");
49 | td.innerHTML = " ";
50 | td.className = "hover";
51 | tr.appendChild(td);
52 | }
53 | }
54 | },
55 | renderTab: function(y, m, indexDay) { // 渲染表格 为表格添加内容
56 | var trs = this.table.tBodies[0].rows;
57 | var count = 1;
58 | var allDay;
59 | var tmp = new Date();
60 | var tmpY = tmp.getFullYear();
61 | var tmpM = tmp.getMonth();
62 | var tmpD = tmp.getDate();
63 | var tempIndex = indexDay;
64 | while (tempIndex > 0) { // 日期1号前面没有日期的格子不设置样式 所以将类名设置为空
65 | tempIndex--;
66 | trs[0].cells[tempIndex].className = "";
67 | }
68 | for (; indexDay < 7; indexDay++) { // 第一行的日期
69 | trs[0].cells[indexDay].innerHTML = count;
70 | count++;
71 | }
72 | for (var i = 1; i < 6; i++) { // 后续行的日期
73 | for (var j = 0; j < 7; j++) {
74 | trs[i].cells[j].innerHTML = count;
75 | count++;
76 | }
77 | }
78 |
79 | switch(m) { // 判断月份并设置当月的天数
80 | case 0:
81 | case 2:
82 | case 4:
83 | case 6:
84 | case 7:
85 | case 9:
86 | case 11:
87 | allDay = 31;
88 | break;
89 | case 3:
90 | case 5:
91 | case 8:
92 | case 10:
93 | allDay = 30;
94 | break;
95 | case 1:
96 | if ((y%400 == 0) || (y%4 == 0 && y%100 != 0))
97 | allDay = 29; // 闰年
98 | else
99 | allDay = 28; // 平年
100 | break;
101 | default: break;
102 | }
103 | for (var k = 0; k < 6; k++) { // 将超过当月天数的TD 内容设为空
104 | for (var n = 0; n < 7; n++) {
105 | if (trs[k].cells[n].innerHTML > allDay) {
106 | trs[k].cells[n].innerHTML = " ";
107 | trs[k].cells[n].className = "";
108 | }
109 | else if (trs[k].cells[n].innerHTML == tmpD && y == tmpY && m == tmpM) {
110 | trs[k].cells[n].style.color = "blue"; // 当天日期高亮显示
111 | this.returnDate(tmpY, tmpM, tmpD);
112 | }
113 | }
114 | }
115 | },
116 | returnDate: function(y, m, d) { // 点击日期时将日期的内容显示在INPUT
117 | var self = this;
118 | var trs = this.table.tBodies[0].rows;
119 | var input = $("date");
120 | if (d) {
121 | input.value = y + "-" + (m+1) + "-" + d;
122 | return;
123 | }
124 | for (var i = 0; i < 6; i++) {
125 | for (var j = 0; j < 7; j++) {
126 | trs[i].cells[j].onclick = function() {
127 | var d = this.innerHTML;
128 | if (d != " ") {
129 | input.value = y + "-" + (m+1) + "-" + d;
130 | self.table.style.visibility = "hidden"; // 选中一个日期后会隐藏日历
131 | $("btn").innerHTML = "显示日历";
132 | }
133 | }
134 | }
135 | }
136 | },
137 | chooseDate: function(y, m) { // 为SPAN添加点击事件
138 | var self = this;
139 | var spans = document.getElementsByTagName("span");
140 | for (var i = 0, len = spans.length; i < len; i++) {
141 | spans[i].index = i; // 如果不将I这样赋值给spans[i].index 后面的点击事件绑定的全是I的最大值
142 | spans[i].onclick = function() {
143 | switch(this.index) {
144 | case 0:
145 | m--;
146 | break;
147 | case 1:
148 | y--;
149 | break;
150 | case 3:
151 | y++;
152 | break;
153 | case 4:
154 | m++;
155 | break;
156 | default: break;
157 | }
158 | if (m < 0) { // 如果M为1月 在点击上一月时 自动减一年 将月份设为12月
159 | y--;
160 | m = 11;
161 | }
162 | if (m > 11) { // 如果M为12月 在点击下一月时 自动加一年 将月份设为1月
163 | y++;
164 | m = 0;
165 | }
166 | if (y < 1970 || y > 2030) {
167 | alert("当前日历只能显示1970-2030年"); // 设定日期上限下限 超过将弹窗提示
168 | y = 2017;
169 | return;
170 | }
171 | self.repeat(y, m);
172 | }
173 | }
174 | }
175 | }
176 |
177 | function creatCalender(table) { // 创建一个函数来创建对象
178 | return new Calender(table);
179 | }
180 | (function() { // 在打开页面的同时创建对象并执行init();
181 | var calender = creatCalender($("tab"));
182 | calender.init();
183 | })();
--------------------------------------------------------------------------------
/part3/task42/README.md:
--------------------------------------------------------------------------------
1 | 42任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 练习对于代码的抽象与封装
5 | 为第四阶段的RIA任务做准备
6 | 任务描述
7 |
8 | 基于任务41,进行升级
9 |
10 | 增加一个参数及相应接口方法,来决定这个日历组件是选择具体某天日期,还是选择一个时间段
11 | 当设置为选择时间段时,需要在日历面板上点击两个日期来完成一次选择,两个日期中,较早的为起始时间,较晚的为结束时间,选择的时间段用特殊样式标示
12 | 增加参数及响应接口方法,允许设置时间段选择的最小或最大跨度,并提供当不满足跨度设置时的默认处理及回调函数接口
13 | 在弹出的日期段选择面板中增加确认和取消按钮
14 | 任务注意事项
15 |
16 | 示例图仅为参考,样式及交互方式不需要完全实现一致
17 | 可以使用JQuery等类库,不可直接使用现成的日历组件
18 | 请注意代码风格的整齐、优雅
19 | 代码中含有必要的注释
--------------------------------------------------------------------------------
/part3/task42/task42.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UI组件之日历组件(三)
6 |
76 |
77 |
78 | 可以点击两个日期来选择一个时间段 时间段必须大于或等于3天 小于或等于100天
79 |
80 | 显示日历
81 |
82 |
83 | <
84 | <
85 |
86 | >
87 | >
88 |
89 |
90 |
91 | Sun
92 | Mon
93 | Tue
94 | Wed
95 | Thu
96 | Fri
97 | Sat
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 | 确定
107 |
108 |
109 | 取消
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
--------------------------------------------------------------------------------
/part3/task43/README.md:
--------------------------------------------------------------------------------
1 | 43任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 为第四阶段的相册任务做准备
5 | 结合CSS,JavaScript掌握更加复杂的布局方式
6 | 任务描述
7 |
8 | 使用JavaScript、CSS,实现在不同图片数量时的不同布局
9 | 实现封装为一个JavaScript的库
10 |
11 | 任务注意事项
12 |
13 | 请注意代码风格的整齐、优雅
14 | 代码中含有必要的注释
15 | 可以合理选择使用其它第三方类库,但不建议
--------------------------------------------------------------------------------
/part3/task43/images/01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/part3/task43/images/01.jpg
--------------------------------------------------------------------------------
/part3/task43/images/02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/part3/task43/images/02.jpg
--------------------------------------------------------------------------------
/part3/task43/images/03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/part3/task43/images/03.jpg
--------------------------------------------------------------------------------
/part3/task43/images/04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/part3/task43/images/04.jpg
--------------------------------------------------------------------------------
/part3/task43/images/05.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/part3/task43/images/05.jpg
--------------------------------------------------------------------------------
/part3/task43/images/06.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/part3/task43/images/06.jpg
--------------------------------------------------------------------------------
/part3/task43/task43.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | }
5 | .layout {
6 | width: 800px;
7 | height: 450px;
8 | position: relative;
9 | object-fit: cover;
10 | margin: auto;
11 | border: 3px solid red;
12 | }
13 | .layout1 img{
14 | width: 100%;
15 | height: 100%;
16 | }
17 |
18 | .layout2 img {
19 | width: 100%;
20 | height: 100%;
21 | position: absolute;
22 | }
23 | .layout2 img:nth-child(2) {
24 | -webkit-clip-path: polygon(67% 0, 33% 100%, 100% 100%, 100% 0);
25 | }
26 | .layout3 img:nth-child(n+1) {
27 | width: 33%;
28 | height: 50%;
29 | float: right;
30 | }
31 | .layout3 img:nth-child(1) {
32 | width: 67%;
33 | height: 100%;
34 | float: left;
35 | }
36 | .layout4 img {
37 | width: 50%;
38 | height: 50%;
39 | }
40 | .layout4 img:nth-child(odd) {
41 | float: left;
42 | }
43 | .layout4 img:nth-child(even) {
44 | float: right;
45 | }
46 | .layout5 img:nth-child(1) {
47 | float: left;
48 | width: 66.66%;
49 | height: 66.66%;
50 | }
51 | .layout5 img:nth-child(2) {
52 | float: right;
53 | width: 33.33%;
54 | height: 33.33%;
55 | }
56 | .layout5 img:nth-child(3) {
57 | float: right;
58 | width: 33.33%;
59 | height: 66.66%;
60 | }
61 | .layout5 img:nth-child(4) {
62 | float: left;
63 | width: 33.33%;
64 | height: 33.33%;
65 | }
66 | .layout5 img:nth-child(5) {
67 | float: left;
68 | width: 33.33%;
69 | height: 33.33%;
70 | }
71 | .layout6 img:nth-child(n) {
72 | float: left;
73 | width: 33.33%;
74 | height: 33.33%;
75 | }
76 | .layout6 img:nth-child(1) {
77 | float: left;
78 | width: 66.66%;
79 | height: 66.66%;
80 | }
--------------------------------------------------------------------------------
/part3/task43/task43.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 图库
6 |
7 |
8 |
9 |
10 |
11 |
12 |
21 |
22 |
--------------------------------------------------------------------------------
/part3/task43/task43.js:
--------------------------------------------------------------------------------
1 | // 这也算是一个插件 只要参数正确 就能生成对应的图库 图片参数必须为一个数组 数组里有1-6张图片的相对路径 HTML里有调用方法
2 | ;(function($, undefined){
3 | $.fn.creatGallery = function(imgArry) { // 添加一个jQuery原型方法用来创建图库
4 | var myGallery = new Gallery(imgArry, this);
5 | return myGallery; // 返回一个图库的对象
6 | }
7 |
8 | function Gallery(imgArry, container) { // 图库构造函数 值是图片数组和容器DIV
9 | this.imgArry = imgArry;
10 | this.container = container;
11 | }
12 | Gallery.prototype = {
13 | init: function() {
14 | var i,
15 | len = this.imgArry.length;
16 | this.container.attr("class","layout layout" + len); // 根据图片的数量给容器添加类名 然后CSS里有对应1-6张图片不同的样式
17 | for (i = 0; i < len; i++) {
18 | var $img = $(" ");
19 | $img.attr("src", this.imgArry[i]);
20 | this.container.append($img);
21 | }
22 | }
23 | }
24 | })(jQuery);
--------------------------------------------------------------------------------
/part3/task44/README.md:
--------------------------------------------------------------------------------
1 | 44任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 为第四阶段的相册任务做准备
5 | 结合CSS,JavaScript掌握瀑布布局方式
6 | 任务描述
7 |
8 | 使用JavaScript、CSS,实现如图的瀑布布局
9 |
10 | 实现封装为一个JavaScript的库
11 | 在瀑布式布局中,每一栏的宽度是相同的,下图中的黑色数字表示图片被添加的顺序
12 | 每次添加新的图片时,都将其放在高度最小的一栏,以保证每一栏的高度尽可能相近。
13 | 点击一张图片后,全屏显示该图(有能力的同学可以适当增加动画效果)。黑色遮罩的不透明度是 80%,点击黑色部分退出全屏浏览。
14 |
15 | 有能力的同学可以实现,当页面滚动到瀑布图最下方后,通过Ajax动态加载下一批图片
16 | 任务注意事项
17 |
18 | 请注意代码风格的整齐、优雅
19 | 代码中含有必要的注释
20 | 可以合理选择使用其它第三方类库,但不建议。不能直接使用现成的瀑布布局的库
--------------------------------------------------------------------------------
/part3/task44/task44.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | font-family: 微软雅黑;
5 | }
6 | #container {
7 | margin: auto;
8 | font-size: 0;
9 | position: relative;
10 | transition: all 1s;
11 | }
12 | .box {
13 | margin: auto;
14 | display: inline-block;
15 | position: absolute;
16 | }
17 | img {
18 | width: 100%;
19 | height: 100%;
20 | }
21 | input {
22 | width: 200px;
23 | height: 20px;
24 | border-radius: 3px;
25 | color: #d3d3d3;
26 | }
27 | button {
28 | width: 50px;
29 | height: 25px;
30 | color: #fff;
31 | background: #f00;
32 | border: 1px solid #f00;
33 | border-radius: 3px;
34 | }
35 | .floatLay {
36 | background: rgba(0,0,0,0.8);
37 | position: fixed;
38 | top: 50%;
39 | left: 50%;
40 | transform: translate(-50%, -50%);
41 | display: none;
42 | }
43 | .floatLay div {
44 | position: fixed;
45 | top: 50%;
46 | left: 50%;
47 | transform: translate(-50%, -50%);
48 | }
--------------------------------------------------------------------------------
/part3/task44/task44.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 多功能相册之瀑布流
6 |
7 |
8 |
9 |
10 |
11 | 执行
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/part3/task45/README.md:
--------------------------------------------------------------------------------
1 | 45任务目的
2 |
3 | 练习综合运用HTML、CSS、JavaScript实现局部功能
4 | 为第四阶段的相册任务做准备
5 | 结合CSS,JavaScript掌握木桶布局方式
6 | 任务描述
7 |
8 | 使用JavaScript、CSS,实现如图的木桶布局。我们在一些摄影网站(如 500px、flickr 等)有时会看到如下图的布局,每张图片的占位长宽比和图片本身的长宽比是一致的;每一行的高度是不固定的,但是要尽可能接近;每行的图片数也是不同的,在一定范围内(这题中我们规定每行 3-6 张,最后一行除外)通过控制图片是否加入当前行,保证行高尽可能接近。这里我们方便起见给这种布局起名叫“木桶布局”,因为它和木桶一样,不在乎你放多少块木头,以及不同圈的木头高度是否一致,只要每圈都把桶围成同样宽度。
9 |
10 | 实现封装为一个JavaScript的库
11 | 任务注意事项
12 |
13 | 请注意代码风格的整齐、优雅
14 | 代码中含有必要的注释
15 | 可以合理选择使用其它第三方类库,但不建议。不能直接使用木桶布局的库
--------------------------------------------------------------------------------
/part3/task45/task45.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | font-family: 微软雅黑;
5 | }
6 | #container {
7 | margin: 0 auto;
8 | }
9 | .box {
10 | display: inline-block;
11 | box-sizing:border-box;
12 | }
13 | img {
14 | height: 100%;
15 | }
16 | .floatLay {
17 | background: rgba(0,0,0,0.8);
18 | position: fixed;
19 | top: 50%;
20 | left: 50%;
21 | transform: translate(-50%, -50%);
22 | display: none;
23 | }
24 | .floatLay div {
25 | position: fixed;
26 | top: 50%;
27 | left: 50%;
28 | transform: translate(-50%, -50%);
29 | }
--------------------------------------------------------------------------------
/part3/task45/task45.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 多功能相册之木桶布局
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/part3/task45/task45.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | $.fn.creatCask = function(imgNum, width) {
3 | var cask = new Cask(this, imgNum, width);
4 | return cask;
5 | }
6 |
7 | function Cask(container, imgNum, width) { // 参数依次为 容器对象 图片数量 容器总宽度
8 | this.$container = container;
9 | this.minHeight = 200;
10 | this.imgNum = imgNum;
11 | this.containerWidth = width;
12 | this.divArry = []; // 保存着包含图片DIV的数组
13 | }
14 |
15 | Cask.prototype = {
16 | init: function() {
17 | var $container = this.$container;
18 | $container.width(this.containerWidth); // 设置容器总宽度
19 | var imgs = [];
20 | for (var i = 0, len = this.imgNum; i < len; i++) { // 获取每张图片的地址
21 | imgs.push(this.getImg());
22 | }
23 | this.render(imgs); // 加载完图片时返回各列总高度的最小值
24 | var that = this; // 开始增加滚动事件
25 | var $body = $("body");
26 | var screenW = window.screen.width;
27 | var screenH = window.screen.height;
28 | window.onscroll = function(){ // 当滚动到一定的高度开始再次加载图片
29 | if ($body.scrollTop() + screenH > $container.height()) {
30 | that.init();
31 | }
32 | };
33 |
34 | $container.off("click"); // 初始化先去掉容器绑定事件 否则每次滚动到底部的时候 再次加载图片时 绑定事件会叠加 导致浮出层叠加
35 |
36 | $container.click(function(event){ // 为容器添加点击事件 当点击图片时 放大图片 用图片原尺寸显示
37 | var $that = $(this);
38 | var url = event.target.src; // 用正则从图片URL中取得宽高 再赋值给包裹着图片的DIV
39 | var re = /\d{3}/g;
40 | var arry = url.match(re);
41 | var $floatLay = $("");
42 | $floatLay.width(screenW).height(screenH).addClass("floatLay");
43 | var $imgDiv = $("
");
44 | $imgDiv.width(arry[0]).height(arry[1]);
45 | var $img = $("
");
46 | $img.attr("src", url);
47 | $imgDiv.append($img);
48 | $floatLay.append($imgDiv);
49 | $body.append($floatLay);
50 | $floatLay.fadeIn(); // 添加动画事件 淡入
51 | $floatLay.click(function(){ // 当点击遮罩层时 先淡出 再移除遮罩层
52 | var $that = $(this);
53 | $that.fadeOut(500,function(){
54 | $that.remove();
55 | });
56 | });
57 | });
58 | },
59 | getImg: function() {
60 | var width = this.getRandom();
61 | var height = this.getRandom();
62 | var img = "https://placehold.it/" + width + "x" + height + "/" + this.getColor(); // width height为宽高 getColor方法获取图片背景颜色
63 | return img;
64 | },
65 | getColor: function() {
66 | var color = Math.floor(Math.random()*0xffffff+1).toString(16); // 1个16进制数颜色
67 | while (color.length < 6) {
68 | color += "0";
69 | }
70 | return color;
71 | },
72 | getRandom: function() { // 随机获取高度
73 | return Math.floor(Math.random()*450+150);
74 | },
75 | rowcal: function(min, max, divArry) { //min-max 每行能容纳的最小和最大DIV数
76 | var conWidth = this.containerWidth;
77 | var width = 0;
78 | var count = 0;
79 | var minheight = this.minHeight;
80 | var rows = [];
81 | for (var i = 0, len = divArry.length; i < len; i++) {
82 | divArry[i].height(minheight);
83 | divArry[i].width(divArry[i].height()/divArry[i].attr("ratio"));
84 | width += divArry[i].width();
85 | count++;
86 | if ((width > conWidth && count > min) || count > max) {
87 | var totalwidth = width - divArry[i].width();
88 | var rowheight = conWidth*(minheight/totalwidth);
89 | rows.push({num: count - 1, height: rowheight}); // 每行DIV数量 每行的高度
90 | width = divArry[i].width();
91 | count = 1;
92 | }
93 | }
94 | return [rows, count]; // 返回行数量的数组 和剩下不够一行的DIV数量
95 | },
96 | render: function(imgs) { // 开始加载图片
97 | var $container = this.$container;
98 | var divArry = this.divArry;
99 | var index;
100 | for (var i = 0, len = this.imgNum; i < len; i++) {
101 | var $box = $("
");
102 | var $img = $("
");
103 | $img.attr("src", imgs[i]);
104 | $box.append($img);
105 | $box.addClass("box");
106 | var re = /\d{3}/g;
107 | var arry = $img.attr("src").match(re); // 通过正则提取宽高
108 | $box.attr("ratio", (parseInt(arry[1]))/(parseInt(arry[0]))); // ratio 高宽比率
109 | divArry.push($box); // 不直接添加到容器DIV里而添加到数组是为了优化性能
110 | }
111 | var tempArry = this.rowcal(3, 6, divArry);
112 | var rows = tempArry[0];
113 | var count = tempArry[1];
114 | for (i = 0, len = rows.length; i < len; i++) {
115 | var $row = $("
");
116 | $row.height(rows[i].height);
117 | for (var j = 0, jlen = rows[i].num; j < jlen; j++) {
118 | $row.append(divArry.shift().height("100%").width("")); // 设置高度100% 宽度会自动调整
119 | }
120 | $container.append($row);
121 | }
122 | for (i = 0, len = divArry.length; i < len; i++) { // 最后剩下不够一行的 直接添加到容器后面 然后下一次加载图片时用appen动作添加到行容器时 会从原来的位置移除再添加到新的行容器里 所以不必担心重复添加
123 | $container.append(divArry[i]);
124 | }
125 | }
126 | }
127 | $("#container").creatCask(20, 1000).init();
128 | });
--------------------------------------------------------------------------------
/picture/task1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/picture/task1.jpg
--------------------------------------------------------------------------------
/picture/task2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/picture/task2.jpg
--------------------------------------------------------------------------------
/picture/风景1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/picture/风景1.jpg
--------------------------------------------------------------------------------
/picture/风景2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/picture/风景2.jpg
--------------------------------------------------------------------------------
/picture/风景3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woai3c/2016ife-task/707f7393d3ddf81ebc0c63c6677a44039223e7ed/picture/风景3.jpg
--------------------------------------------------------------------------------