JS_Learning

JavaScript Learning

[TOC]

了解

基本知识

脚本语言 scripting language

面向对象 object-oriented

放在 <script> 标签内,或者通过外部引用,多用于浏览器交互

能做什么?

  1. 翻转器(rollover):鼠标指针、突出显示按钮
  2. 处理表单
  3. 设置cookie
  4. 客户端……

不能做什么?

  1. 服务器
  2. 干涉其他脚本打开的窗口
  3. ……

JQuery

JS库,代码复用

Ajax

Asynchronous JavaScript and XML(异步 Javascript 和 XML),实质上是 Javascript 的一小部分,但是使用频繁以至于有了独立的词汇描述。

一种创建交互式 Web 应用程序的方式,由以下技术组成:

  • HTML
  • CSS(Cascading Style Sheet)
  • 使用 Javascript 访问的 DOM(Document Object Model)
  • XML or JSON
  • XMLHttpRequest

事件处理

event handler

用户操作触发事件,事件有其处理程序。

代码分离

将网站分为:

  • HTML:页面内容和结构
  • CSS:页面外观和表现
  • Javascript:页面交互行为

HTML内容的语义性(semantic)划分:

  • <div> :block-level元素,与前后元素之间有物理换行
  • <span> :inline元素

HTML内容的标识(标识一些需要修改的内容,以便 JS 和 CSS 访问):

  • id:唯一元素,CSS 中使用# 访问
  • class:多次使用的元素,CSS 中使用 . 访问

Startup

脚本位置

<head></head>

<body></body>

外部引用<script src=""></script>

Example

1
2
3
4
5
6
7
8
9
10
11
window.onload = WriteMessage;
/* 当窗口完成加载时,执行WriteMessage函数 */

alert("Welcome to my JacaScript page!")
/* 弹窗警告 */

function WriteMessage() {
document.getElementById('test').innerHTML = "Hello World!";
/* 向对应id的HTML标签内写入字符串 */
/* innerHTML 已被W3C废弃,还可以用document.write() */
}

不支持JS?

1
<noscript>This page requests JavaScript.</noscript>

条件选择框?

1
2
confirm("...")
/* 询问,YES返回true,否则返回false */
1
2
3
4
5
6
7
8
if(confirm("Are you sure you want to do that?")) {
alert("You choose YES.");
}
else {
alert("You choose NO.");
}
/* 或者如下书写 */
confirm("Are you sure you want to do that?") ? alert("You choose YES.") : alert("You choose NO.");

获取用户回答?

1
2
prompt("Questions", "default answer")
/* 获取用户对于问题的回答 */
1
2
3
4
5
6
7
var ans = prompt("Are you sure you want to do that?", "Your answer.");
if(ans){
alert("Your answer is " + ans);
}
else {
alert("You refuse to answer.");
}

链接重定向

在HTML上可以直接使用:

1
<a href="target-page.html"><a>

但是JS脚本能够覆盖掉HTML标签的重定向,甚至不会让用户知道

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!-- source-page.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Redirection Test</title>
<script src="redirection.js"></script>
</head>
<body>
<h1>Source Page</h1>
<h2>
<a href="target-page-1.html" id="redirect">Welcome to my site!</a>
</h2>
</body>
</html>

<!-- target-page-1.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Target Page</title>
</head>
<body>
<h1>Target Page 1</h1>
</body>
</html>

<!-- target-page-2.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Target page 2</title>
</head>
<body>
<h1>Target Page 2</h1>
</body>
</html>

没有JS的情况下,点集链接会重定向到 target-page-1.html

使用JS重定向到 target-page-2.html

1
2
3
4
5
6
7
8
9
10
11
12
13
window.onload = initAll;

function initAll() {
/* 点击时调用initRedirect函数 */
document.getElementById("redirect").onclick = initRedirect;
}

function initRedirect() {
/* 重定向到页面 */
window.location = "target-page-1.html";
/* 停止对用户单击的处理,阻止原页面<a>标签的重定向 */
return false;
}

优化体验

加入重定向提醒:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
window.onload = initAll;

function initAll() {
/* 点击时调用initRedirect函数 */
document.getElementById("redirect").onclick = initRedirect;
}

