JavaScript
运行JS
在HTML中使用<script>
标签
<script>
标签可以插在<head>
或者<body>
标签中,内部的内容就是js代码。
<script>
function myFunction()
{
document.getElementById("demo").innerHTML="我的第一个JavaScript函数";
}
</script>
外链引入
方式是使用<script>
标签的src
属性来引入外部的js文件
<head>
...
<script src="./4-1.js"></script>
...
</head>
对于较大的项目一般推荐使用引入外链的方式
了解JS输出内容的方式
alert()函数
调用alert()函数将会弹出一个窗口并将传入的参数打印出来。
<body>
<script>
alert("Hello World!!")
</script>
</body>
alert()
可以打印绝大多数的数据类型,包括数组和对象在内
console.log()函数
这个函数会把接受的变量以及详细的类型打印到浏览器的控制台中。打开页面后查看控制台,就可以看到结果了
<body>
<script>
var obj={
name: "mark",
sex: "male"
};
console.log(obj);
</script>
</body>
变量的定义与数据类型
- 没有类型,任何变量可存储任何类型的数据
- 无需提前声明就可以直接使用
语法规范
- 变量必须以字母开头或
$
或_
开头- 大小写敏感
当您向变量分配文本值时,应该用双引号或单引号包围这个值。
声明变量使用var关键字,可以储存任意类型的数据
var myInt=123;
var myDecimal=12.1;
var myString="Hello JS";
var myArray=[1,"Hello",12.3,{name:"lux"}];
var myObject={name:"kux",sex:"male",age:"18"}
var myFunction=function(){return "this is a function"}
变量可以随意转换类型,也可不声明直接用(不推荐)
(let
允许你声明一个作用域被限制在块级中的变量、语句或者表达式。在Function中局部变量推荐使用let
变量,避免变量名冲突。)
你应该特别留意数组和对象两种类型,它们的作用方式和静态语言存在很大的不同
strict模式
JavaScript在设计之初,为了方便初学者学习,并不强制要求用var
申明变量。这个设计错误带来了严重的后果:如果一个变量没有通过var
申明就被使用,那么该变量就自动被申明为全局变量
使用var申明的变量则不是全局变量,它的范围被限制在该变量被申明的函数体内(函数的概念将稍后讲解),同名变量在不同的函数体内互不冲突。
为了修补JavaScript这一严重设计缺陷,ECMA在后续规范中推出了strict模式,在strict模式下运行的JavaScript代码,强制通过var申明变量,未使用var申明变量就使用的,将导致运行错误。
启用strict模式的方法是在JavaScript代码的第一行写上:
'use strict';
几个特殊的变量
NaN
Nan
这个特殊的值与所有其他值都不相等,包括自己
唯一能判断NaN
的方法是通过isNaN()
函数
isNaN(NaN);//true
null和undefined
null
表示一个“空”值,与0
和''
不同,0
是一个数值,''
表示长度为0的字符串,而null表示“空”。
有一个和null
类似的undefined
,它表示“未定义”。
JavaScript的设计者希望用null
表示一个空的值,而undefined
表示值未定义。事实证明,这并没有什么卵用,区分两者的意义不大。大多数情况下,我们都应该用null
。undefined
仅仅在判断函数参数是否传递的情况下有用。
Object
JavaScript 对象是拥有属性和方法的数据。
对象也是一个变量,但对象可以包含多个值(多个变量)
定义一个对象
JavaScript用一个{...}
表示一个对象,键值对以xxx: xxx
形式申明,用,隔开。注意,最后一个键值对不需要在末尾加,
,如果加了,有的浏览器(如低版本的IE)将报错。
var car={type:"Fiat",model:500,color:"white"};
如果属性名包含特殊字符,就必须用”括起来:
var xiaohong={
name:'小红',
'middle-school':'No.1 Middle School'
};
xiaohong
的属性名middle-school
不是一个有效的变量,就需要用''
括起来。访问这个属性也无法使用.操作符,必须用['xxx']
来访问:
xiaohong['middle-school']; // 'No.1 Middle School'
xiaohong['name']; // '小红'
xiaohong.name; // '小红'
也可以用xiaohong['name']
来访问xiaohong
的name
属性,不过xiaohong.name
的写法更简洁。我们在编写JavaScript代码的时候,属性名尽量使用标准的变量名,这样就可以直接通过object.prop
的形式访问一个属性了。
实际上JavaScript对象的所有属性都是字符串,不过属性对应的值可以是任意数据类型。
如果访问一个不存在的属性会返回什么呢?JavaScript规定,访问不存在的属性不报错,而是返回
undefined
由于JavaScript的对象是动态类型,你可以自由地给一个对象添加或删除属性:
var xiaoming={
name:'小明'
}
xiaoming.age=18;//新增一个age属性
delete xiaoming.age;//删除age属性
delete xiaoming['name'];//删除name属性
delete xiaoming.school;//删除不存在的属性不会报错
如果我们要检测对象是否拥有某一属性,可以用in
操作符:
var xiaoming={
name:xiaoming
};
'name' in xiaoming;//true
'grade' in xiaoming;//false
小心,如果in
判断一个属性存在,这个属性不一定是xiaoming
的,它可能是xiaoming
继承得到的:
'toString' in xiaoming;//true
因为toString
定义在object
对象中,而所有对象最终都会在原型链上指向object
,所以xiaoming
也拥有toString
属性。
要判断一个属性是否是xiaoming
自身拥有的,而不是继承得到的,可以用hasOwnProperty()
方法:
var xiaoming={
name:'小明'
};
xiaoming.hasOwnProperty('name');//true
xiaoming.hasOwnProperty('toString');//false
总之,JavaScript 对象是属性变量的容器。
JavaScript 对象是键值对的容器
键值对通常写法为name : value
(键与值以冒号分割)。
键值对在 JavaScript 对象通常称为 对象属性。
对象方法
对象的方法定义了一个函数,并作为对象的属性存储
对象方法通过添加()
调用
name=person.fullName();//访问了 person 对象的 fullName() 方法
name=person.fullName;//访问 person 对象的 fullName 属性,它将作为一个定义函数的字符串返回
Date 日期对象
日期对象可以储存任意一个日期,并且可以精确到毫秒数。
定义一个时间对象 :
var Udate=new Date();
注意:使用关键字new
,Date()
的首字母必须大写。
使 Udate
成为日期对象,并且已有初始值:当前时间(当前电脑系统时间)。
如果要自定义初始值,可以用以下方法:
var d = new Date(2012, 10, 1); //2012年10月1日
var d = new Date('Oct 1, 2012'); //2012年10月1日
我们最好使用下面介绍的“方法”来严格定义时间。
访问方法语法:“<日期对象>.<方法>”
Date
对象中处理时间和日期的常用方法:
方法 | 功能 |
---|---|
get/setDate() | 返回/设置日期 |
get/setFullYear() | 返回/设置年份(4位数表示) |
get/setYear() | 返回/设置年份 |
get/setMonth() | 返回/设置月份 0:一月,1:二月…… |
get/setHours() | 返回/设置小时,24小时制 |
get/setMinutes() | 返回/设置分钟数 |
get/setSeconds() | 返回/设置秒钟 |
get/setTime() | 返回/设置时间(单位:毫秒) |
get/setDay() | 返回星期,返回的是0-6的数字,0 表示星期天。 |
Math对象
提供对数据的数学运算
<script type="text/javascript">
var mypi=Math.PI; //3.141592653589793
var myabs=Math.abs(-15);//15
document.write(mypi);
document.write(myabs);
</script>
注意:Math 对象是一个固有的对象,无需创建它,直接把 Math 作为对象使用就可以调用其所有属性和方法。这是它与Date,String对象的区别。
Math对象属性
属性 | 说明 |
---|---|
E | 自然对数底数 |
LN2 | 2的自然对数 |
LOG2E | 以2为底e的对数 |
PI | π |
SQRT1_2 | 2的平方根的倒数 |
SQRT2 | 2的平方根 |
Math对象方法
方法 | 说明 |
---|---|
ceil() | 向上取整 |
exp() | 返回e的指数 |
floor() | 向下取整 |
random() | 返回0~1之间的随机数 |
round() | 把数四舍五入为最接近的整数 |
toSource() | 返回该对象的源代码 |
valueOf() | 返回Math对象的原始值 |
Array
创建一个数组
- 常规方式
var mrCars=new Array();
myCars[0]="Saab";
myCars[1]="Volvo";
myCars[2]="BMW";
- 简洁方式
var myCars=new Array("Saab","Volvo","BMW");
- 字面
var myCars=["Saab","Volvo","BMW"];
所有的JavaScript变量都是对象。数组元素是对象。函数是对象。
因此,你可以在数组中有不同的变量类型。
你可以在一个数组中包含对象元素、函数、数组:
myArray[0]=Date.now;
myArray[1]=myFunction;
myArray[2]=myCars;
直接给Array
的length
赋一个新的值会导致Array
大小的变化:
var arr=[1,2,3];
arr.length;//3
arr.length=6;//arr变为[1,2,3,undefined,undefined,undefined]
arr.length=2;//arr变为[1,2]
如果通过索引赋值时,索引超过了范围,同样会引起Array
大小的变化:
var arr=[1,2,3];
arr[5]='x';//arr变为[1,2,3,undefined,undefined,'x'];
数组的方法和属性
属性/方法 | 说明 |
---|---|
length | 数组中元素的数量 |
indexOf() | 括号内对象的索引值 |
concat() | 合并数组 |
pop() | 删除数组的最后一个元素 |
push() | 数组的末尾添加新的元素 |
reverse() | 反转顺序 |
shift() | 删除数组第一个元素并返回删除的元素 |
slice(a,b) | 选择索引值为a~(b-1) 的元素 |
sort() | 排序 |
toString | 转换数组到字符串 |
unshift("a","b") | 向数组之前添加元素a ,b ,(不适用IE8之前的版本) |
slice()
截取Array
的部分元素,然后返回一个新的Array
var arr = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
arr.slice(0, 3); // 从索引0开始,到索引3结束,但不包括索引3: ['A', 'B', 'C']
arr.slice(3); // 从索引3开始到结束: ['D', 'E', 'F', 'G']
sort()
array.sort(方法函数);
- 如果不指定<方法函数>,则按unicode码顺序排列。
- 如果指定<方法函数>,则按<方法函数>所指定的排序方法排序。
注意: 该函数要比较两个值,然后返回一个用于说明这两个值的相对顺序的数字。比较函数应该具有两个参数 a 和 b,其返回值如下:
若返回值<=-1,则表示 A 在排序后的序列中出现在 B 之前。
若返回值>-1 && <1,则表示 A 和 B 具有相同的排序顺序。
若返回值>=1,则表示 A 在排序后的序列中出现在 B 之后。
排序函数栗子如下
<script type="text/javascript">
function sortNum(a,b){
return a-b;//升序;降序为b-a
}
</script>
字符串
字符串不可变,如果对字符串的某个索引赋值,不会有任何错误,但是,也没有任何效果
多行字符串
用反引号`表示
`这是
一个多行
字符串`
模板字符串
如果有很多变量需要连接,用+
号就比较麻烦。ES6新增了一种模板字符串,表示方法和上面的多行字符串一样,但是它会自动替换字符串中的变量:
var name='小明';
var age=20;
var message='你好,${name},你今年${age}岁了!'
alert(message);
字符串常用方法
toUpperCase()
把字符串变成大写
var s='Hello';
s.toUpperCase();
toLowerCase
把字符串变成小写
(同toUpperCase
)
charAt(index)
charAt()
方法可返回指定位置的字符。返回的字符是长度为 1 的字符串。
indexOf(substring,startpos)
搜索指定字符串出现的位置
substring必要,startpos不必要
substring()
返回指定索引的字串
var s='hello world';
s.substring(0,5);//从索引0开始到5(不包括5)
s.substring(7);//从索引7开始到结束
substr()
从字符串中提取从 startPos
位置开始的指定数目的字符串。
stringObject.substr(startPos,length);
startPos,必需,提取字串的开始位置
length,可选,提取字符串的长度,若忽略,从startPos到结尾
注意:如果参数startPos是负数,从字符串的尾部开始算起的位置。也就是说,-1 指字符串中最后一个字符,-2 指倒数第二个字符,以此类推。
如果startPos为负数且绝对值大于字符串长度,startPos为0。
split()
stringObject.split(separator,limit);
separator
必需,从该参数指定的位置开始分隔字符串
limit
可选,分隔的次数,返回的字串不会多于该参数限定的数组;若无参数则不限次数
注意:若把空字符用作separator
,则每个字符间都会被分割
如:
var mystr='www.baidu.com';
document.write(mystr.split('.',2)+'<br />');//www,baidu
document.write(mystr.split('.'));//www,baidu,com
Windows对象
方法 | 说明 |
---|---|
alert() | 警告框 |
prompt() | 可提示用户输入的对话框 |
confirm() | 确认框 |
open() | 打开新浏览器窗口或查找一个已命名的窗口 |
close() | 关闭浏览器窗口 |
print() | 打印当前窗口内容 |
focus() | 把键盘焦点给予一个窗口 |
… | … |
计时器方法
方法 | 说明 |
---|---|
setTimeout() | 指定的延迟时间后执行代码 |
clearTimeout() | 取消setTimeout()设置 |
setInterval() | 每隔指定时间执行代码 |
clearInterval() | 取消setInterval()设置 |
setInterval()
setInterval(代码,交互时间);
说明:交互时间以毫秒计算
返回值:可以传递给clearInterval()从而取消对“代码”周期性执行的值
//我们设置一个计时器,每隔100毫秒调用clock()函数,并将时间显示出来,代码如下:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>计时器</title>
<script type="text/javascript">
var int=setInterval(clock, 100)
function clock(){
var time=new Date();
document.getElementById("clock").value = time;
}
</script>
</head>
<body>
<form>
<input type="text" id="clock" size="50" />
</form>
</body>
</html>
setTimeout()
setTimeout()计时器,在载入后延迟指定时间后,去执行一次表达式,仅执行一次。
参数与setInterval()相同
History对象
history对象记录了用户曾经浏览过的页面(URL),并可以实现浏览器前进与后退相似导航的功能。
注意:从窗口被打开的那一刻开始记录,每个浏览器窗口、每个标签页乃至每个框架,都有自己的history对象与特定的window对象关联。
运算符
比较运算符
特别注意相等运算符
==
。JavaScript在设计时,有两种比较运算符:
第一种是==
比较,它会自动转换数据类型再比较,很多时候,会得到非常诡异的结果;
第二种是===
比较,它不会自动转换数据类型,如果数据类型不一致,返回false
,如果一致,再比较。
由于JavaScript这个设计缺陷,不要使用==
比较,始终坚持使用===
比较。
条件判断
JavaScript把null
、undefined
、0
、NaN
和空字符串''
视为false
,其他值一概视为true
循环
For/In循环
for/in
循环遍历对象的属性
var person={fname:"John",lname:"Doe",age:25};
for(x in person)
{
txt=txt+person[x];
}
由于Array
也是对象,而它的每个元素的索引被视为对象的属性,因此,for ... in
循环可以直接循环出Array
的索引:
var a=['A','B','C'];
for(var i in a){
console.log(i);//'0','1','2'
console.log(a[i]);'A','B','C'
}
注意,
for ... in
对Array
的循环得到的是String
而不是Number
。
Map和Set
JavaScript的默认对象表示方式{}可以视为其他语言中的Map
或Dictionary
的数据结构,即一组键值对。
但是JavaScript的对象有个小问题,就是键必须是字符串。但实际上Number
或者其他数据类型作为键也是非常合理的。
为了解决这个问题,最新的ES6规范引入了新的数据类型Map
。
Map
Map
是一组键值对的结构,具有极快的查找速度。
举个例子,假设要根据同学的名字查找对应的成绩,如果用Array
实现,需要两个Array
:
var name=['M','B','T'];
var score=[95,75,89];
给定一个名字,要查找对应的成绩,就先要在names
中找到对应的位置,再从scores
取出对应的成绩,Array
越长,耗时越长。
如果用Map
实现,只需要一个“名字”-“成绩”的对照表,直接根据名字查找成绩,无论这个表有多大,查找速度都不会变慢。用JavaScript写一个Map
如下:
var m=new Map([['M',90],['B',80],['T',70]]);
m.get('M');//90
初始化Map
需要一个二维数组,或者直接初始化一个空Map
。
Map
具有以下方法:
var m=new Map();
m.set('A',90);//添加新的key-value
m.has('A');//是否存在key:'A'? true
m.get('A');//90
m.delete('A');
m.get('A');//undefined
由于一个key
只能对应一个value
,所以,多次对一个key
放入value
,后面的值会把前面的值覆盖掉
Set
Set
和Map
类似,也是一组key
的集合,但不存储value
。由于key
不能重复,所以,在Set
中,没有重复的key
。
要创建一个Set
,需要提供一个Array
作为输入,或者直接创建一个空Set
var s1=new Set();
var s2=new Set([1,2,3]);
重复元素在Set
中自动被过滤
通过add(key)
方法可以添加元素到Set
中,通过delete(key)
方法可以删除元素
Map和Set是ES6标准新增的数据类型,请根据浏览器的支持情况决定是否要使用。
iterable
遍历Array可以采用下标循环,遍历Map和Set就无法使用下标。为了统一集合类型,ES6标准引入了新的iterable类型,Array、Map和Set都属于iterable类型。
具有iterable类型的集合可以通过新的for … of循环来遍历。
for … of循环是ES6引入的新的语法。
用法如下:
var a=['A','B','C'];
var s=new Set(['A','B','C']);
var m=new Map([[1, 'x'], [2, 'y'], [3, 'z']]);
for(var x of a){
console.log(x);
}
for(var x of s){
console.log(x);
}
for(var x of m){
console.log(x[0]+'='+x[1]);
}
for … of循环和for … in循环的区别
for … in循环由于历史遗留问题,它遍历的实际上是对象的属性名称。一个Array数组实际上也是一个对象,它的每个元素的索引被视为一个属性。
当我们手动给Array对象添加了额外的属性后,for … in循环将带来意想不到的意外效果:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x in a) {
console.log(x); // '0', '1', '2', 'name'
}
for … in循环将把name包括在内,但Array的length属性却不包括在内。
for … of循环则完全修复了这些问题,它只循环集合本身的元素:
var a = ['A', 'B', 'C'];
a.name = 'Hello';
for (var x of a) {
console.log(x); // 'A', 'B', 'C'
}
这就是为什么要引入新的for … of循环。
然而,更好的方式是直接使用iterable内置的forEach方法,它接收一个函数,每次迭代就自动回调该函数。以Array为例:
var a=['A','B','C'];
a.forEach(function(element,indexmarrat)){
// element: 指向当前元素的值
// index: 指向当前索引
// array: 指向Array对象本身
console.log(element+',index='+index);
}
注意,forEach()方法是ES5.1标准引入的
Set与Array类似,但Set没有索引,因此回调函数的前两个参数都是元素本身
var s=Set(['a','b','c']);
s.forEach(function(element,sameElement,set)){
console.log(element);
}
Map的回调函数参数依次为value、key和map本身
var m=new Map([[1,'x'],[2,'y'],[3,'z']]);
m.forEach(function(value,key,map)){
console.log(value);
};
如果对某些参数不感兴趣,由于JavaScript的函数调用不要求参数必须一致,因此可以忽略它们。例如,只需要获得Array的element:
var a = ['A', 'B', 'C'];
a.forEach(function (element) {
console.log(element);
});
函数
JS是一门函数式编程的语言
特征:
1. 函数可以作变量
2. 函数可以作为另一个函数的参数或返回值
基本定义
函数一定要用function
关键字声明,另外由于变量没有类型,所以函数也不用指定参数的类型和返回值的类型
function 函数名(参数1,参数2,...){
函数代码
return 返回值
}
函数可以没有名称,这样的函数被称为匿名函数
,它可以保存到变量
如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined
由于JavaScript允许传入任意个参数而不影响调用,因此传入的参数比定义的参数多也没有问题,虽然函数内部并不需要这些参数
避免收到undefined,可以对参数进行检查:
function abs(x) {
if (typeof x !== 'number') {
throw 'Not a number';
}
if (x >= 0) {
return x;
} else {
return -x;
}
}
用变量储存函数
//用变量调用匿名函数
//addMe相当于函数指针,指向了这个匿名函数
var addMe=function(var1,var2){
return var1+var2;
};
var a=1,b=2;
console.log(addMe(a,b));//利用变量来调用,输出为3
将函数作为值传递
最常用的情景是把函数当做参数来传递,这样做可以极大的扩充函数的功能
//定义两个匿名函数
var sayHello=function(name){
console.log("hello,"+name);
}
var sayHi=function(name){
console.log("hi",+name);
}
var arr=["Mark","Ann","Ouxu","Molybdenum","Ruby"];
//一个用于对arr数组进行操作的函数,第一个参数是要操作的数组,第二个参数是需要对数组中的元素所应用的函数
function operateArr(func){
for(var i=0;i<5;++i){
func(arr[i]);//这里的func相当于函数模板
}
}
//传入不同的函数来执行
operateArr(sayHello);
operateArr(sayHi);
其中,sayHi和sayHello两个函数称为回调函数。
总之,函数可以说是编写js代码的最小结构块
arguments
JavaScript还有一个免费赠送的关键字arguments,它只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array:
function foo(x) {
console.log('x = ' + x); // 10
for (var i=0; i<arguments.length; i++) {
console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
}
}
foo(10, 20, 30);
实际上arguments最常用于判断传入参数的个数。你可能会看到这样的写法:
// foo(a[, b], c)
// 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
function foo(a, b, c) {
if (arguments.length === 2) {
// 实际拿到的参数是a和b,c为undefined
c = b; // 把b赋给c
b = null; // b变为默认值
}
// ...
}
要把中间的参数b变为“可选”参数,就只能通过arguments判断,然后重新调整参数并赋值。
rest参数
由于JavaScript函数允许接收任意个参数,于是我们就不得不用arguments来获取所有参数。
function foo(a, b) {
var i, rest = [];
if (arguments.length > 2) {
for (i = 2; i<arguments.length; i++) {
rest.push(arguments[i]);
}
}
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
为了获取除了已定义参数a、b之外的参数,我们不得不用arguments,并且循环要从索引2开始以便排除前两个参数,这种写法很别扭,只是为了获得额外的rest参数,有没有更好的方法?
ES6标准引入了rest参数,上面的函数可以改写为:
function foo(a, b, ...rest) {
console.log('a = ' + a);
console.log('b = ' + b);
console.log(rest);
}
foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]
foo(1);
// 结果:
// a = 1
// b = undefined
// Array []
rest参数只能写在最后,前面用…标识,从运行结果可知,传入的参数先绑定a、b,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。
如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。
rest参数是ES6新标准
小心!
JavaScript引擎有一个在行末自动添加分号的机制,所以正确的多行写法是
function foo(){
return{
name:'foo'
};
}
代码的执行
脚本语言和编译语言不同,不需要编译成可执行的二进制文件之后运行,它是解释运行的。
它工作的原理是由JS执行器读取JS文件后,一行一行代码的读取并执行,不会产生任何中间文件,程序运行的过程,就是由执行器读取代码文件的过程,脱离了执行器(也叫解释器或者代码引擎)代码就和纯文本没有任何区别了
一个典型的情况是,即便你的脚本中存在错误,只要执行的过程中没有执行到错误所在的地方,它都还能正常运行。
使用JS和用户交互
DOM节点
JS
是通过HTML
的DOM
模型来控制HTML
内容的,首先我们来了解一下什么是DOM
。
DOM
是Document Object Model
的缩写,也就是文档对象模型
。HTML
的DOM
就是整个页面元素的逻辑结构,包含了元素和元素之间的层级关系,你可以简单把它理解成一颗元素树。
所有的HTML
都可以整理成这样的一棵DOM
节点树。JS可以对DOM
节点进行各种操作:查找,获取,修改属性,内容,响应事件….
在JS中我们通常使用document
对象来获取整个页面的DOM
JS获取页面元素的手段
下面介绍的函数都是document
对象提供的方法,你可以像document.getElementById("main")
这样使用。
根据id查找
id
属性是一个元素的唯一标识符。
使用getElementById()
方法
可以用一个变量保存查找到的DOM
节点对象:
var x=document.getElementById("card1");//获取id为cad1的dom元素
根据类名(class)查找
使用getElementsByClassName()
方法,注意方法名中Element
为复数。因为同一class
可能有多个元素,该方法返回该class
所有元素的集合
注意:如果你是在
body
中书写js代码,一定要把这段代码放在你能获取的DOM
节点后面,否则由于页面的解析是从上到下的,在你执行代码时将无法得到想要的DOM
节点。
根据标签名查找
使用getElementsByTagName()
方法,该方法返回的同样是集合,由于同名标签在整个页面中非常多,所以这个方法经常用于嵌套取出某个DOM
节点内的指定标签
var x=document.getElementById("card1");//x是card1
var y=x.getElementsByTagName("p");//y是card1里的p标签
操作DOM
改变HTML内容
可以使用document.write()
直接在script
标签,也就是代码执行的位置直接写入内容
<body>
<div>
<script>
document.write("<p>这是一段由JS创建的文字</p>")
</script>
</div>
</body>
更为常见的做法是,通过上面所述的方法获取DOM
节点后,使用innerHTML
属性来访问和修改对应节点的内容
<body>
<h1 id="header">这是老标题内容...</h1>
<script>
var header =document.getElementById("header");
header.innerHTML = "这是新标题内容..."; // 修改h1标签里的文字
</script>
</body>
改变元素的样式
可以使用DOM
对象的style
属性来访问和修改对应元素的样式,你可以发现js中DOM
对象的属性和对应html
的元素的属性存在着对应的关系
<body>
<p id="para1" style="color:red">其实我是蓝色文字</p>
<p id="para2" style="font-size:2px">我的字很大</p>
<script>
document.getElementById("para1").style.color = 'blue';
document.getElementById("para2").style.fontSize = '30px';
</script>
</body>
事件和回调函数
事件编程
事件就是在操作页面过程可能发生的诸多动作,比如:点击一个按钮,拖动一个元素,将光标移动到某个元素上…你可以把这些事件理解成开关或者触发器,我们一般会绑定函数到某个事件上,当事件被触发的时候,该函数就会被自动调用,我们也把这种函数成为事件的回调函数。
例子:通过点击一个按钮来弹出一个警告框
<body>
<script>
function alertSth(){
alert("你点我干啥");
} // 定义回调函数
</script>
<button onclick="alertSth()">点我试试</button>
<!--通过onclick属性把alertSth()函数绑定到该按钮的点击事件上-->
</body>
事件例子:
1. 当用户点击鼠标时
2. 当网页已加载时
3. 当图像已加载时
4. 当鼠标移动到元素上时
5. 当输入字段被改变时
6. 当提交 HTML 表单时
7. 当用户触发按键时
HTML事件属性
<button onclick="displayDate()">Click here!</button>//向 button 元素分配 onclick 事件,名为 displayDate 的函数将在按钮被点击时执行。
使用HTML DOM来分配事件
<script>
document.getElementById("myBtn").onclick=function(){displayDate()};//向 button 元素分配 onclick 事件,名为 displayDate 的函数被分配给 id="myBtn" 的 HTML 元素。按钮点击时Javascript函数将会被执行。
</script>
onload 和 onunload 事件
onload
和 onunload
事件会在用户进入或离开页面时被触发。
onload
事件可用于检测访问者的浏览器类型和浏览器版本,并基于这些信息来加载网页的正确版本。
onload
和 onunload
事件可用于处理 cookie
。
<body onload="checkCookies()">
<script>
function checkCookies(){
if (navigator.cookieEnabled==true){
alert("Cookies 可用")
}
else{
alert("Cookies 不可用")
}
}
</script>
<p>弹窗-提示浏览器 cookie 是否可用。</p>
</body>
onchange事件
onchange
事件常结合对输入字段的验证来使用。
如下,当用户改变输入字段的内容时,会调用 upperCase()
函数
<head>
<script>
function myFunc(){
var x=document.getElementById("t");
x.value=x.value.toUpperCase();
}
</script>
</head>
<body>
<input type="text" id="t" onchange="myFunc()" />//当你离开输入框后,函数将被触发,将小写字母转为大写字母。
</body>
onmouseover 和 onmouseout 事件
onmouseover
和 onmouseout
事件可用于在用户的鼠标移至 HTML 元素上方或移出元素时触发函数。
<head>
<script>
function mOver(obj){
obj.innerHTML="Thank you!";
}
function mOut(obj){
obj.innerHTML="Mouse over me";
}
</script>
</head>
<body>
<div onmouseover="mOver(this)" onmouseout="mOut(this)" style="background-color:#d94a38;width:120px;height:20px;padding:40px;">Mouse over me</div>
</body>
onmousedown、onmouseup 以及 onclick 事件
onmousedown
, onmouseup
以及onclick
构成了鼠标点击事件的所有部分。首先当点击鼠标按钮时,会触发 onmousedown
事件,当释放鼠标按钮时,会触发 onmouseup
事件,最后,当完成鼠标点击时,会触发 onclick
事件。
<head>
<script>
function OMD(obj){
obj.innerHTML="Release me";
}
function OMU(obj){
obj.innerHTML="Click me";
}
</script>
</head>
<body>
<div id="d" onmousedown="OMD(this)" onmouseup="OMU(this)" style="background-color:#d94a38;width:120px;height:20px;padding:40px;">Oops</div>
</body>
DOM节点属性
getElementsByTagName()
返回带有指定标签名的节点对象的集合(数组)。返回元素的顺序是它们在文档中的顺序。
getElementsByName()
Name 是他的名字,可以重复。所以通过getElementsByName获取名字相同的人集合(数组)。
getAttribute()
通过元素节点的属性名称获取属性的值。
var node=document.getElementById("idName");
setAttribute()
var node=document.getElementById("idName");
node.setAttribute("属性",值);
DOM节点属性
DOM节点有三个属性
1. nodeName: 节点名称
2. nodeValue: 节点的值
3. nodeType: 节点类型
nodeName属性
节点的名称,只读
1. 元素节点的nodeName属性与标签名相同
2. 属性节点的nodeName是属性的名称
3. 文本节点的nodeName永远是#text
4. 文档节点的nodeName永远是#document
nodeValue属性
节点的值
1. 元素节点的nodeValue是undefined或null
2. 文本节点的nodeValue是文本自身
3. 属性节点的nodeValue是属性的值
nodeType属性
节点属性,只读。
常用节点类型
元素类型 | 节点类型 |
---|---|
元素 | 1 |
属性 | 2 |
文本 | 3 |
注释 | 8 |
文档 | 9 |
访问子节点childNodes
访问选定元素节点下的所有子节点的列表,返回的值可以看作是一个数组,他具有length属性。
注意:如果选定的节点没有子节点,则该属性返回不包含节点的 NodeList。
var nodes=node.childNodes;
访问子节点的第一项firstChild
返回childNodes数组的第一个子节点
访问子节点的最后一项lastChild
返回childNodes数组的最后一个节点
插入节点appendChild()
在指定节点的最后一个子节点列表之后添加一个新的子节点。
<body>
<ul id="test">
<li>JavaScript</li>
<li>HTML</li>
</ul>
<script type="text/javascript">
var otest = document.getElementById("test");
var child=document.createElement("li");
child.innerHTML="PHP";
otest.appendChild(child);
</script>
</body>
插入节点insertBefore()
parentNode.insertBefore(newnode,node);
删除节点removeChild()
removeChild() 方法从子节点列表中删除某个节点。如删除成功,此方法可返回被删除的节点,如失败,则返回 NULL。
parentNode.removeChild(node)
replaceChild()
replaceChild 实现子节点(对象)的替换。返回被替换对象的引用。
parentNode.replace(newnode,oldnode);