Javascript

时间:2021-06-10 01:16:43

Javascript

一、概述

  • 脚本语言
  • 解释性
  • 解释器作为浏览器一部分
  • 弱类型,定义变量时不需要指定类型。
  • 动态类型,变量类型可以发生变化。
  • 基于原型继承
  • 内置支持类型

作用:给页面添加动态功能。

二、JS组成

  • ECMAScript:js标准语法
  • 文档对象模型(DOM)
  • 浏览器对象模型(BOM)

三、JS的导入

3.1 在页面元素中使用
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<input type="button" value="点击我试试" onclick="alert('Hello,world')"/>
	</body>
</html>
3.2 在script标签中使用

script标签可以放在页面大多数位置,但是推荐放到最后,html的外面。

注意:type属性可以不写,如果写,值应该是text/javascript

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<input type="button" value="点击我试试1" onclick="fn1()"/>
	</body>
</html>
<script type="text/javascript">
	function fn1(){
		alert('Hello');
	}
</script>
3.3 外部导入

使用script引入外部的js,可以在head中引入,也可在大多数位置引入,推荐写在最后。

注意:

  • type属性可以不写,如果写,值应该是text/javascript
  • 结束标签必须要写,不能直接改成自结束。
  • 不能在中间写js代码。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<input type="button" value="点击我试试2" onclick="fn2()"/>
	</body>
</html>
<script type="text/javascript" src="js/common.js" ></script>

四、变量

var作为变量定义的关键字。

弱类型,动态类型,命名规则与Java相似。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
	</body>
</html>
<script>
	var n = 100 // 弱类型
	// 类似Java中的sout
	console.log(n)
    // 动态类型
	n = "hello, world"
	console.log(n)
</script>

五、基本类型

基本类型有5种:

  • Number
  • String
  • Boolean
  • Undefined
  • Null
<script>
	var age = 9; // number
	console.log(typeof(age));
	console.log(age / 2); // 数字不区分小数整数,所以9/2 =4.5
	var name = "mary";
	console.log(typeof(name)); // string
	var flag = true;
	console.log(typeof(flag)); // boolean
	var phone;
	console.log(phone); // undefined
	console.log(typeof(phone)); // undefined
	var person = null;
	console.log(person); // null
	console.log(typeof(person)); // object
</script>

六、引用类型

对象类型:Object类型。

语法:

<script>
	// 使用对象类型
	var obj = new Object();
	obj.name = "张三";
	obj.sex = "男";
	obj.say = function(){
		alert("hello, world");
	}
	console.log(obj.name);
	console.log(obj.sex);
	var n = "name";
	console.log(obj[n]);
	console.log(obj["sex"]);
	obj.say();
	
	// 使用map
	var m = {"name":"李四", sex:"男"} // JSON(JavaScript Object Notation)格式
	console.log(m.name);
	console.log(m.sex);
	console.log(m["name"]);
	console.log(m["sex"]);
</script>

数组类型:

<script>
	// 定义数组,两种方式
	var arr1 = new Array();
	var arr2 = [1,2,3,4];
	// 设置数组的值
	arr1[0] = 5;
	arr1[1] = 10;
	console.log(arr1[1]);
	console.log(arr1.length) // 2
	arr1[10] = "hello";
	console.log(arr1[10]);
	console.log(arr1.length) // 11
	console.log(arr1[5]); // undefined
	
	// js中数组有java中集合的作用
	arr2[arr2.length] = 5;
	console.log(arr2[4]);
	// 通过push添加元素
	arr2.push(10);
	console.log(arr2[5]);
	
	// 循环遍历
	for (var i=0;i<arr2.length;i++) {
		console.log("i==" + arr2[i]);
	}
	// for in循环
	// 注意:i还是下标
	for(var i in arr2){
		console.log("==" + arr2[i]);
	}
	
	// splice可以删除,可以修改,可以添加
	var arr3 = [1,2,3,4,5,6];
//	 从下标3开始删除2个元素
//	arr3.splice(3, 2)
// 从下标3开始删除0个元素,添加8和9,相当于添加
//	arr3.splice(3, 0, 8, 9)
// 从下标3开始删除2个元素,添加8和9,相当于修改
	arr3.splice(3, 2, 8, 9)
	console.log(arr3)
</script>

七、运算符

7.1 算术运算符

与Java类似,不同之处在于,js中只有number类型,所以5/2结果为2.5

7.2 赋值运算符

与Java类似

7.3 逻辑运算符

与Java类似

7.4 关系运算符

大多与Java类似

==:比较值是否相等,所以数字2与字符串"2"是相等的。

===:即比较值也要比较类型,所以数字2与字符串"2"不相等。

<script>
	var n = 2;
	var m = "2";
	console.log(n == m) // true
	console.log(n === m) // false
</script>
7.5 三目(三元)运算符

与Java类似

7.6 分支结构

if结构与Java用法一致。

但是判断条件与Java有区别,Java中判断条件必须是布尔值。而JS中0、null、undefine、NaN表示false,其他表示true。

// 以下代码是可以执行的

if(1){

}

注意:NaN是not a number的缩写,表示不是数字。如果变量没有定义,则会报错。

变量没有定义和undefine区别:

var a;
console.log(a); // undefine
console.log(b); // 会报错 b is not define
console.log(a.name); // 会报错

switch与Java一致。

7.7 循环结构

JS中的for的基本用法,while、do-while、break、continue与Java一致。

注意:for循环中一定不要写int i,JS中没有int

for…in循环

var arrstr = ["mary", "jack", "tom", "andy"];
for(var i = 0; i < arrstr.length; i++){
    console.log(arrstr[i]);
}
// 注意for in循环中的变量还是下标,与Java的foreach不同
for(var s in arrstr){
    console.log(arrstr[s]);
}

八、函数

8.1 函数的定义与调用

函数定义的语法:

function 函数名(参数列表){

}

函数调用的语法:

函数名()

注意:在JS中,函数的调用时,如果函数有参数,可以传相应的参数,也可以少传或不传,但是无论如何,传入的参数都是按顺序匹配。

function m1(){
    alert(5);
}

function m2(m, n){
    alert(m);
}

function m3(m = 10, n){ // 10为默认值,没有传参时值为10
    alert(m);
}

function m4(){
    return 5; // 有返回值就return,没有就不用return
}

m2(8); // 显示8
m2("hello", 5); // 显示hello
m2(); // 显示undefine
m3(); // 显示10
m3("hello"); // 显示hello
var n = m4(); // 得到函数调用的返回值
alert(n);
8.2 函数变量

类似于Java中方法引用。或者C语言中的方法指针。

var n = m1; // 定义变量,值为一个函数
n(); // 调用该函数


function m1(){
    alert(5);
}
8.3 函数参数
m2(m1);
var n = m1;
m2(n);

function m1(){
    alert("hello");
}