function initRedirect() {
alert("We are not responsible for the content of pages outside out site.");
/* 重定向到页面 */
window.location = this;
/* 停止对用户单击的处理,阻止原页面<a>标签的重定向 */
return false;
}

this:关键字,根据上下文传递value。这里 this 在一个由标签的事件触发的函数中使用,因此 this 是一个链接对象。

无干扰编程 unobstusive scripting,一种使用JS编写网页的方式,旨在分离JS代码和HTML代码

渐进增强,不支持JS的访问者也能够访问全部功能,只是体验较差。

多级条件

多个判断分支:

1
2
3
switch(){
case "":
}

错误处理

1
2
3
4
5
try{
throw
}
catch(){
}

示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
var ans = prompt("Enter a number:", "");
try{
/* 没有输入、输入的是负数、输入的不是数字 */
if(!ans || ans < 0 || isNaN(ans)){
/* 抛出错误 */
throw new Error("Not a valid number!");
}
alert("The square root of " + ans + "is " + Math.sqrt(ans));
}
/* 出现错误时执行,捕获错误 */
catch(errMsg){
alert(errMsg.message);
}

Web 应用程序

Bingo Card

美国的Bingo 卡片是5×5 的方形,5 个列上标着B-I-N-G-O,格子中包含1~75 的数字。正中间通常是一个空的格子,常常印着单词free。 每列可以包含的数字的范围如下:

  • B 列包含数字1~15;
  • I 列包含数字16~30;
  • N 列包含数字31~45;
  • G 列包含数字46~60;
  • O 列包含数字61~75。

HTML & CSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
window.onload = initALL;

/* 标记数字是否被使用过 */
var usedNums = new Array(76);

function initALL() {
if (document.getElementById){
/* 没有点击就执行newCard,点击则执行anotherCard */
document.getElementById("reload").onclick = anotherCard;
newCard();
}
else {
alert("Your browser doesn't support this script.")
}
}

function newCard() {
for (let i = 0; i < 24; i++) {
setSquare(i);
}
}

/* 分离计算过程 */
function setSquare(squareNum) {
var currSquare = "square" + squareNum;
var colPlace = new Array(0,0,0,0,0,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,4);
var colBasis = colPlace[squareNum] * 15;
/* 检查是否使用过该数字 */
do {
var newNum = colBasis + getNewNum();
}
while(usedNums[newNum]);
usedNums[newNum] = true;
document.getElementById(currSquare).innerHTML = newNum;
/* 鼠标点击着色 */
document.getElementById(currSquare).className = "";
document.getElementById(currSquare).onmousedown = toggleColor;
}

/* 分离随机数计算过程 */
function getNewNum() {
return Math.floor(Math.random() * 15) + 1;
}

/* 重新生成Card */
function anotherCard() {
for (let i = 1; i < usedNums.length; i++) {
usedNums[i] = false;
}
newCard();
/* 返回false来防止在initAll中再次执行newCard */
return false;
}

/* JS 操纵 CSS 着色 */
function toggleColor(evt) {
if (evt) {
var squareNum = evt.target;
}
else {
/* 兼容IE */
var square = window.event.srcElement;
}
/* 更改 class 属性以匹配不同样式 */
if (squareNum.className == "") {
squareNum.className = "pickedBG";
}
else {
/* 单击着色的格子,将恢复背景色 */
squareNum.className = "";
}
checkWin();
}

/* 使用了位运算判断是否在集合之内 */
function checkWin() {
var winningOption = -1;
var setSquare = 0;
var winners = new Array(31,992,15360,507904,541729,557328,1083458,2162820,4329736,8519745,8659472,16252928);
/* 对每个选中的格子进行运算 */
for (let i = 0; i < 24; i++) {
var currSquare = "square" + i;
if(document.getElementById(currSquare).className != "") {
document.getElementById(currSquare).className = "pickedBG";
/* 或运算 */
setSquare = setSquare | Math.pow(2, i);
}
}
/* 遍历每个获胜的数字,检查条件 */
for (let i = 0; i < winners.length; i++) {
if ((winners[i] & setSquare) == winners[i]) {
winningOption = i;
}
}
/* 如果有获胜的,则选择获胜模式的格子,并改变其样式 */
if (winningOption > -1) {
for (let i = 0; i < 24; i++) {
if(winners[winningOption] & Math.pow(2, i)) {
currSquare = "square" + i;
document.getElementById(currSquare).className = "winningBG";
}
}
}
}

