JavaScript
1. JavaScript概述
1.1 历史
JavaScript是世界上最流行的脚本语言。1994年,网景公司(Netscape)发布了Navigator浏览器0.9版。这是历史上第一个比较成熟的网络浏览器,轰动一时。但是,这个版本的浏览器只能用来浏览,不具备与访问者互动的能力。网景公司急需一种网页脚本语言,使得浏览器可以与网页互动。网景公司的整个管理层,都是Java语言的信徒,Sun公司完全介入网页脚本语言的决策。因此,Javascript后来就是网景和Sun两家公司一起携手推向市场的,这种语言被命名为"Java+script"并不是偶然的。
此时,34岁的系统程序员Brendan Eich登场了。仅仅一个月之后,1995年5月,网景公司做出决策,未来的网页脚本语言必须"看上去与Java足够相似",但是比Java简单,使得非专业的网页作者也能很快上手。Brendan Eich被指定为这种"简化版Java语言"的设计师。但是,他对Java一点兴趣也没有。为了应付公司安排的任务,他只用10天时间就把Javascript设计出来了。
ECMAScript是一种由Ecma国际(前身为欧洲计算机制造商协会,European Computer Manufacturers Association)通过ECMA-262标准化的脚本程序设计语言。这种语言在万维网上应用广泛,它往往被称为JavaScript,所以它可以理解为是JavaScript的一个标准,但实际上后两者是ECMA-262标准的实现和扩展。目前主流版本为ES6。
1.2 JavaScript组成
- 核心语法(ECMAscript)
- 文档对象模型 (DOM Docuemtn Object Model) ,JS与HTML文档交互。
- 浏览器对象模型(BOM Browser Object Model),JS与游览器交互。
1.3 JavaScript特征
JavaScript是一种解释型脚本语言,或者动态语言。是一种弱类型语言,意味着里面的类型可以变化。
-
编译型语言,需要经历编写-编译-链接-运行。比如java、c++等。
-
解释型语言,解释型语言没有编译结果
2. JavaScript基础语法
2.1 JS的引入
HTML中有3种方式写入JS代码。
-
写在标签属性
<a href="#" onclick="alert('hello world')">点击我</a>
-
写在script标签中
<script type="text/javascript"> alert("hello world..."); </script>
-
写在外部的JS文件中
js/hello.js
alert("hello world...");
index.html
<!-- 注意:即使标签中没有内容也不能写成自闭合的 --> <script src="js/hello.js" type="text/javascript"></script>
2.2 注释
JS中的注释同Java。
- // 单行注释
- /* */ 多行注释
- /** */ 多行注释
2.3 变量
变量是用来存储数据的,操作变量来间接操作内存中空间的数据。由于JS是弱类型语言,变量类型是动态的,故定义的时候不需要定义变量类型,使用var即可。
-
变量命名规范:
- 不允许使用js关键字和保留关键字
- 可以包含字母、数字、下划线_以及$
- 变量名不能以数字开头
- 可以用中文,但是不推荐使用
- 见名知意(驼峰)
-
变量的声明提前
所有变量的声明,会自动提升到代码(当前作用域)的最顶部。声明提前破坏了程序的执行顺序,所以大家知道原理即可,切勿在实际开发过程中使用,不仅会降低代码可读性,还容易造成程序错误。
1 console.log(a); //undefined 2 var a; // 这行代码相当于插入到最开始 3 a=10; 4 console.log(a
2.4 调试
- alert将数据弹出
- document.write();在文档内输出
- console.log在游览器的控制中输出
- 在游览器的开发控制台的Sources面板中断点调试
2.5 流程控制
条件分支跟循环参考Java,此处省略。
2.6 关键字跟保留字
JS中我们在命名规范中不能使用系统的关键字跟保留字。
-
关键字
-
保留字
3. 数据类型
变量没有类型,但是值有类型,可以通过typeof
运算符检查值类型。
var i = 1 ;
console.log(typeof i );
-
原始类型(基本类型):按值访问,可以操作保存在变量中实际的值。原始类型汇总中null和undefined比较特殊,5种。
-
引用类型:引用类型的值是保存在内存中的对象。
3.1 基本数据类型
3.1.1 number
数字类型,既可以表示整数,也可以表示小数。
123 //整数
123.1 //小数
1.1e3 // 科学计数法
-9 // 负数
NaN // not a number
Infinity // 无穷大
-Infinity // 负无穷大
0x11a // 16进制
0755 // 8进制
0b10101 // 2进制
- NaN不等于任何值,包括它自身。所以只能通过全局函数
isNaN()
来判断。 - Infinity比任何数字都要大。
- -Infinity比任何数字都要小。
3.1.2 string
-
字符串表示一段文本符号数据。由字符、数字、符号、特殊字符等组成。JS中的字符串可以用单引号也可以使用双引号。
"hello" 'hello \n world'
-
字符串模板:模板字符串是ES6增加的用于定于字符串的新特性,支持字符串直接换行而不需要转义,且支持插值
${}
var name = "seven"; var msg = ` 你好, ${name} `;
3.1.3 boolean
- 布尔类型,只有
true
跟false
2个值,表示结果是真还是假。 - boolean也可以进行算术运算,true当做1,false当做0。
3.1.4 undefined
表示未定义。
3.1.5 null
表示空,不存在。从逻辑角度上看,null是一个空的对象指针。而这也正是使用typeof操作符检测null值,会返回“object”的原因。
3.2 引用数据类型
也就是对象类型Object type,比如:Object 、Array 、Function 、Data等,以及自定义的。
object
对象,是一组数据和功能(函数)的集合。可以用new操作符后跟要创建的对象类型的名称来创建。也可以用字面量表示法创建。
var person = {name:'zhangsan'} // 方式1: 字面量的方式
var obj1= new Object(); // 方式2: 构造方法
4. 运算符
算术运算符
+
-
*
/
%
++
--``**
-
+
用在字符串上表示字符串的拼接。 -
可以通过()改变运算的优先级。
-
浮点数也有小尾巴的问题(0.1 + 0.2 ),尽量避免。可以使用number的toFixedf方法来四舍五入。
-
++
--
只能作用在变量上,不能作用在值上面。 -
/
除数为0,结果是无穷console.log(-1/0); // -Infinity console.log(1/0); // Infinity console.log(0/0) // NaN console.log(isNaN(0/0)) // true
-
**
表示计算幂,优先级比较高console.log(3**4); // 81 console.log(-3**3); // 报错 console.log((-3)**3); // -27 console.log(-(3**3)); // -27
比较运算符
比较运算符的结果是一个boolean类型。
>
<
>=
<=
用法同JAVA
-
==
等于,js中
==
只判断2个值是否相等,不考虑类型。"1" == 1 // true 1 == true // true 0 == false // true null == undefined // true NaN == NaN // false
-
===
绝对等于,js中用来判断值跟类型都必须相同。
"1" === 1 // false "1" === "1" // true NaN === NaN // false
逻辑运算符
逻辑运算符同java中逻辑运算符,也具有短路功能。结果是一个boolean类型。
&& 2个都为真则为真
|| 有一个为真则为真
! 真即假,假即真
5. 函数
JS中通过函数来把一段逻辑封装用来重复使用。函数式通过关键字function
来定义的。
- JS中的函数不需要定义返回类型,直接返回结果即可
- JS中的函数参数列表不需要定义类型以及var,只需定义变量名
- 函数需要调用才会执行,不调用是不会执行的
- 函数没有重载,只要方法名相同就会去执行,不管参数列表匹配与否
- 如果定义了多个方法名相同,后面覆盖前面的
5.1 函数的定义
定义方式一
/* 语法
function 函数名(参数列表){
函数体;
}*/
function study(){
console.log("好好学习,天天向上。");
}
定义方式二
/* 语法
var 函数名 = function(参数列表){
函数体;
}*/
var study = function(){
console.log("好好学习,天天向上。");
}
定义方式三(不推荐)
/*
语法:参数跟函数体都必须在字符串内,Function的F必须大写
new Function(arg1, arg2, ..., argN, function_body);
*/
var study = new Function("name", "time","console.log(name+'每天学习'+time+'分钟');console.log('继续保持')");
5.2 函数的调用
函数的调用(方式一)
/*
语法: 函数名(参数值)
*/
study("seven",180);
函数的调用(方式二)
/*
语法: 函数名.call(调用对象,参数值)
*/
study.call(this,"seven",180 );
函数的调用(方式三)
/*
参数需要封装到数组中
语法: 函数名.apply(调用对象,参数值数组)
*/
study.apply(this,['seven',120] );
函数的调用(方式四)
/*
bind会返回新的函数,需要调用才会执行,所以后面需要(),其它跟call用法一样。
语法: 函数名.bind(调用对象,参数值)()
*/
study.bind(this,"seven",180 )();
5.3 函数参数
JS中的参数都会封装到arguments
中,在函数体中可以通过这个参数拿到定义参数以外的参数值。
var study = function(name , time){
// 传统方式只能拿到定义的参数
console.log(name);
console.log(time);
// 通过arguments可以定义参数以外的参数
console.log(arguments.length);
console.log(arguments[0]);
console.log(arguments[1]);
console.log(arguments[2]);
console.log(arguments[3]);
console.log(name+'每天学习'+time+'分钟');
}
study("zhangsan",180,1,"a");
ES6也支持类似Java中的可变长度参数
var study = function(name , time , ... args){
console.log(args);
}
6. 数组
用来装元素的集合。
- JS中的数组中的类型可以不一样。
- JS中数组下标越界不会异常,访问会返回 undefined
数组的定义
// 方式1
var arr1 = [1,2,3,true,2.1,'hello',null ];
// 方式2
var arr2 = new Array(1,2,3,true,2.1,'hello',null);
console.log(arr1[100]);// undefined
7. 对象
JS中的对象分为3类:
- 内置对象(Array、Boolean、Date、Function、Global、Math、Number、Object、RegExp、Error、 String )
- 宿主对象(BOM/DOM)
- 自定义对象
内置对象
-
String
var s = "hello js world ..."; console.log(s.length);// length属性表示字符串长度 console.log(s[1]);// 可以通过具体的下标访问数组中的字符 s.toUpperCase();// 转换成大写 s.toLowerCase();// 转换成小写 s.indexOf('e'); // 获取字符e出现的位置 s.substring(3,5); // 获取子字符串
-
Array
var arr = [1,2,3,4,5]; console.log(arr.length);// length属性表示数组元素个数 arr.length = 2 ; // 设置长度减小,表示只保留前面的2个元素,剩余的丢掉 arr.length = 10 ;// 会增加5个元素,增加的都是undefined值 arr.indexOf(3);//返回元素3的索引,如果没有返回-1 arr.slice(3,6);// 截取子数组,类似String的subString arr.push("a","b","c") // 往数组尾部添加元素 arr.pop(); // 把数组的尾部最后一个元素弹出,也就是删除 arr.unshift("f"); // 往数组头部添加元素 arr.shift(); // 把数组的头部第一个元素弹出,也就是删除 arr.sort(); // 把数组进行排序 arr.reverse(); // 把数组元素进行反转 arr.concat(['a','b','c']); // 把新的数组拼接在元素后,会返回新的数组,并没改变原数组 arr.join("-");// 把数组中的所有元素拼接在一起,使用设置的分隔符。 // 数组的遍历 arr.forEach(function(value){ console.log(value); }); // 数组的遍历,这里的index是数组中的索引 for(var index in arr){ console.log( arr[index]); } // 数组的遍历,这里的e是数组中的元素 for(var e of arr){ console.log( e); }
-
Date
var d = new Date();// 定义日期类型 console.log(d);// 打印当前日期 console.log(d.getFullYear());// 获取年份 console.log(d.getMonth());// 获取月份 console.log(d.getDate());// 获取日 console.log(d.getDay());// 获取星期几 console.log(d.getHours());// 获取小时 console.log(d.getMinutes());// 获取分 console.log(d.getSeconds());// 获取秒 console.log(d.getTime());// 获取时间戳 console.log(d.toLocaleString());// 获取本地日期 console.log(d.toLocaleDateString());// 获取本地日期,只有年月日
-
JSON
JSON(JavaScript Object Notation)(http://www.json.org/) 是一种轻量级的数据交换格式。 JSON中支持2种数据格式:对象跟数组2种数据。具体支持的值类型有数字、字符串、boolean、null
-
对象用花括号表示{}
-
数组用中括号表示[]
-
数据表现为键值对用:隔开
-
同级数据用,号隔开
// json对象 { "name":"seven","age":"18"} // json数组,数组里面的元素是对象 [ {“name”:"张三","age":"21"}, {“name”:"李四","age":"22"} ]
JSON跟JS对象的区别
-
区别 | JSON | Javascript |
---|---|---|
含义 | 仅仅是一种数据格式 | 表示类的实例 |
传输 | 可以跨平台数据传输,速度快 | 不能传输 |
表现 | 1.简直对方式,键必须加双引号 2.值不能是方法函数,不能是undefined/NaN | 1.键值对方式,键不加引号 2.值可以是函数、对象、字符串、数字、boolean 等 |
-
JS对象转JSON
var user = { name:"zhangsan", age:18, sex:"男" }; // js对象转JSON对象(JSON.stringify) var json = JSON.stringify(user); console.log(json); //{"name":"zhangsan","age":18,"sex":"男"}
-
JSON转JS对象
var user = JSON.parse('{"name":"zhangsan","age":18,"sex":"男"}'); console.log(user);
自定义对象
对象的定义
-
方式1(字面量)
// 大括号{}表示一个对象 var user = { name:"zhangsan", age:17, sleep:function(){ console.log("sleeping ... "); } };
-
方式2(Object)
var user = new Object(); user.name = "zhangsan"; user.age = 17 ; user.sleep = function(){ console.log("sleeping ... "); }
-
方式3(工厂模式)
function createUser(name,age){ var user = new Object(); user.name = name ; user.age = age ; user.sleep = function(){ console.log("sleeping ... "); }; return user; };
-
方式4(构造方法)
// 构造方法名首字母大写,用以区分其他普通函数 function User(name,age){ this.name = name; this.age = age ; this.sleep = function(){ console.log("sleeping ... "); }; } var u1 = new User("zhang",111);
-
方式5(Object.create)
// 类似java中的clone var user1 = {name:"zhangsan",age:18}; var user2 = Object.create(user1);
对象的使用
var person = {
name:"zhangsan",
age:19,
sex:"男",
sleep:function(){
console.log("早睡早起身体好。");
}
-
属性的访问跟赋值
person.name person["name"] person.name = "seven"; person["name"] = "seven"; person.height // 使用对象的一个不存在的属性不会报错,undefined
-
动态的删除属性
delete person.name ;// 动态的删除person对象的name属性
-
动态的添加属性
person.hello = "hello";// 直接给新的属性赋值即可 person.eat =function(){console.log("吃");} // 函数也一样。
-
判断属性是否在这个对象中
'name' in person // 判断name属性是否存在person对象或者父类对象中。 'sleep' in person // 判断sleep函数是否存在person对象或者父类对象中。 person.hasOwnProperty("name");// 判断name属性是否存在person对象中,不包括父类的 person.hasOwnProperty("sleep");// 判断sleep函数是否存在person对象中,不包括父类的
8. 原型与原型链
我们先通过构造函数创建一个对象
function Person() {
}
//Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person
var person = new Person();
person.name = 'seven';
console.log(person.name) // seven
JS在创建对象的时候都会创建对应类型的原型。
-
当我们给Person添加属性跟方法的时候,可以添加在对象中,也可以添加在原型中。区别是对象中的属性是独立的,原型中的属性是所有对象共享的。
-
当访问对象的属性跟方法时,先去对象中找,找不到再去原型中找。
function Person() { } // 虽然写在注释里,但是你要注意: // prototype是函数才会有的属性 Person.prototype.name = 'seven'; var person1 = new Person(); var person2 = new Person(); console.log(person1.name) // seven console.log(person2.name) // seven
-
每一个JS对象都有一个属性
__proto__
,这个属性会指向该对象的原型.
function Person() {
}
var person = new Person();
console.log(person.__proto__ === Person.prototype); // true
- 每个对象跟原型都有一个 constructor 属性指向关联的构造函数实例原型指向构造函数。
function Person() {
}
console.log(Person === Person.prototype.constructor); // true
- 原型也是一个特殊的对象,也有
__proto__
属性,默认指向Object.prototype
。
-
我们访问对象的属性跟方法先去对象中找,找不到就去对应的原型上找,原型找不到再去父原型上面找,直到顶级原型
Object.prototype
。JS中是通过原型链来达到继承的效果。function Person() { } var person = new Person(); Object.prototype.name = "seven"; console.log(person.name) // seven
9. BOM
浏览器对象模型 (Browser Object Model) 使 JavaScript 有能力与浏览器"对话"。
9.1 window
window 对象是BOM中所有对象的核心,除了是BOM中所有对象的父对象外,还包含一些窗口控制函数。
所有浏览器都支持 window 对象。它表示浏览器窗口。其它的BOM对象都是window对象的子对象。
全局变量是 window 对象的属性。
全局函数是 window 对象的方法。
// 定义的全局变量都默认是window属性
var a = "hello";
// 定义的全局函数都默认是window函数
function study(){
console.log("好好学习,天天向上。");
}
// window可省略
console.log(a); // hello
console.log(window.a);// hello
window.study();
-
窗口尺寸
-
innerHeight
:浏览器窗口的内部高度。 -
innerWidth
:浏览器窗口的内部宽度。 -
outerHeight
:浏览器窗口外部高度。 -
outerWidth
:浏览器窗口外部宽度。console.log(window.innerHeight); console.log(window.innerWidth); console.log(window.outerHeight); console.log(window.outerWidth);
-
-
系统对话框
-
alert()
确定提示框,只有一个确定按钮。 -
confirm()
:选择提示框,有确认跟取消按钮 -
prompt()
:输入提示框,可以输入值,有确认跟取消按钮。// 只有一个确定按钮 alert("我很帅"); // 有确认跟取消按钮 var result = confirm("我是不是很帅"); console.log(result); // true/false // 可以输入值,有确认跟取消按钮 var time = prompt("你今天学习了几个小时?",3);// 输入值默认初始值设置为3 console.log(time); // 输入的值,点击取消结果为null
-
-
定时器
window 对象包含 4 个定时器专用方法,说明如下表所示,使用它们可以实现代码定时执行,或者延迟执行,使用定时器可以设计演示动画。
方法 说明 setInterval() 按照执行的周期(单位为毫秒)调用函数或计算表达式 setTimeout() 在指定的毫秒数后调用函数或计算表达式 clearInterval() 取消由 setInterval() 方法生成的定时器 clearTimeout() 取消由 setTimeout() 方法生成的定时器 var i = 0 ; function printNowTime(){ i++; console.log(new Date().toLocaleString()); if(i>=3){ // 清除这个定时器 clearInterval(timer); } } // 每1000毫秒执行一次,一直执行 var timer = setInterval(printNowTime,1000);
var i = 0 ; function printNowTime(){ i++; console.log(new Date().toLocaleString()); // 递归,让一次性定时器一直执行. var timer = setTimeout(printNowTime,1000); if(i>=3){ // 清除这个定时器 clearTimeout(timer); } } printNowTime();
-
窗口移动
moveBy()
:可相对窗口的当前坐标把它移动指定的像素。moveTo()
:把窗口的左上角移动到一个指定的坐标。
由于安全性的考虑,Chrome等游览器把这个功能屏蔽了。
// 下面案例仅IE有效 // 每秒运行一次 window.onload = function () { timer = window.setInterval("jump()", 1000); } function jump () { // 把窗口大小改为200*200像素 window.resizeTo (200, 200); // 随机一个X轴跟Y轴坐标 x = Math.ceil (Math.random() * 1024); y = Math.ceil (Math.random() * 760); // 移动到这个位置 window.moveTo(x, y); }
-
打开窗口
使用 window 对象的 open() 方法可以打开一个新窗口。
window.open (URL, name, features, replace)
参数列表如下:
URL
:可选字符串,声明在新窗口中显示网页文档的 URL。如果省略,或者为空,则新窗口就不会显示任何文档。name
:可选字符串,声明新窗口的名称。features
:可选字符串,声明了新窗口要显示的标准浏览器的特征,具体说明如下表所示。如果省略该参数,新窗口将具有所有标准特征。replace
:可选的布尔值。规定了装载到窗口的 URL 是在窗口的浏览历史中创建一个新条目,还是替换浏览历史中的当前条目。
var features = "height=500, width=800, top=100, left=100, toolbar=no, menubar=no, scrollbars=no,resizable=no, location=no, status=no"; //设置新窗口的特性 var win = window.open("http://www.bailiban.com", "windowName", featrues); setTimeout (function () { //定时器 if (win.closed) { console.log("创建的窗口已经关闭。"); } else { win.close(); } }, 5000); //半秒钟之后关闭该窗口 //打开一个新的窗口 var win = window.open("http://www.bailiban.com"); setTimeout (function () { //定时器 win.close(); }, 5000); //半秒钟之后关闭该窗口
9.2 document
每个载入浏览器的 HTML 文档都会成为 Document 对象。Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。Document 对象是 Window 对象的一部分,可通过 window.document 属性对其进行访问。
-
对象属性
//document.cookie = "name='zhangsan'"; //设置或返回与当前文档有关的所有 cookie。 console.log(document.cookie); //返回当前文档的域名。 console.log(document.domain); //返回文档被最后修改的日期和时间。 console.log(document.lastModified); //返回载入当前文档的文档的 URL。 console.log(document.referrer); //返回当前文档的标题。 console.log(document.title); //返回当前文档的 URL。 console.log(document.URL);
-
文档写入
open()
打开一个流,以收集来自任何 document.write() 或 document.writeln() 方法的输出。write()
向文档写 HTML 表达式 或 JavaScript 代码。writeln()
等同于 write() 方法,不同的是在每个表达式之后写一个换行符。
<html> <head> <script> function docWrite(){ // 重写打开一个一个新的流 var newDoc=document.open(); var txt="Learning about the DOM is FUN!"; // 往新的流中写入内容 newDoc.writeln(txt); // 往新的流中写入内容 newDoc.write(txt); // 关闭流 newDoc.close(); } </script> </head> <body> <input type="button" value="Write to a new document" onclick="docWrite()"> </body> </html>
-
文档操作见DOM
9.3 location
window.location 对象用于获得当前页面的地址 (URL),并把浏览器重定向到新的页面。
这种方法既可以用于具有onclick事件的标签,也可以用于满足某些条件进行跳转,特点是方便且灵活。
-
对象属性
// http://127.0.0.1:8848/aaaa/b.html?name=zhangsan //设置或返回主机名和当前 URL 的端口号。 console.log(location.host); // 127.0.0.1:8848 //设置或返回当前 URL 的协议。 console.log(location.protocol);//http: //设置或返回当前 URL 的主机名。 console.log(location.hostname);//127.0.0.1 //设置或返回当前 URL 的端口号。 console.log(location.port);//8848 //设置或返回完整的 URL。 console.log(location.href);//http://127.0.0.1:8848/aaaa/b.html?name=zhangsan //设置或返回当前 URL 的路径部分。 console.log(location.pathname);///aaaa/b.html //设置或返回从问号 (?) 开始的 URL(查询部分)。 console.log(location.search);//?name=zhangsan //可以通过location.href来设置页面的跳转 location.href = "http://www.bailiban.com";
-
地址操作
location.assign("http://www.bailiban.com")
打开新的页面,会在History 对象中生成一个新的记录。location.replace("http://www.bailiban.com")
打开新的页面,不会在 History 对象中生成一个新的记录。location.reload()
刷新当前页面内容
10. DOM
浏览器对象模型 (Document Object Model) 使 JavaScript 有能力与当前文档对话。
任意的文档都可以绘制成树状结构,在DOM树上,每个元素都可与看做一个对象,每个对象都叫做一个节点(node)。docunment就是一个对象,这个对象指代的是这个文档。DOM 将文档解析为一个由节点和对象(包含属性和方法的对象)组成的结构集合。简言之,它会将web页面和脚本或程序语言连接起来。
节点类型主要分为4类(不考虑注释):
- document
- element
- attribute
- text
10.1 document节点
-
属性
-
nodeName
document的nodeName属性为#document。
-
nodeType
document的nodeName属性为9。
-
nodeValue
document的nodeValue属性为null。
-
-
方法
-
getElementById
返回带有指定 ID 的元素,结果为dom对象。
// 获取ID值为my_h1的元素,结果为dom对象 var h1 = document.getElementById("my_h1");
-
getElementsByTagName
返回带有指定标签名的所有元素。结果为dom对象数组。
// 返回所有标签名为tagname的元素结合。 document.getElementsByTagName("tagname");
-
getElementsByClassName
返回带有相同类名的所有元素。结果为dom对象数组。
// 返回所有class属性值为intro的元素结合。 document.getElementsByClassName("intro");
-
getElementsByName
可返回带有指定名称的对象的集合。结果为dom对象数组。
// 返回所有name属性为my_input的元素集合。 document.getElementsByName("my_input");
-
querySelector
可返回文档中匹配指定 CSS 选择器的一个元素。结果为第一个匹配的dom对象。
var h1 = document.querySelector("#my_h1");
-
querySelectorAll
可返回文档中匹配指定 CSS 选择器的所有元素的集合。
var li = document.querySelectorAll("li");
-
createElement
创建一个元素节点 。
-
createAttribute
创建一个属性节点。
-
createTextNode
创建一个文本节点。
// 通过document创建一个h1元素节点 var newH1 = document.createElement("h1"); // 通过document创建一个h1元素节点 var att1 = document.createAttribute("class"); att1.value = "my_class" ; // 通过document创建一个h1元素节点 var text2 = document.createTextNode("我们正在学习JS的DOM."); // 把属性节点设置到对应的元素节点上 newH1.setAttributeNode(att1); // 把文本节点设置到对应的元素节点上 newH1.appendChild(text2); // 将创建的h1加入到body中 document.body.appendChild(newH1);
-
10.2 element节点
-
方法
-
getElementsByTagName
返回带有指定标签名的所有元素。结果为dom对象数组。
var span = document.getElementById("span"); //通过元素标签span获取内部元素标签 var h1 = span.getElementsByTagName("h1"); console.log(h1[0].innerText);
-
appendChild
向元素添加新的子节点,作为最后一个子节点。
var newH1 = document.createElement("h1"); // 将创建的h1加入到body中 document.body.appendChild(newH1);
-
removeChild
从元素中移除子节点。
var span = document.getElementById("span"); var h1 = span.getElementsByTagName("h1")[0]; // 把第一个h1标签从span父容器中删除 span.removeChild(h1);
-
remove
直接把当前元素删除。
var h1 = document.getElementsByTagName("h1")[0]; // 把当前的h1元素直接删除 h1.remove();
-
replaceChild
用新节点替换某个子节点。
var span = document.getElementById("span"); var h1 = document.getElementsByTagName("h1")[0]; // 创建新的节点 var newNode = document.createTextNode("a"); newNode.innerText = "bailiban" ; // 用新的节点替换旧的节点 span.replaceChild(newNode,h1);
-
setAttribute / getAttribute
设置/获取元素的属性值。
var input = document.getElementById("userPassword"); // 设置输入框的type属性值为text input.setAttribute("type","text");
-
setAttributeNode / getAttributeNode
设置/返回指定的属性节点。
var span = document.getElementById("span"); // 通过document创建一个class属性节点 var att1 = document.createAttribute("class"); // 设置此属性节点的值为my_class att1.value = "my_class" ; // 将此属性节点设置到对应的元素上 span.setAttributeNode(att1); // 获取span的class属性节点,打印此属性值 console.log(span.getAttributeNode("class").value);
-
insertBefore
在指定的已有子节点之前插入新的子节点。新节点参数在前,已存在节点参数在后。
// 创建新的节点h2 var newNode = document.createElement("h2"); newNode.innerText = "bailiban"; // 获取已存在的id值为my_p的节点 var exsitNode = document.getElementById("my_p"); // 在body元素中,将新的节点插入到已存在的p之前。 document.body.insertBefore(newNode,exsitNode);
-
cloneNode
创建节点的拷贝,并返回该副本。参数为boolean类型,默认false,表示只克隆节点跟属性。true表示复制节点跟属性以及后代。
var exsitNode = document.getElementsByTagName("h1")[0]; //将已存在的h1标签进行克隆,后代也一起克隆过来 var newNode = exsitNode.cloneNode(true); // 将克隆的新的节点插入到body中。 document.body.insertBefore(newNode,exsitNode);
-
-
属性
-
nodeName
element的nodeName属性为标签名。
-
nodeType
element的nodeName属性为1。
-
nodeValue
element的nodeValue属性为null。
-
innerText
设置或返回元素的内部文本。
var h1 = document.getElementsByTagName("h1")[0]; // 设置h1标签的内部文本 h1.innerText = "bailiban"; // 获取h1标签的内部文本 console.log(h1.innerText);
-
innerHTML
设置或返回元素的内部HTML。
var h1 = document.getElementsByTagName("h1")[0]; // 设置h1标签的内部html,html标签可以得到正确解析 h1.innerHTML = "<em>bailiban</em>"; // 获取h1标签的内部html console.log(h1.innerHTML);
-
outerHTML
设置或返回元素的外部HTML。
var h1 = document.getElementsByTagName("h1")[0]; // 获取h1标签的外部html console.log(h1.innerHTML); // 设置h1标签的外部html,html标签可以得到正确解析 h1.outerHTML = "<em>bailiban</em>";
-
id / className / tagName
设置或返回元素的 id / class / 标签名。
var h1 = document.getElementsByTagName("h1")[0]; // 设置元素的id值 h1.id = "h1_id"; // 设置元素的class值 h1.className = "h1_class"; // 获取元素的id值 console.log(h1.id); // 获取元素的class值 console.log(h1.className); // 获取元素的标签值 console.log(h1.tagName);
-
offsetHeight / offsetWidth
返回元素的高度/宽度。
var h1 = document.getElementsByTagName("h1")[0]; console.log(h1.offsetHeight); console.log(h1.offsetWidth);
-
offsetLeft / offsetTop
返回元素的水平/垂直偏移位置。
var h1 = document.getElementsByTagName("h1")[0]; console.log(h1.offsetLeft ); console.log(h1.offsetTop);
<h1>bailiban</h1> <ul id="ul"> <li>苹果</li> <li>香蕉</li> <li>菠萝</li> <li>西瓜</li> </ul> <p>我们正在学习DOM。</p>
-
childNodes / children
返回节点的子节点集合,childNodes会把折叠的空白也算做一个子节点,而children不会。
var ul = document.getElementById("ul"); console.log(ul.childNodes[1].innerText);//苹果,因为前面的空白算第一个孩子 console.log(ul.children[1].innerText);// 香蕉,不考虑空白
-
firstChild / firstElementChild
返回元素的第一个子元素。firstChild计算空白,而firstElementChild不会。
var ul = document.getElementById("ul"); console.log(ul.firstChild.innerText);//undefined,第一个孩子是空白,没有innerText console.log(ul.firstElementChild.innerText);//苹果,不考虑空白
-
lastChild / lastElementChild
返回元素的最后一个子元素。lastChild 计算空白,而lastElementChild不会。
var ul = document.getElementById("ul"); console.log(ul.lastChild.innerText);//undefined,最后一个孩子是空白,没有innerText console.log(ul.lastElementChild.innerText);//西瓜,不考虑空白
-
nextSibling / nextElementSibling
返回位于相同节点树层级的下一个节点。nextSibling计算空白,而nextElementSibling不会。
var ul = document.getElementById("ul"); console.log(ul.nextSibling.innerText);//undefined,下个节点是空白,没有innerText console.log(ul.nextElementSibling.innerText);//我们正在学习DOM。
-
previousSibling / previousElementSibling
返回位于相同节点树层级的上一个节点。previousSibling 计算空白,而previousElementSibling不会。
var ul = document.getElementById("ul"); //undefined,空白没有innerText console.log(ul.previousSibling.innerText); //bailiban console.log(ul.previousElementSibling.innerText);
-
parentNode
返回元素的父节点。
var ul = document.getElementById("ul"); console.log(ul.parentNode.tagName);// body
-
10.3 CSS
-
内联样式
我们可以通过元素.style.属性或者==元素.style[“属性”]==来获取或者设置元素的内联样式。如果属性是多个单词需要使用驼峰命名。
var p = document.getElementById("my_p"); // 获取元素P的内联样式的宽度 console.log(p.style['width']); // 获取元素p的内联样式的字体大小,fontSize采用驼峰命名 console.log(p.style.fontSize); // 设置元素p的宽度 p.style.width = "200px" ;
- 我们获取样式的时候是字符串类型,并且带有px字样。如果想转成只有数字的number类型可以使用parseInt方法。
-
生效样式
很多样式我们是定义在内部或者外部,只查看内联样式没意义,我们可以查看元素的生效样式而不用管是定义在哪里。
-
IE游览器: 元素. currentStyle.属性
var p = document.getElementById("my_p"); console.log(p.currentStyle.width); console.log(p.currentStyle.fontSize);
-
非IE游览器:getComputedStyle
var p = document.getElementById("my_p"); console.log( getComputedStyle(p)["width"] ); console.log( getComputedStyle(p)["fontSize"] );
-
-
兼容样式
由于IE跟非IE游览器的样式访问不太一样,我们可以自定义一个方法,来兼容所有游览器。
/* ele:要查看样式的元素。 styleName:要查看的样式名,字符串形式。 */ function getStyleValue(ele,styleName){ return ele.currentStyle ? ele.currentStyle[styleName] : getComputedStyle(ele,null)[styleName]; } var p = document.getElementById("my_p"); console.log(getStyleValue(p,"width")); console.log(getStyleValue(p,"fontSize"));
11. 事件
有时候我们需要在达到某些条件的时候去执行 一段固定的JS代码。我们称之为事件。事件有3要素:事件源、绑定事件、事件执行程序。比如页面有一个提交按钮,当点击这个按钮后可以打开一个新的页面。这个按钮叫事件源,打开新的页面叫做事件执行程序,按钮需要跟事件执行程序绑定后,才能在点击的时候触发执行逻辑。
11.1常用事件句柄
11.2 事件的绑定
方式一,直接在HTML中定义元素事件的相关属性
<button onclick="alert('hello')">按钮</button>
<button onclick="helloClk()">按钮</button>
<script>
function helloClk(){
alert('hello');
}
</script>
缺点:html中写JS代码,强耦合,违反了“内容与行为相分离”的原则,少用。
方式二,直接在JS中定义元素事件的相关属性
//<button id="btn_id1">按钮</button>
// 获取按钮元素
var btn = document.getElementById("btn_id1");
// 给按钮元素绑定事件句柄函数
btn.onclick = helloClk;
// 定义事件驱动函数
function helloClk(){
alert('hello');
}
解决了强耦合性,但只能给一个事件对象绑定一个事件类型。 绑定多个同一类型的事件的话后面覆盖前面的。
方式三,高级事件处理方式 (addEventListener)
// 获取按钮元素
var btn = document.getElementById("btn_id1");
// 给按钮元素绑定事件句柄函数,可以绑定多个
btn.addEventListener("click",btnClick1);
// false表示事件冒泡阶段执行,true表示事件捕获阶段执行,默认false
btn.addEventListener("click",btnClick2 ,false);
function btnClick1(){
alert('hello1');
}
function btnClick2(){
alert('hello2');
}
// 把btn上的click事件的btnClick1解除绑定
btn.removeEventListener("click",btnClick1);
- 可以为一个元素绑定多个监听函数,都会得到执行。
- 匿名事件无法解绑。
- IE使用的是detachEvent / attachEvent
11.3 表单的校验
对于JAVA工程师来说,前端与后台的数据交互是及其重要的,而表单的提交就是前端与后台的重要的数据交互。为了提交表单时数据更加合理,减轻后台的压力,在提交表单时进行校验是非常有必要的。
需求:一个具有用户名跟密码的表单,用户名跟密码长度不低于6位则提交,否则不提交并给出提示。
Step 1
在表单中绑定onsubmit事件,调用校验的函数,通过boolean结果来控制是否需要提交。
<form id="my_form" action="#" method="post" onsubmit="return check()" >
用户名: <input id="user_name" name="userName" /> <br/>
密 码: <input id="user_pwd" type="password" name="userPwd" /> <br/>
<input type="submit" />
</form>
<script>
function check(){
var name = document.getElementById("user_name").value;
var pwd = document.getElementById("user_pwd").value;
if(name.length < 6){
alert("用户名长度必须不低于6位");
return false ;
}
if(pwd.length < 6){
alert("密码长度必须不低于6位");
return false ;
}
return true;
}
</script>
Step 2
这种方式可以进行表单校验,但是密码具有私密性,这种方式密码可以直接看到,我们可以进一步优化,在提交数据之前对密码进行MD5加密。
md5在线CDN:
https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.9.0/js/md5.js
https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.9.0/js/md5.min.js
<!-- 引入md5的cdn -->
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.9.0/js/md5.min.js"></script>
function check(){
var name = document.getElementById("user_name").value;
var pwdInput = document.getElementById("user_pwd") ;
var pwd = pwdInput.value;
if(name.length < 6){
alert("用户名长度必须不低于6位");
return false ;
}
if(pwd.length < 6){
alert("密码长度必须不低于6位");
return false ;
}
// 当合法时通过md5方法对密码进行加密后,更新到密码框,这样提交的时候就是加密后的结果。
pwdInput.value = md5(pwd);
return true;
}
Step 3
虽然这样可以对密码进行加密,但是提交的时候密码框的长度会变长,给用户的体验并不好,我们还可以进一步优化,使用隐藏域来提交密码。
终极方案:
<script src="https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.9.0/js/md5.min.js"></script>
<form id="my_form" action="#" method="post" onsubmit="return check()" >
用户名: <input id="user_name" name="userName" /> <br/>
密 码: <input id="user_input_pwd" type="password" /> <br/>
<!-- 隐藏域,值用来保存密码md5加密后的结果,提交到后台 -->
<input id="user_hidden_pwd" type="hidden" name="userPwd" />
<input type="submit" />
</form>
function check(){
var name = document.getElementById("user_name").value;
var pwdInput = document.getElementById("user_input_pwd") ;
var pwd = pwdInput.value;
var pwdHidden = document.getElementById("user_hidden_pwd") ;
if(name.length < 6){
alert("用户名长度必须不低于6位");
return false ;
}
if(pwd.length < 6){
alert("密码长度必须不低于6位");
return false ;
}
pwdHidden.value = md5(pwd);
return true;
}
11.4 事件冒泡
-
事件的传播
JS中的事件创建后,会按照如下过程在HTML元素间进行传播。IE的事件模型是没有捕获阶段的。
- 第一阶段:事件捕获,事件对对象沿DOM树向下传播
- 第二阶段:目标出发,运行事件监听函数
- 第三阶段:事件冒泡,事件沿DOM树向上传播
<div id="my_div">
<button id="btn_id1">按钮</button>
</div>
<script>
// 获取按钮元素
var btn = document.getElementById("btn_id1");
var div = document.getElementById("my_div");
// 给按钮元素绑定btnClick1,在冒泡阶段
btn.addEventListener("click",btnClick1,false);
// 给按钮元素绑定btnClick1,在冒泡阶段
div.addEventListener("click",btnClick2,false);
// 给按钮元素绑定btnClick1,在捕获阶段
document.body.addEventListener("click",btnClick3,true);
function btnClick1(){
alert('btn click1');
}
function btnClick2(){
alert('div click2');
}
function btnClick3(){
alert('body click3');
}
</script>
结果
body click3
div click2
btn click1
11.5 event对象
事件处理函数中有一个绑定事件的对象,有时候我们需要用到里面的一些重要属性。
-
target
返回触发此事件的元素(事件的目标节点)。
event.target.id;// 返回触发事件的元素的ID event.target.nodeName;// 返回触发事件的元素的标签名
-
type
返回事件的类型。
event.type; // click
-
clintX / clintY
返回当事件被触发时,鼠标指针的水平 / 垂直坐标。
-
offsetX / offsetY
返回当事件被触发时,鼠标指针相对于事件源的水平 / 垂直坐标。
-
keyCode
对于按键事件,返回按键的代码。
-
preventDefault
取消事件的默认动作(如果存在这样的动作)。比如超链接、表单。
<a id="my_a" href="https://www.bailiban.com">bailiban</a> <script> var a = document.getElementById("my_a"); a.onclick = function(e){ e.preventDefault(); } </script>
-
stopPropagation()
阻止事件的继续传播。
<div id="my_div"> <button id="btn_id1">按钮</button> </div> <script> // 获取按钮元素 var btn = document.getElementById("btn_id1"); var div = document.getElementById("my_div"); // 给按钮元素绑定btnClick1,在冒泡阶段 btn.addEventListener("click",btnClick1,false); // 给按钮元素绑定btnClick1,在冒泡阶段 div.addEventListener("click",btnClick2,false); // 给按钮元素绑定btnClick1,在捕获阶段 document.body.addEventListener("click",btnClick3,true); function btnClick1(e){ alert('btn click1'); } function btnClick2(e){ alert('div click2'); } function btnClick3(e){ alert('body click3'); // 阻止事件的进一步传播,不会传播到div跟btn e.stopPropagation(); } </script>
-
cancelable
指示事件是否可拥可取消的默认动作。设置成true表示阻止事件的传播,等同
stopPropagation()
11.6 事件的委托/代理
事件委托就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。
需求:给ul下的每一个li绑定事件。
<ul id="ul1">
<li>苹果</li>
<li>香蕉</li>
<li>菠萝</li>
<li>哈密瓜</li>
</ul>
传统方式
循环给li元素绑定事件。
for(var item of li){
item.onclick = function(){
alert(this.innerText);
}
}
这种方式需要绑定很多事件,进行比较多次数的dom交互,影响性能。
事件委托
利用事件的传播机制,直接绑定在ul元素上。
ul.onclick = function(event){
if(event.target.nodeName.toLowerCase() == 'li'){
alert(event.target.innerText);
}
}