// 由于函数中m进行函数调用,意味着m参数必须传入一个函数
function m2(m){
    m();
}
8.4 匿名函数
var n = function(){
    alert("hello");
};

n();

// 将匿名函数传入到函数的参数中
m2(function(){
    alert("world");
});

function m2(m){
    m();
}
8.5 函数的返回值
function f1(){
    // 第一种写法,函数中定义函数
    //		var n = function(){
    //			alert("hello");
    //		}
    // 第二种写法,函数中定义函数
    //		function n(){
    //			alert("hello");
    //		}
    //		return n;

    // 使用匿名函数
    return function(){
        return function(){
            alert("world");
        }
    }
}

var m = f1();
m()();

f1()()();

九、弹窗函数

alert(msg)弹出一个确定按钮的窗口。

confirm(msg)弹出一个有确定和取消按钮的窗口。

<script>
	function fn1(){
		 if(confirm("确定要删除吗?")){
		 	alert("你点击了确定")
		 }else{
		 	alert("你点击了取消")
		 }
	}
</script>

prompt(msg, default)弹出一个可以输入内容的窗口。

  • msg:提示信息
  • default:输入框中的默认值
  • 返回值为输入的内容,如果没有输入任何内容,点击确定后返回值为空串,如果点击取消,返回null
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<input type="button" value="输入" onclick="fn2()"/>
	</body>
</html>
<script>
	function fn2(){
		var r = prompt("请输入姓名", "mary")
		if(r){
		 	alert("你点击了确定")
		 }else{
		 	alert("你点击了取消或者没有输入任何内容")
		 }
	}
</script>

十、系统函数

parseInt():将一个内容转换成整数。

<script>
	var n = 5.5;
	console.log(parseInt(n)); // 将小数转换成整数
	n = "123";
	console.log(parseInt(n) + 1); // 将字符串转换成整数
	n = "235a34563";
	console.log(parseInt(n) + 1); // 236,将字符串转换成整数
	n = "a234";
	console.log(parseInt(n)); // 得到NaN
</script>

parseFloat():将一个内容转换成小数。

<script>
	var n = 5.5;
	console.log(parseFloat(n)); // 将小数转换成小数
	n = "123.3";
	console.log(parseFloat(n) + 1); // 将字符串转换成小数
	n = "235a34563";
	console.log(parseFloat(n) + 1); // 236,将字符串转换成小数
	n = "a234";
	console.log(parseFloat(n)); // 得到NaN
</script>

isNaN():不是数字返回true,是数字返回false

不会关心类型,只会判断值是否不是数字。

<script>
	console.log(isNaN("235a")); // true
	console.log(isNaN("235")); // false
	console.log(isNaN(235)); // false
</script>

十一、事件

鼠标操作:

  • onclick:单击
  • ondbclick:双击
  • onmouseup:按键弹起
  • onmousedown:按键按下
  • onmouseover:当鼠标移入
  • onmouseout:当鼠标移出
  • onmousemove:当鼠标移动
  • onmouseenter:当鼠标移入
  • onmouseleave:当鼠标移出
  • onmousewheel:滚轮滚动
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			div{
				width: 600px;
				height: 240px;
				border: 1px solid #ccc;
				display: none;
			}
		</style>
	</head>
	<body>
		<input type="button" value="手机" onmouseover="fn1()" onmouseout="fn2()"/>
		
		<div id="div1">
			<ul>
				<li>苹果</li>
				<li>华为</li>
				<li>小米</li>
			</ul>
		</div>
	</body>
</html>
<script>
	function fn1(){
		// 得到div1
		document.getElementById("div1").style.display = "block";
	}
	
	function fn2(){
		// 得到div1
		document.getElementById("div1").style.display = "none";
	}
</script>

键盘操作:

  • onkeydown:键盘按下
  • onkeyup:键盘弹起
  • onkeypress:键盘敲击
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			*{
				padding: 0px;
				margin: 0px;
			}
		</style>
	</head>
	<body>
		<div id="div1" style="width: 50px;height: 50px;background-color: red;position: absolute;top: 50px;left: 50px;"></div>
	</body>
</html>
<script>
	var d = document.getElementById("div1");
	document.onkeydown = function(e){
		// 得到按键的编码
//		alert(e.keyCode);
		if(e.keyCode == 37){ // left
			d.style.left = (parseInt(d.style.left) - 5) + "px";
		}else if(e.keyCode == 38){ // up
			d.style.top = (parseInt(d.style.top) - 5) + "px";
		}else if(e.keyCode == 39){ // right
			d.style.left = (parseInt(d.style.left) + 5) + "px";
		}else if(e.keyCode == 40){ // down
			d.style.top = (parseInt(d.style.top) + 5) + "px";
		}
	};
</script>

其他事件:

  • onload:加载完成后执行,写在body标签中表示页面加载完成后执行
  • onsubmit:表单提交事件,写在form标签中
  • onchange:值改变事件,一般用在表单元素中。
  • onblur:失去焦点事件
  • onfocus:获得焦点事件
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body onload="fn1()">
		<form onsubmit="return fn5()" action="列表.html" method="get">
			<input type="text" onblur="fn3()" name="username" id="userTxt"  placeholder="请输入用户名"/>
			<span id="span1"></span>
			<br />
			<!--密码框-->
			<input type="password" onfocus="fn4()" name="password" id="pwdTxt" value="" placeholder="请输入密码"/><br />
			
			省份:<select id="sel" onchange="fn2()" name="province">
				<option value="">请选择</option>
				<option value="1">湖北</option>
				<option value="2">湖南</option>
			</select><br />
			城市:<select id="sel1"  name="city">
				
			</select><br />
			<!--提交按钮,点击后会提交表单到action对应的地址-->
			<input type="submit" value="提交"/>
		</form>
	</body>
</html>
<script>
	var u = document.getElementById("userTxt");
	var p = document.getElementById("pwdTxt");
	var s = document.getElementById("sel");
	var s1 = document.getElementById("sel1");
	var span1 = document.getElementById("span1");
	function fn1(){
		u.value = "";
		p.value = "";
		s.value = "";
	}
	
	function fn2(){
		if(s.value == "1"){
			s1.options.length = 0;
			s1.options.add(new Option("武汉", "1"));
			s1.options.add(new Option("鄂州", "2"));
			s1.options.add(new Option("黄石", "3"));
		}else if(s.value == "2"){
			s1.options.length = 0;
			s1.options.add(new Option("长沙", "4"));
			s1.options.add(new Option("株洲", "5"));
			s1.options.add(new Option("岳阳", "6"));
		}
	}
	
	function fn3(){
		if(u.value.length < 6){
			// innerHTML可以显示标签样式
			// innerText只能显示文本
			span1.innerHTML = "<font color='red'>用户名长度不能低于6位<font>";
			// 获得焦点
//			u.focus();
			// 将内容全选
//			u.select();
		}
	}
	
	function fn4(){
		p.value = "123456";
	}
	
	function fn5(){
		if(u.value.length < 6){
			alert("用户名不合法")
			return false
		}
		if(p.value.length < 6){
			alert("密码不合法")
			return false
		}
		if(s.value == ""){
			alert("必须选择一个省份")
			return false
		}
		return true
	}