探测对象

object detection:探测浏览器是否有能力理解使用的对象

1
2
3
4
5
if(document.getElementByID){
}
else {
alert("Your browser doesn't support this script.")
}

对象探测在生产环境中很重要,但是不必总是检查,对于没有100%支持的对象总是需要先检查。

Math

Math.random():生成0-1的随机浮点数

Math.floor:向下取整

Array

生成包含指定元素的数组:

1
var newArray = new Array(1,2,3)

生成有指定个数元素的数组:

1
var newArray = new Array(20)

多种方式调用脚本

点击 Click here 时,不是重新加载页面,而是重新执行脚本:

1
2
3
4
5
6
7
8
9
10
document.getElementById("reload").onclick = anotherCard;

function anotherCard() {
for (let i = 1; i < usedNums.length; i++) {
usedNums[i] = false;
}
newCard();
/* 返回false来防止在initAll中再次执行newCard */
return false;
}

JS 操纵 CSS

通过更改对象的 class 属性,从而匹配CSS中的不同样式。

也可以更改 style 属性,就不必使用CSS文件,但是使用CSS文件能够将页面的表现和交互行为分离。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* JS 操纵 CSS 着色 */
function toggleColor(evt) {
/* 获取事件的目标 */
if (evt) {
var squareNum = evt.target;
}
else {
/* 兼容IE */
var square = window.event.srcElement;
}
/* 更改 class 属性以匹配不同样式 */
if (squareNum.className == "") {
squareNum.className = "pickedBG";
}
else {
/* 单击着色的格子,将恢复背景色 */
squareNum.className = "";
}
}

状态压缩技术

使用二进制位表示某位元素是否在集合内。

1
00 00 00 00 00 00 00 00 00 00 00 00

存在24个格子,编号为 0~23。将上述二进制数从低到高位编号为 0~23,第 i 位若为0则表示第 i 个格子不在集合内,若为1则表示第 i 个格子在集合内。

单元素集合

\[ \begin{equation} \{i\}:\underbrace{00...0\overbrace{1}^{\text{第 i 个}}0...00}_{\text{N个}}=2^i \end{equation} \]

集合合并

按位取或 \[ \{i,j\}=a|b\;\;\;\;(a=\{i\},b=\{j\}) \]

判断元素是否在集合内

按位取与 \[ m\in A:m\&A \]

判断集合是否相等

按位取与,与目标集合比较 \[ A==B:(A\&B)==B \]

图像处理

翻转器

效果:鼠标移动到图像上时,改变网页上的图像。

实现:翻转器 rollover

思路:original img + replacement img

标签中实现

通过加入 onmouseoveronmouseout 事件,使用 document.images["attr"].src="link.png" 更换图片来达到动画效果。

缺点:图片下载缓慢产生的效果延迟。

onmouseover:鼠标指针放在目标上方

onmouseout:鼠标指针离开目标

document.images[“id”].src=“link”:将目标id的 img 标签图像链接替换为对应的图像链接。

1
2
3
<a href="next.html" onmouseover="document.images['2b'].src='replacement.jpg'" onmouseout="document.images['2b'].src='original.jpg'">
<img src="original.jpg" id="2b" alt="2b">
</a>

alt 为非图形化浏览器提供图片的描述。

JS实现

为确保替换图像立刻出现,使用JS预先加载图片到浏览器缓存,并保存在脚本变量中。

HTML & CSS

tagName 总是返回大写的值

这里的翻转器定义在 img 上,不支持老式浏览器(IE3)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
window.onload = rolloverInit;

function rolloverInit() {
/* 扫描每个图像,选择父标签为<a>的进行翻转器设置 */
for (let i = 0; i < document.images.length; i++) {
if (document.images[i].parentNode.tagName == "A") {
setupRollover(document.images[i]);
}
}
}