</script>

十二、DOM操作

当页面加载后,页面上HTML元素,统称为文档对象模型(DOM)。

DOM操作,即使用js对文档对象模型中的元素进行操作。

  • 对HTML元素本身进行增删改查操作
  • 对HTML元素的样式进行操作
12.1 查找HTML元素

主要有三种方法:

  • getElementById(“”):通过id属性获取某个元素。
  • getElementsByTagName(“”):通过标签名称得到一组元素。
  • getElementsByClassName(“”):通过class名称得到一组元素。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			.c2{
				width: 50px;
				height: 50px;
			}
		</style>
	</head>
	<body>
		<input type="checkbox" onclick="fn2()" id="chk"/><br />
		<input type="checkbox" class="c1 c2"/>
		<input type="checkbox" class="c1"/>
		<input type="checkbox" class="c1"/>
		<input type="checkbox" class="c1"/>
		<input type="checkbox" class="c1"/>
		<input type="checkbox" class="c1"/>
		<input type="checkbox" class="c1"/>
		<!--button标签默认是submit,需要设置type属性-->
		<button type="button" onclick="fn1()">点击</button>
	</body>
</html>
<script>
	function fn1(){
		var arr = document.getElementsByTagName("input");
		for(i in arr){
			arr[i].checked = true;
		}
	}
	
	function fn2(){
		// 得到复选框是否被勾选的状态
		var c = document.getElementById("chk").checked;
        // 得到class属性中有c1的元素
		var arr = document.getElementsByClassName("c1");
		for(i in arr){
			arr[i].checked = c;
		}
	}
</script>
12.2 修改HTML元素内部内容

有两种方式:

  • innerText:只能显示文本内容,如果有标签会以文本的方式显示。
  • innerHTML:可以显示标签的效果
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<h1 align="center">Hello, world</h1>
		<input type="button" value="点击" onclick="fn1()"/>
	</body>
</html>
<script>
	function fn1(){
		var arr = document.getElementsByTagName("h1");
        // 只会以文本的方式显示
//		arr[0].innerText = "<font color='red'>AAAA</font>";
        // 可以显示出红色的字体
		arr[0].innerHTML = "<font color='red'>AAAA</font>";
	}
</script>
12.3 修改属性

有两种方式:

  • 对象.属性
  • 通过getAttribute(“属性名”)获取属性值,通过setAttribute(“属性名”, “属性值”);来设置属性值。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<a id="a1" href="https://www.baidu.com">百度</a>
		<img id="img1" src="img/13.png" width="200px"/><br />
		<input type="button" value="点击" onclick="fn1()"/>
	</body>
</html>
<script>
	function fn1(){
		var a1 = document.getElementById("a1");
		a1.innerText = "千锋";
		a1.setAttribute("href", "https://www.qfedu.com");
//		a1.href = "https://www.qfedu.com";
		var img1 = document.getElementById("img1");
		img1.src = "img/14.png";
	}
</script>
12.4 修改css

一般可以通过style属性来修改。

注意:在样式的名称可能类似border-width,在js中会使用驼峰式即borderWidth。

但是style只能得到行内的样式,而无法得到内部或外部加载的样式。

如果要想获取非行内样式,IE9以下的版本与其他浏览器有差异。

function getStyle(elem, attr){
    if(window.getComputedStyle){ // w3c标准,支持chrome,firefox,safari,IE9+等
        return window.getComputedStyle(elem)[attr];
    }else if(elem.currentStyle){ // IE其他版本
        elem.currentStyle[attr];
    }else{
        return null;
    }
}
<input type="text" onblur="fn3()" name="username" id="userTxt"  placeholder="请输入用户名"/>
<img id="img1" style="display: none;" src="img/icon1.png" />
<br />
<!--密码框-->
<input type="password" onfocus="fn4()" name="password" id="pwdTxt" value="" placeholder="请输入密码"/><br />
<script>
function fn3(){
    if(u.value.length < 6){
        document.getElementById("img1").style.display = "inline";
    }else{
        document.getElementById("img1").style.display = "none";
    }
}
</script>
12.5 事件的添加和移除

如果直接在标签中写事件,意味着该事件是静态,不能够动态操作。可以通过下面两种方式,动态给元素添加事件:

  • 元素.onXxxx = function(){}
  • 元素.addEventListener(事件名, 函数, 冒泡或捕获)

使用元素.onXxxx = function(){},可以多次赋值,但是后面的事件会覆盖前面的事件。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<input type="button" value="设置事件1" onclick="fn1()"/>
		<input type="button" value="设置事件2" onclick="fn2()"/>
		<input id="btn1" type="button" value="事件2"/>
	</body>
</html>
<script>
	function fn1(){
		var btn1 = document.getElementById("btn1");
		btn1.onclick = function(){
			alert("事件2");
		};
	}
	
	function fn2(){
		var btn1 = document.getElementById("btn1");
		btn1.onclick = function(){
			alert("事件2事件2");
		};
	}
</script>

上面的事件如果都设置了,只会保留后设置的事件。

使用元素.addEventListener(事件名, 函数, 冒泡或捕获), 三个参数含义分别为:

  • 事件名:设置事件的名称,不需要写on,例如点击事件:click
  • 函数:可以写已经定义了的函数名称,也可以写匿名函数
  • 冒泡或捕获:可以不设置此参数,默认为false(冒泡),可以设置为true(捕获)
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
	</head>
	<body>
		<input type="button" value="设置事件1" onclick="fn1()"/>
		<input type="button" value="设置事件2" onclick="fn2()"/>
		<input id="btn1" type="button" value="事件2"/>
	</body>
</html>
<script>
	function fn1(){
		var btn1 = document.getElementById("btn1");
		btn1.addEventListener("click", function(){
			alert("事件2");
		});
	}
	
	function fn2(){
		var btn1 = document.getElementById("btn1");
		btn1.addEventListener("click", function(){
			alert("事件2事件2");
		});
	}
</script>

上面的案例,给元素添加了两次点击事件,当元素点击时,会分别执行两个事件,不会覆盖。

冒泡和捕获:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style>
			#div1{
				width: 200px;
				height: 200px;
				background-color: orange;
			}
			#div2{
				width: 100px;
				height: 100px;
				background-color: blue;
			}
		</style>
	</head>
	<body>
		<input type="button" value="设置div1事件1" onclick="fn1()"/>
		<input type="button" value="设置div2事件2" onclick="fn2()"/>
		<div id="div1">
			<div id="div2">
				
			</div>
		</div>
	</body>
</html>
<script>
	function fn1(){
		var div1 = document.getElementById("div1");
		div1.addEventListener("click", function(){
			console.log("div1事件")
		});
	}
	
	function fn2(){
		var div2 = document.getElementById("div2");
		div2.addEventListener("click", function(){
			console.log("div2事件");
		});
	}
</script>

上面的操作,当给元素设置了两次事件后,由于div2在div1中,默认是冒泡,所以当点击div2时,会先执行div2的点击事件,再执行div1的点击事件。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style>
			#div1{
				width: 200px;
				height: 200px;
				background-color: orange;
			}
			#div2{
				width: 100px;
				height: 100px;
				background-color: blue;
			}
		</style>
	</head>
	<body>
		<input type="button" value="设置div1事件1" onclick="fn1()"/>
		<input type="button" value="设置div2事件2" onclick="fn2()"/>
		<div id="div1">
			<div id="div2">
				
			</div>
		</div>
	</body>
</html>
<script>
	function fn1(){
		var div1 = document.getElementById("div1");
		div1.addEventListener("click", function(){
			console.log("div1事件")
		}, true);
	}
	
	function fn2(){
		var div2 = document.getElementById("div2");
		div2.addEventListener("click", function(){
			console.log("div2事件");
		}, true);
	}
</script>

上面将冒泡修改为捕获,所以当点击div2时,会先执行div1的点击事件,再执行div2的点击事件。

事件的移除:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style>
			#div1{
				width: 200px;
				height: 200px;
				background-color: orange;
			}
			#div2{
				width: 100px;
				height: 100px;
				background-color: blue;
			}
		</style>
	</head>
	<body>
		<input type="button" value="设置div1事件1" onclick="fn1()"/>
		<input type="button" value="设置div2事件2" onclick="fn2()"/>
		<input type="button" value="移除事件" onclick="fn3()"/>
		<div id="div1">
			<div id="div2">
				
			</div>
		</div>
	</body>
</html>
<script>
	function fn1(){
		var div1 = document.getElementById("div1");
		div1.addEventListener("click", function(){
			console.log("div1事件")
		});
	}
	
	function fn2(){
		var div2 = document.getElementById("div2");
		div2.addEventListener("click", function(){
			console.log("div2事件")
		});
	}
	
	function fn3(){
		var div2 = document.getElementById("div2");
		div2.removeEventListener("click", function(){
			console.log("div2事件")
		});
	}
</script>

上面的移除div2事件的代码移除经测试后,无法实现,因为使用的匿名函数,应该改为以下方式:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<style>
			#div1{
				width: 200px;
				height: 200px;
				background-color: orange;
			}
			#div2{
				width: 100px;
				height: 100px;
				background-color: blue;
			}
		</style>
	</head>
	<body>
		<input type="button" value="设置div1事件1" onclick="fn1()"/>
		<input type="button" value="设置div2事件2" onclick="fn2()"/>
		<input type="button" value="移除事件" onclick="fn3()"/>
		<div id="div1">
			<div id="div2">
				
			</div>
		</div>
	</body>
</html>
<script>
	function fn1(){
		var div1 = document.getElementById("div1");
		div1.addEventListener("click", function(){
			console.log("div1事件")
		});
	}
	
	function fn2(){
		var div2 = document.getElementById("div2");
		div2.addEventListener("click", fn4);
	}
	
	function fn4(){
		console.log("div2事件");
	}
	
	function fn3(){
		var div2 = document.getElementById("div2");
		div2.removeEventListener("click", fn4);
	}
</script>
12.6 新建和删除元素

当需要动态的新建和删除元素时,可以使用js来进行处理。

  • 使用document.createElement(“标签名”); 创建元素
  • 使用appendChild将元素放入到指定位置。
  • 也可以使用insertBefore来将元素放入到指定的位置。
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			#div1{
				width: 400px;
				height: 400px;
				background-color: orange;
			}
		</style>
	</head>
	<body>
		<div id="div1">
			<span id="span1">111</span>
		</div>
		<input type="button" value="添加元素" onclick="fn1()"/>
	</body>
</html>
<script>
	function fn1(){
		var h = document.createElement("hr");
        // 将h添加到div1的里面的最后
//		var div1 = document.getElementById("div1");
//		div1.appendChild(h);
		
        // 将h添加到span1中的最前面
		var span1 = document.getElementById("span1");
		var refElement=span1.childNodes[0];
		span1.insertBefore(h, refElement);
	}
</script>

删除元素:

  • 元素.remove(); 删除某个元素
  • 父元素.removeChild(子元素); 删除父元素中的某个子元素
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<style>
			#div1{
				width: 400px;
				height: 400px;
				background-color: orange;
			}
		</style>
	</head>
	<body>
		<div id="div1">
			<span id="span1">111</span>
			<span id="span2">222</span>
			<span id="span3">333</span>
			<span id="span4">444</span>
		</div>
		<input type="button" value="删除元素" onclick="fn2()"/>
	</body>
</html>
<script>
	function fn2(){
		// 要删除span
		var span1 = document.getElementById("span1");
//		// 删除自己
//		span1.remove();
		
		var div1 = document.getElementById("div1");
		// 删除子元素
//		div1.removeChild(span1);
	}
</script>

十三、js定时器

  • setTimeout(函数名,延迟时间)多久后,执行相应的函数(仅执行一次)
  • clearTimeout(定时器名):停止

注意:时间单位为毫秒

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<h1 id="aa"></h1>
		<input type="button" value="开始" onclick="fn1()"/>
		<input type="button" value="停止" onclick="fn2()"/>
	</body>
</html>
<script>
	var h = document.getElementById("aa");
	var s;
	function fn1(){
		// 1秒后执行fn3
		s = setTimeout(fn3, 1000);
	}
	
	function fn3(){
		var d = new Date();
		h.innerText = d.toLocaleString();
		s = setTimeout(fn3, 1000);
	}
	
	function fn2(){
		// 停止
		clearTimeout(s);
	}
</script>
  • setInterval(函数名,延迟时间)每隔多久后,执行相应的函数(执行多次)
  • clearInterval(定时器名):停止
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<h1 id="aa"></h1>
		<input type="button" value="开始" onclick="fn1()"/>
		<input type="button" value="停止" onclick="fn2()"/>
	</body>
</html>
<script>
	var h = document.getElementById("aa");
	var s;
	function fn1(){
		// 每隔1秒后执行fn3
		s = setInterval(fn3, 1000);
	}
	
	function fn3(){
		var d = new Date();
		h.innerText = d.toLocaleString();
	}
	
	function fn2(){
		// 停止
		clearInterval(s);
	}
</script>

案例:倒计时

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<input id="btn1" type="button" value="点击" onclick="fn4()"/>
	</body>