/* 添加两个新属性到图像对象中 */
function setupRollover(theImage) {
theImage.outImage = new Image();
theImage.outImage.src = theImage.src;
/* 匿名函数,设置鼠标指针离开时的图片对象的显示 */
theImage.onmouseout = function() {
this.src = this.outImage.src;
}
theImage.overImage = new Image();
theImage.overImage.src = "replacement_" + theImage.id + ".png";
/* 匿名函数,设置鼠标指针在其之上时的图片对象的显示 */
theImage.onmouseover = function() {
this.src = this.overImage.src;
}
}

三状态翻转器(点击)

1
2
3
4
5
theImage.clickImage = new Image();
theImage.clickImage.src = "click_" + theImage.id + ".png";
theImage.onclick = function() {
this.src = this.clickImage.src;
}

通过链接触发翻转器

JS通过 id class 操纵文档,因此通过这两个属性定位链接和对应的图像。

对链接的 onmouseover onmouseout onclick 事件定义处理函数,这就需要用到对应的图像对象,因此使用一个新的属性 imgToChange 来储存图像对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function setupRollover(theLink, theImage) {
theLink.imgToChange = theImage;
theLink.onmouseover = function() {
this.imgToChange.src = this.overImage.src;
}
theLink.onmouseout = function() {
this.imgToChange.src = this.outImage.src;
}
/* 新增theLink对象的两个属性 */
theLink.outImage = new Image();
theLink.outImage.src = theImage.src;
theLink.overImage = new Image();
theLink.overImage.src = "replacement_" + theImage.id + ".png";
}

程序附录

Web App

返回

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Make Your Own Bingo Card</title>
<link rel="stylesheet" href="bingo-card.css">
<script src="bingo-card.js"></script>
</head>
<body>
<h1>Create A Bingo Card</h1>
<table>
<tr>
<th>B</th>
<th>I</th>
<th>N</th>
<th>G</th>
<th>O</th>
</tr>
<tr>
<td id="square0">&nbsp;</td>
<td id="square5">&nbsp;</td>
<td id="square10">&nbsp;</td>
<td id="square14">&nbsp;</td>
<td id="square19">&nbsp;</td>
</tr>
<tr>
<td id="square1">&nbsp;</td>
<td id="square6">&nbsp;</td>
<td id="square11">&nbsp;</td>
<td id="square15">&nbsp;</td>
<td id="square20">&nbsp;</td>
</tr>
<tr>
<td id="square2">&nbsp;</td>
<td id="square7">&nbsp;</td>
<td id="free">Free</td>
<td id="square16">&nbsp;</td>
<td id="square21">&nbsp;</td>
</tr>
<tr>
<td id="square3">&nbsp;</td>
<td id="square8">&nbsp;</td>
<td id="square12">&nbsp;</td>
<td id="square17">&nbsp;</td>
<td id="square22">&nbsp;</td>
</tr>
<tr>
<td id="square4">&nbsp;</td>
<td id="square9">&nbsp;</td>
<td id="square13">&nbsp;</td>
<td id="square18">&nbsp;</td>
<td id="square23">&nbsp;</td>
</tr>
</table>
<p><a href="bingo-card.html" id="reload">Click here </a>to create a new card.</p>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
body {
background-color: white;
color: black;
font-size: 20px;
font-family: "Lucida Grande", Verdana, Arial, Helvetica, sans-serif, Tahoma, sans-serif;
}

h1, th {
font-family: Georgia, 'Times New Roman', Times, serif;
}

h1 {
font-size: 28px;
}

table {
border-collapse: collapse;
}

th, td {
padding: 10px;
border: 2px #666 solid;
text-align: center;
width: 20%;
}

#free, .pickedBG {
background-color: #f66;
}

.winningBG {
background-image: url("winningBG.png");
}

Rollover

返回

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rollover Test</title>
<script src="rollover.js"></script>
<link rel="stylesheet" href="rollever.css">
</head>
<body>
<a href="next.html" ><img src="original_arrow.png" id="arrow" alt="arrow"></a>
</body>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
body {
background-color: #ffffff;
}

img {
border-width: 0;
}

img#arrow, img#arrowImg {
width: 147px;
height: 82px;
}

#button1, #button2 {
width: 113px;
height: 33px;
}

.centered {
text-align: center;
}