</html>
<script>
	var btn1 = document.getElementById("btn1");
	function fn4(){
		var n = 10;
		var e = setInterval(function(){
			btn1.disabled = true;
			btn1.value = n--;
			if(n < 0){
				clearInterval(e);
				btn1.disabled = false;
				btn1.value = "点击";
			}
		}, 1000)
	}
</script>

十四、BOM

BOM浏览器对象模型,主要是指使用js操作浏览器。

整个浏览器顶层为window,window下面又有几个常用的对象属性:

  • history
  • location
  • navigator
  • screen
14.1 window对象

是js的顶层对象,表示浏览器的窗口。

所有的函数、变量均属于window。例如:window.alert()、window.document,自定义的函数fn1()也是属于window的,可以写为window.fn1()

window.innerHeight:窗口高度

window.innerWidth:窗口宽度

注意:得到的当前浏览器中的文档区域的宽度和高度。当窗口缩小或放大时,会改变值。

window.open():打开新窗口

window.close():关闭窗口

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<input type="button" value="点击" onclick="fn1()"/>
		<input type="button" value="打开窗口" onclick="fn2()"/>
		<input type="button" value="关闭窗口" onclick="fn3()"/>
	</body>
</html>
<script>
	function fn1(){
		alert(window.innerWidth + "===" + window.innerHeight);
	}
	
	function fn2(){
		// 打开窗口
		window.open("元素的创建和删除.html", "aaa")
	}
	
	function fn3(){
		// 关闭当前窗口
		window.close()
	}
</script>
14.2 当前屏幕对象

screen.availWidth:浏览所能够最大占据屏幕的宽度

screen.availHeight:浏览所能够最大占据屏幕的高度

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<input type="button" value="点击" onclick="fn1()"/>
	</body>
</html>
<script>
	function fn1(){
		alert(screen.availWidth + "===" + screen.availHeight);
	}
</script>
14.3 location对象

地址栏对象。用来对地址进行操作。能够跳转页面,或者刷新页面。

属性:

  • href:地址
  • hostname:主机名
  • protocol:协议
  • port:端口号

注意:可以通过修改href属性来跳转页面。

方法:

  • reload():刷新页面
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<input type="button" value="点击" onclick="fn1()"/>
		<input type="button" value="刷新" onclick="fn2()"/>
		<input type="button" value="跳转页面" onclick="fn3()"/>
	</body>
</html>
<script>
	function fn1(){
		console.log("href=" + location.href);
		console.log("hostname=" + location.hostname);
		console.log("protocol=" + location.protocol);
		console.log("port=" + location.port);
	}
	
	function fn2(){
		location.reload();
	}
	
	function fn3(){
		// 通过修改href属性来跳转页面
		location.href = "冒泡捕获.html";
	}
</script>
14.4 history对象

history主要是操作浏览器的历史记录。

主要用前进、后退。

back():后退一次

forward():前进一次

go(n):前进或后退n次,n为正数表示前进,n为负数表示后退。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<input type="button" value="跳转页面" onclick="fn1()"/>
		<input type="button" value="前进" onclick="fn2()"/>
		<input type="button" value="go前进" onclick="fn3()"/>
	</body>
</html>
<script>
	function fn1(){
		location.href = "location对象.html";
	}
	
	function fn2(){
		history.forward();
	}
	
	function fn3(){
		history.go(2);
	}
</script>
14.5 navigator对象

查看浏览器的信息。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<input type="button" value="点击" onclick="fn1()"/>
	</body>
</html>
<script>
	function fn1(){
		console.log("appName=" + navigator.appName);
		console.log("appVersion=" + navigator.appVersion);
		console.log("appCodeName=" + navigator.appCodeName);
		console.log("platform=" + navigator.platform);
		console.log("userAgent=" + navigator.userAgent);
	}
</script>

十五、正则表达式

是用来描述字符模式的对象。

作用:用来检查、搜索、替换字符串的模式。

基本语法:

  • var reg = new RegExp(“pattern”, “modifier”);
  • var reg = /pattern/modifier
15.1 修饰符

i:不区分大小写

g:所有的都会匹配,而不是匹配到一个就停止

m:执行多行匹配

15.2 字符

[abc]:查找字符串中的任意一个字符。

[^abc]:查找不是字符串中的任意一个字符。

[0-9]:匹配一个数字

[a-z]:匹配一个小写字母

[A-Z]:匹配一个大写字母

[A-z]:匹配一个大小写字母

(red|green|blue):匹配其中的一个单词

15.3 元字符

. :匹配任意一个字符,除了换行和行结束符

\w:匹配单词字符,字母数字下划线

\W:匹配非单词字符

\d:匹配数字字符

\D:匹配非数字字符

\s:匹配空白字符

\S:匹配非空白字符

15.4 量词

用来表示数量。

n+:表示至少一个

n*:表示0个到多个

n?:表示0个到1个

n{x}:表示x个

n{x,}:表示x个到多个

n{x,y}:表示x个到y个

^表示开始$表示结束

15.5 使用
  • 正则表达式对象.test(“字符串”); 返回true或者false
  • String对象.match(“正则”);返回一个或多个的匹配
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
		<input type="text" id="txt1" onblur="fn1()"/><br />
		<input type="text"/>
	</body>
</html>
<script>
	function fn1(){
		var t = document.getElementById("txt1").value;
		
		// 验证邮箱
		var reg = /^[A-z0-9]+@[A-z0-9]+[\.](com|cn|org|edu|net|gov)$/;
		// 验证手机号
//		var reg = /^1(39|86|30|92|58)[0-9]{8}$/;
		// 验证用户名
//		var reg = /^[\w]{6,16}$/;
		if(reg.test(t)){
			alert("合法")
		}else{
			alert("不合法")
		}
	}
</script>

十六、创建对象的方式

var v = new Date();

16.1 直接使用属性赋值
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>
	</body>
</html>
<script>
	function Student(name, age, sex="男"){
		this.name = name;
		this.age = age;
		this.sex = sex;
		
		this.say = function(){
			return "name = " + this.name + ", age = " + this.age + ", sex =" + this.sex;
		}
		
		this.say1 = function(){
			// 定义变量接收this对象当前的引用
			var that = this;			
			
			function Cla(id, name){
				this.id = id;
				this.name = name;
				
				this.say2 = function(){
					return "id=" + this.id + ", name=" + this.name + ", studentname=" + that.name;
				}
			}
			var c = new Cla(1, "1班");
			return c.say2();
		}
	}
	
	var s = new Student("张三", 20, "女");
	console.log(s.say1());
</script>
16.2 使用prototype
function Student(name, age, sex="男"){
    this.name = name;
    this.age = age;
    this.sex = sex;
}

Student.prototype = {
    say:function(){
        return "name = " + this.name + ", age = " + this.age + ", sex =" + this.sex;
    },

    say1:function(){
        // 定义变量接收this对象当前的引用
        var that = this;			

        function Cla(id, name){
            this.id = id;
            this.name = name;

            this.say2 = function(){
                return "id=" + this.id + ", name=" + this.name + ", studentname=" + that.name;
            }
        }
        var c = new Cla(1, "1班");
        return c.say2();
    }
};

var s = new Student("张三", 20, "女");
console.log(s.say1());

注意:多个方法用逗号隔开。此处是键值对。

16.3 简单的单例模式
var Stu = (function(){
	function Student(){
		console.log("构造函数被调用")
	}
	
	var instance;
	
	var _static = {
		name: "Stu",

		getInstance : function(){
			if(!instance){
				instance = new Student();
			}
			return instance;
		}
	}

	return _static;
})();

var s = Stu.getInstance()

十七、画布和绘制

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<link rel="stylesheet" type="text/css" href="css/canvas.css"/>
		<script src="js/canvas.js" type="text/javascript" charset="utf-8"></script>
	</head>
	<body>
		<canvas id="myCanvas"></canvas>
	</body>
</html>
window.onload = function(){
	// 得到canvas(画布)
	var canvas = document.getElementById("myCanvas");
	// 设置画布的大小
	canvas.width = window.innerWidth;
	canvas.height = window.innerHeight;
	// 设置背景颜色
	canvas.style.backgroundColor = "black";
	// 得到上下文(画笔)
	var context = canvas.getContext("2d");
	
	var i = 0;
	// 循环执行画圆
	setInterval(function(){
		context.clearRect(0,0, canvas.width, canvas.height);
		// 开始画画
		context.beginPath();
		// 设置实心画笔的颜色
	 	context.fillStyle = "#" + Math.floor(Math.random() * 0xffffff).toString(16);
		// 设置空心画笔颜色
		//context.strokeStyle = "#FFFFFF";
		// 画一个宽度为50,高度为50的矩形
	//	context.rect(100,100,200,100);
		// 画线
	//	context.moveTo(100,100);
	//	context.lineTo(200,200);
	//	context.lineTo(100, 200);
	//	context.lineTo(0,100);
		// 画圆
		context.arc(200+i*20,200+i*20,100,0,Math.PI * 2,false);
		// 结束画画
		context.closePath();
		// 填充实心内容
		context.fill();
		// 填充空心内容
		// context.stroke();
		// i递增
		//i++;
	}, 200);
	
};
// 绘制图片
window.onload = function(){
	var canvas = document.createElement("canvas");
	canvas.width = window.innerWidth;
	canvas.height = window.innerHeight;
	canvas.style.backgroundColor = "#333333";
	document.body.appendChild(canvas);
	
	var context = canvas.getContext("2d");
	
	// 创建一个图片对象
	var img = new Image();
	img.src = "img/2.png";
	
	// 绘制图片
	// 延时执行
	setTimeout(function(){
		//5个参数时含义 图片,x坐标,y坐标, 宽度,高度
        /*
		1、图片,2、图片中的起始x,3、图片中的起始y
		4、图片中取得的宽度,5、图片中取得的高度
		6、在画布中显示的x、7、在画布中显示的y
		8、在画布中显示的宽度、9、在画布中显示的高度
		 */
		context.drawImage(img, 100, 100, 500, 500);
	}, 500);
};

十八、案例

18.1 案例1-模拟喷泉
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="js/particle.js" type="text/javascript" charset="utf-8"></script>
		<style type="text/css">
			body{
				margin: 0px;
			}
		</style>
	</head>
	<body>
	</body>
</html>
window.onload = function(){
	// 创建一个画布对象
	var canvas = document.createElement("canvas");
	// 设置大小和颜色
	canvas.width = window.innerWidth;
	canvas.height = window.innerHeight;
	canvas.style.backgroundColor = "#333333";
	// 将画布放置到body里
	document.body.appendChild(canvas);
	// 得到画笔
	var context = canvas.getContext("2d");
	// 定义一个存放所有粒子的数组
	var particles = [ ];
	
	// 调用显示粒子
	showParticle();
	
	// 创建并显示粒子的方法
	function showParticle(){
		// 循环操作
		setInterval(function(){
			// 清空画布
			context.clearRect(0,0,canvas.width, canvas.height);
			// 创建粒子
			var p = new Particle(canvas.width * 0.5, canvas.height * 0.5);
			// 将粒子装入存放粒子的数组
			particles.push(p);
			// 循环更新所有粒子的位置
			for (var i = 0;i<particles.length;i++) {
				// 更新位置
				particles[i].updateData();
			}
		}, 50);
	}
	
	function Particle(x, y){
		// 原坐标
		this.x = x;
		this.y = y;
		// 初始出现的改变的y的值
		this.yVal = -5;
		// 改变的x的值
		this.xVal = Math.random() * 8 - 4;
		// 定义一个下降的重力加速度
		this.g = 0.1;
		// 更新位置
		this.updateData = function(){
			// X值的变化
			this.x = this.x + this.xVal;
			// Y值的变化
			this.y = this.y + this.yVal;
			// 每次改变Y值速度的变化
			this.yVal = this.yVal + this.g;
			// 生成一个随机颜色
			context.fillStyle = "#" + Math.floor(Math.random() * 0xffffff).toString(16);
			// 将更新位置后的圆绘制出来
			this.draw();
		};
		
		// 绘图的方法
		this.draw = function(){
			// 开始画图
			context.beginPath();
			// 画圆
			context.arc(this.x, this.y,5,0,Math.PI * 2, false);
			// 结束画图
			context.closePath();
			// 填充
			context.fill();
		};
	}
};
18.2 俄罗斯方块

俄罗斯方块.html

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>俄罗斯方块</title>
		<link rel="stylesheet" href="css/common.css" />
	</head>
	<body>
		<canvas id="tetris" width="320" height="640"></canvas>
		<canvas id="nextShape" width="200" height="160"></canvas>
		<canvas id="score" width="200" height="160"></canvas>
	</body>
	<script type="text/javascript" src="js/common.js" ></script>
</html>

common.css

*{
	padding: 0;
	margin: 0;
}

body{
	background: url(../img/bg.png);
}


#tetris{
	border: 2px solid white;
	border-radius: 5px;
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	margin: auto;
}

#nextShape{
	position: absolute;
	left: 40px;
	bottom: 160px;
	border-radius: 5px;
	background: orange;
}

#score{
	position: absolute;
	left: 40px;
	top: 160px;
	border-radius: 10px;
	background: orange;
}

common.js

// 定义一个俄罗斯方块的类 Tetris
var Tetris = (function() {
	// 定义存放形状矩阵的数组
	var layouts = [
		[
			[1, 1, 0],
			[0, 1, 1]
		],
		[
			[0, 1, 1],
			[1, 1, 0]
		],
		[
			[1, 0, 0],
			[1, 1, 1]
		],
		[
			[0, 0, 1],
			[1, 1, 1]
		],
		[
			[0, 1, 0],
			[1, 1, 1]
		],
		[
			[1, 1, 1, 1]
		],
		[
			[1, 1],
			[1, 1]
		]
	];
	
	// 分数
	var score = 0;
	// 行数
	var row = 20;
	// 列数
	var col = 10;

	// 构造函数
	function Tetris() {
		// 创建游戏面板对象
		this.board = new Board();
		// 创建提示方块的对象
		this.nextShape = new NextShape();
		// 绘制提示的头部内容
		this.nextShape.drawHeader();
		
		this.score = new Score();
		this.score.drawHeader();
		
		// 回调
		KeyBoard.call(this);
		// 调用自己的初始化方法
		this.init();
	}
	
	Tetris.prototype = {
		init: function() {
			// 调用添加键盘监听事件的方法
			this.addEventHandlers();
			var self = this;
			// 在图片源加载到内存的时候才能绘制出图片
			this.board.shape.block.image.onload = function() {
				// 初始化board对象
				self.board.init();
				// 定时器 刷新canvas画布
				self.timer = setInterval(function() {
					self.board.tick();
				}, 1000);
			}
		}
	}

	// 创建游戏面板的类 Board
	function Board() {
		// 获取面板类的canvas画布
		this.canvas = document.getElementById("tetris");
		// 获取画笔
		this.ctx = this.canvas.getContext("2d");
		// 当前方块
		this.shape = new Shape();
		// 下一个方块
		this.nextShape = new Shape();
		
		// 存放已经下落的方块
		this.list;
	}
	// 原型 定义方法
	Board.prototype = {
		// 定义初始化的方法
		init: function() {
			this.initList();
			this.drawGridLine();
			this.shape.init();
			// 调用形状类的绘制形状的方法
			this.shape.drawShape(this.ctx);
			// 初始化下一个形状
			this.nextShape.init();
			// 绘制下一个形状
			window.Tetris.nextShape.drawNextShape(this.nextShape);
			window.Tetris.score.drawScore();
			
		},
		// 初始化list
		initList: function() {
			this.list = [];
			for (var i = 0; i < row; i++) {
				this.list[i] = [];
				for (var j = 0; j < 10; j++) {
					this.list[i][j] = 0;
				}
			}
		},
		// 把下落的块堆积起来的方法
		addShapeToList: function() {
			for (var y = 0; y < this.shape.layout.length; y++) {
				for (var x = 0; x < this.shape.layout[0].length; x++) {
					// 判断形状的某个位置上是否有方块
					if (this.shape.layout[y][x] > 0) {
						// 有方块就保存到list二位数组中,其值为方块的颜色值加1
						this.list[this.shape.currentY + y][this.shape.currentX + x] = this.shape.color + 1;
					}
				}
			}
		},
		// 绘制已存在的方块的方法
		drawList: function() {
			for (var y = 0; y < row; y++) {
				for (var x = 0; x < col; x++) {
					// 判断list中该位置上是否存在方块
					if (this.list[y][x] > 0) {
						this.ctx.drawImage(this.shape.block.image, (this.list[y][x] - 1) * 32, 0, 32, 32, x * 32, y * 32, 32, 32);
					}
				}
			}
		},
		// 定义画网格线条的方法
		drawGridLine: function() {
			// 循环绘制横线
			for (var i = 0; i < row; i++) {
				this.ctx.strokeStyle = "#ffffff";
				this.ctx.beginPath();
				this.ctx.moveTo(0, i * 32);
				this.ctx.lineTo(320, i * 32);
				this.ctx.closePath();
				this.ctx.stroke();
			}
			// 循环绘制竖线
			for (var i = 0; i < col; i++) {
				this.ctx.strokeStyle = "#ffffff";
				this.ctx.beginPath();
				this.ctx.moveTo(i * 32, 0);
				this.ctx.lineTo(i * 32, 640);
				this.ctx.closePath();
				this.ctx.stroke();
			}
		},
		// 定义方块自动下落的方法
		tick: function() {
			if (this.validMove(0, 1)) {
				// 方块的Y坐标自动增加1
				this.shape.currentY++;
				this.refresh();
			} else {
				this.addShapeToList();
				// 添加形状之后,调用消除方块的方法
				this.clearLineBlock();
				window.Tetris.score.drawScore();

				// 表示方块下落到最下面
				this.shape = this.nextShape;
				// 重新随机产生方块
				this.nextShape = new Shape();
				this.nextShape.init();
				window.Tetris.nextShape.drawNextShape(this.nextShape);
				
				this.refresh();
			}
		},
		// 定义刷新画布的方法
		refresh: function() {
			// 清除画布
			this.ctx.clearRect(0, 0, 32*col, 32*row);
			this.drawGridLine();
			this.drawList();
			this.shape.drawShape(this.ctx);
		},
		// 碰撞检测的方法	
		// x 表示方块在横向上的移动		
		// y 表示方块在纵向上的移动
		validMove: function(x, y) {
			// 方块下一个位子的横坐标
			var offsetX = this.shape.currentX + x;
			// 方块下一个位子的纵坐标
			var offsetY = this.shape.currentY + y;
			// 判断方块是否掉出画布
			if (offsetY + this.shape.layout.length > row) {
				// 返回 false 表示无效的移动
				return false;
			}
			// 左右边界的碰撞检测
			if (offsetX < 0 || offsetX + this.shape.layout[0].length > col) {
				return false;
			}
			// 方块与方块之间的碰撞检测
			for (var y = 0; y < this.shape.layout.length; y++) {
				for (var x = 0; x < this.shape.layout[0].length; x++) {
					if (this.list[offsetY + y][offsetX + x] > 0 && this.shape.layout[y][x] > 0) {
						if(offsetY == 1){
							clearInterval(window.Tetris.timer);
							alert("游戏结束");
						}
						return false;
					}
				}
			}

			return true;
		},
		// 消除一行或多行的方块
		clearLineBlock: function() {
			// 循环遍历 list数组
			for (var y = row - 1; y > 0; y--) {
				//	假设该行全部有方块,可以消除
				var flag = true;
				for (var x = 0; x < col; x++) {
					// 如果该行元素存在空的,则假设不成立
					if (this.list[y][x] == 0) {
						flag = false;
					}
				}
				// 如果标记为true,说明该行可以消除
				if (flag) {
					for (var i = y; i > 0; i--) {
						for (var j = 0; j < col; j++) {
							// 消除一行方块,把上一行的数据往下挪
							this.list[i][j] = this.list[i - 1][j];
						}
					}
					// 因为数据往下挪,所以该行还得遍历
					score += 100;
					y++;
				}

			}
		}
	}

	// 定义形状类
	function Shape() {
		// 创建方块对象
		this.block = new Block();
		// 存放形状的矩阵
		this.layout;
		// 形状的颜色
		this.color;
		// 当前X坐标
		this.currentX;
		// 当前Y坐标
		this.currentY;
	}
	Shape.prototype = {
		init: function() {
			// 初始化矩阵	
			this.layout = layouts[Math.floor(Math.random() * 7)];
			// 初始化颜色
			this.color = Math.floor(Math.random() * 7);
			// 初始化横纵坐标
			this.currentX = Math.floor((col - this.layout[0].length) / 2);
			this.currentY = 0;
		},
		// 绘制形状的方法
		drawShape: function(ctx) {
			// 	两层循环遍历二维数组	
			//	this.layout.length表示矩阵的高度		
			//	this.layout[0].length表示矩阵的宽度
			for (var y = 0; y < this.layout.length; y++) {
				for (var x = 0; x < this.layout[0].length; x++) {
					if (this.layout[y][x] > 0) {
						ctx.drawImage(this.block.image, this.color * 32, 0, 32, 32, (this.currentX + x) * 32, (this.currentY + y) * 32, 32, 32);
					}
				}
			}
		}
	}

	// 定义方块类
	function Block() {
		// 创建图片对象
		this.image = new Image();
		// 指定图片源
		this.image.src = "img/blocks.png";
//		// 绘制方块的方法
//		this.drawBlock = function(ctx) {
//			// 绘制图片的方法
//			/*	第一个参数:图片源
//			 * 	第二、三个参数:截取图片的起始点
//			 * 	第四、五个参数:截取图片的大小
//			 * 	第六、七个参数:绘制在canvas上的起始点
//			 * 	第八、九个参数:绘制在canvas上的大小
//			 */
//			ctx.drawImage(this.image, 32, 0, 32, 32, 64, 0, 32, 32);
//		}
	}

	// 键盘监听的类
	function KeyBoard() {
		var self = this;
		var keys = {
			37: "left",
			38: "top",
			39: "right",
			40: "bottom"
		}

		// 添加监听 事件的方法
		this.addEventHandlers = function() {
				// 添加键盘的监听事件
				document.addEventListener("keydown", this.keyPress, true);
			}
			//	监听键盘事件的方法
		this.keyPress = function(event) {
				// ASCII码
				//			alert(event.keyCode);
				// 判断按下的键是不是上下左右四个键
				if (keys[event.keyCode]) {
					self.keyPressEvent(keys[event.keyCode]);
				}
			}
			// 键盘按下之后的任务代码方法
		this.keyPressEvent = function(code) {
			switch (code) {
				// 方块向左移动
				case "left":
					if (this.board.validMove(-1, 0)) {
						this.board.shape.currentX--;
						this.board.refresh();
					}
					break;
				case "top":
					// 矩阵变形的操作
					var lay = [];
					for (var x = 0; x < this.board.shape.layout[0].length; x++) {
						lay[x] = [];
						for (var y = 0; y < this.board.shape.layout.length; y++) {
							lay[x][y] = this.board.shape.layout[this.board.shape.layout.length - y - 1][x];
						}
					}
					// 变形之后的偏移量
//					var offsetX = this.board.shape.currentX + lay[0].length;
//					var offsetY = this.board.shape.currentY + lay.length;
//					// 正确的坐标
//					var xZuoBiao = this.board.shape.currentX;
//					var yZuoBiao = this.board.shape.currentY;
//					
//					if (offsetX > col) {
//						xZuoBiao = col - lay[0].length;
//					}
//					if (offsetY > row) {
//						yZuoBiao = row - lay.length;
//					}
                    
                    if(lay[0].length + this.board.shape.currentX > col){
						return;
					}
                    
//					// 变形之后的矩阵和已存在的方块之间的碰撞检测
					for(var y=0;y<lay.length;y++){
						for(var x=0;x<lay[0].length;x++){
							if(this.board.list[this.board.shape.currentY+y][this.board.shape.currentX+x] >0 && lay[y][x] > 0){
								return;
							}
						}
					}
//					
//					this.board.shape.currentX = xZuoBiao;
//					this.board.shape.currentY = yZuoBiao;

					this.board.shape.layout = lay;
					this.board.refresh();
					break;
				case "right":
					if (this.board.validMove(1, 0)) {
						this.board.shape.currentX++;
						this.board.refresh();
					}
					break;
				case "bottom":
					if (this.board.validMove(0, 1)) {
						this.board.shape.currentY++;
						this.board.refresh();
					}
					break;
			}
		}
	}
	
	// 下一个方块提示的类
	function NextShape(){
		this.canvas = document.getElementById("nextShape");
		this.ctx = this.canvas.getContext("2d");
	}
	
	NextShape.prototype = {
		// 绘制提示的头部
		drawHeader:function(){
			this.ctx.fillStyle = "black";
			// 设置字体
			this.ctx.font = "26px April";
			// 设置文字对齐方式
			this.ctx.textAlign = "center";
			// 绘制文本,文本内容,x坐标,y坐标
			this.ctx.fillText("Next",100,40);
			// 绘制矩形
			this.ctx.fillRect(5,60,190,95);
			this.ctx.fill();
		},
		// 绘制提示的方块
		drawNextShape:function(shape){
			// 把显示形状的位置重新绘制成黑色
			this.ctx.fillStyle = "black";
			this.ctx.fillRect(5,60,190,95);
			this.ctx.fill();
			
			for(var y=0;y<shape.layout.length;y++){
				for(var x=0;x<shape.layout[0].length;x++){
					if(shape.layout[y][x] > 0){
						this.ctx.drawImage(shape.block.image,shape.color*32,0,32,32,40+x*32,80+y*32,32,32);
					}
				}
			}
		}
	}
	
	// 得分的类
	function Score(){
		this.canvas = document.getElementById("score");
		this.ctx = this.canvas.getContext("2d");
	}
	Score.prototype = {
		// 绘制提示的头部
		drawHeader:function(){
			this.ctx.fillStyle = "black";
			// 设置字体
			this.ctx.font = "26px April";
			// 设置文字对齐方式
			this.ctx.textAlign = "center";
			// 绘制文本,文本内容,x坐标,y坐标
			this.ctx.fillText("Score",100,40);
			// 绘制矩形
			this.ctx.fillRect(5,60,190,95);
			this.ctx.fill();
		},
		drawScore:function(){
			
			// 把显示形状的位置重新绘制成黑色
			this.ctx.fillStyle = "black";
			this.ctx.fillRect(5,60,190,95);
			
			this.ctx.fillStyle = "white";
			this.ctx.font = "26px April";
			this.ctx.textAlign = "center";
			this.ctx.fillText(score,100,100);
			
			this.ctx.fill();
			
		}
	}
	
	// 返回Tetris类的一个对象
	return new Tetris();
})();