前端三层
结构层 HTML 搭建结构,放置部件,描述语义
样式层 CSS 美化页面,实现布局
行为层 Javascript 实现交互效果,数据收发,表单验证
javascript的书写位置
在 <body> 中<script>标签,在内部书写javascript代码
将代码单独保存为.js 格式文件,然后在html文件中使用
<script src=""></script>这样的形式引入它
Javascript不能脱离HTML网页运行(当然,今后学习的NodeJS将成为Javascript独立的运行平台)
第一行javascript
<script>
alert('你好,Javascript')
</script>
引入
<script src=""myjs.js></script>
认识输出语句
alert() 语句 弹出对话框
console.log语句 控制台输出
REPL环境
控制台也是个REPL环境,可以用它临时测试表达式的值
read 读 eval执行 println 打印 loop循环
变量
变量是计算机语言中能储存计算结构或能表示值抽象概念
变量不是数值本身,他们仅仅是一个用于存储数值的容器
定义变量
var a = 5
console.log(a)
a = 18;
变量的合法命名
只能由字母数字下划线 $组成,但是不能以数字开头
不能是关键字和保留字
变量名大小写敏感
优秀的变量命名法
驼峰命名法 matchTestScore
c风格: math_test_score
匈牙利命名法:iMathTestScore 第一个字母暗示类型
变量默认值
一个变量只定义,没有赋初值,默认是undefine
一个变量只有被var定义,并赋初值之后,才算正式初始化完成
var a;
console.log(a);
a = 10;
console.log(a);
同时声明多个变量
var a = 0,b = 0;
变量声明提升
你可以提前使用一个稍后才声明的变量,而不会引发异常。
在执行所有代码前,JS有预解析阶段,会预读所有的变量的定义。
console.log(a);//先试用变量
var a = 12; //后定义变量
变量声明提升只提升定义,不提升值,所以输出undefined
注意事项
变量声明提升是Javascript的特性,所以经常会出面试题
在实际开发时,不要刻意使用变量提升的特性。一定要先定义给变量赋初值,然后再使用变量。
重点内容
前端开发主要有哪些层,语言和功能是什么
Javascript的书写位置在哪里
变量是什么?如何定义变量?变量的合法命名规则有哪些
难点内容
只用var定义一个变量,但是没有赋初值,这个变量的值是什么
什么是变量声明的提升
javascrpt 中,等号的功能是什么? 赋值!
数据类型
Number(数字)
所有数字部分大小,部分整浮,部分正负,都是数字类型
typeof 925;
typeof 3.13;
typeof -6;
typeof .5;//number
科学计数法
较大数或较小数(绝对值较小) 可以写成科学计数法
3e8 //300000000
typeof 3e8 //number
3e-4; // 0.0003
typeof 3e-8; //number
不同进制的数字
二进制以0开头
0b10 //2
0b1111 //15
八进制数值以0开头
017 /15
十六进制数字以0x开头
0xf //15
一个特殊的数字类型是NaN
NaN是英语 not a number的意思,即不是一个数,但是他是一个数字类型的值
typeof NaN //number
0除以0的结果是NaN,事实上,在数学运算中,若结果不能得到数字,那结果往往都是NaN
NaN有一个奇怪的性质,不自等。这个知识点将在后续课程中讲解
String (字符串)
typeof ”慕课网“ //string
typeof '慕课网' //string
字符串的拼接
加号可以用来拼接多个字符串
'imo'+'ke'
var year = 2022;
var str = '北京冬奥会在' + year + ’年召开‘
空字符串
var aa = ''
字符串length属性
'我喜欢js'.length
字符串常见方法
charAt() 得到指定位置字符
substring() 提取子串
substr() 提取子串
slice() 提取子串
toUpperCase() 将字符串变为大写
toLowerCase将字符串变为小写
indexOf 检索字符串
substring(1,b) a可以大于b。数字顺序将自动调整为小数在前。
substr(a,b)将得到从a开始的长度为b的子串
substr(-4,2) 表示从倒数第四位开始长度为2的子串
slice(a,b)方法得到从a开始到b结束(不包括b)的子串,和substring类似
slice(a,b)的参数可以是负数,参数a,必须小于参数b
sunstring(a,b)和slice(a,b)功能基本一致,都是从a开始到b结束(不包括b)的子串,区别:
1 substring()可以自动交换两个参数位置,而slice不行
2 slice()的参数a可以是负数,而substring()不行
substr(a,b)中的参数b是子串的长度,而不是位置编号
toUpperCase和toLowerCase
toUpperCase转为大写 toLowerCase转为小写
indexOf()
返回某个指定的字符串值在字符串中首次出现的位置 如果要检索的字符串值没有出现,则该返回-1
布尔类型
typeof true;//boolean
typeof false //boolean
undefined是什么
一个没有被赋值的变量的默认值是undefined,而undefined的类型也是undefined
即 undefined又是值,又是一种类型,这种类型只有它自己一个值
变量声明提升的情况下,变量的值是undefined
null类型
null表示空,他是空对象,当我们需要将对象销毁,数组销毁或者删除事件监听时,通常将他们设置为null
box.onclick = null
用typeof 检测null的结果是 object
typeof null //object
类型和typeof检测结果并不总是一一对应的,比如数组用typeof检测结果也是object
Javascript可能看起来 千疮百孔,一定需要刻意记忆 这些点往往也是面试常考的
基本类型值
- 数字类型 // typeof number //5
- 字符串类型 //typeof string //慕课网
- 布尔类型 //typeof boolean //true false
- undefined类型 //typeof undefined //undefined
- null类型 //typeof object //null
数据类型的转换
其他值 ->数字
使用Number()函数
Number('1,2,3') //123
Number('123.4') //123.4
Number('123年');//NaN
Number('2e3') //2000
Number(''); //0
使用parseInt()函数 将字符串转为整数
parseInt('3.14') //3
parseInt('3.14是圆周率') //3
parseInt('圆周率是3.14');//NaN
parseInt('3.99')//3
parseInt()将自动截掉第一个非数字字符之后的所有字符,也不会四舍五入
使用parseFloat() 函数 字符串转换为浮点数
其他值转换字符串
String(123) //'123'
String(2e3)//'2000'
String(NaN) //'NaN'
String(0xf) //'15'
String(undefined) //undefineds
使用toString()方法 toString 更常用
6.toString() 数字会报错
(6).toString() 正确
true.toString() 'true'
其他值转换布尔值
Boolean(123) //true
Boolean(0) //false
Boolean(NaN) //false
boolean('')//false
Boolean(undifined)//false
Boolean(null)//false
数字转换布尔值 只有0和NaN会转换成false
空字符串转换布尔值是false,其他都是true
undefined和null转换boolean是false
小小计算器
//让用户输入两个数字 prompt弹框
var a = Number(prompt("请输入第一个数字"));
var b = Number(prompt("请输入第二个数字"));
//计算综合
var sum = a+b;
//弹出结果
alert('数字'+a+’加上数字‘+b+'的结果是:'+sum);
复杂数据类型
[1,2,3] 数组
{a:1,b:2}对象
function(){}
复杂数据类型都是 ”引用类型“
课程总结
Javascript有哪些基本类型值,他们的typeof值是什么
说出下面几个特殊值是什么
NaN undefined null
各种类型值相互转换的方法和转换规律
parseInt(’3.6‘+’5.1‘) //3
Boolean('false') //true
0/0 //NaN
4/0 //Infinity
请说出substring substr slice的区别
‘abcde’.substr(1,3) //bcd 从1 长度为3
'abcde'.substring(1,3) //bc 1开始3结束
'abcde'.slice(3,2) //”“ 参数不能a>b
'abcde'.substring(3,1)//bc 自动切换a和b的位置
表达式和运算符
5 + 3
操作数 运算符 操作数
算数运算符
-
-
- / %
-
隐式类型转换
如果参数数学运算的某操作数不是数字类型,那么会自动转换成数字类型
3+'4' 是 '34' 因为+号是连字符
3*'4' 是 12
隐式转换的本质是内部调用Number()函数
true+true //2
number(true) //1 number(false) //0
false +2 //2
3 * '2天' // NaN
3+ undefined //NaN 因为Number(undefined)是NaN
3+null 是 3 因为 Number(null)是0
有关 IEEE754
0.1+0.2 //0.30000000000004
javascript使用了IEEE754二进制浮点数算术标准,这会使一些个别的小数运算产生”丢失精度“问题
解决办法,在进行小数运算时,要调用数字的toFix方法
Number((0.1+0.2).toFixed(2))
幂和开根号
Javascript中没有提供幂计算,开根号的运算。需要使用吗math对象的相关方法进行计算
Math.pow(2,3) //8
Math.pow(3.2) //9
Math.sqrt(81) //9
Math.sqrt(-81) //NaN 负数不能开根号
向上取整和向下取整
Math.ceil向上取整 Math.floor向下取整
判断是否相等
等号 =等于赋值,而不是相等。判断相等应该使用==
相等和全等的区别
两个等号==运算符不比较值的类型。它会进行隐式转换后比较值是否相等
三个等号===运算符,不仅比较值是否相等,也比较类型是否相等。
5 == ‘5’ //true
5==='5'//false
1==true //true
1===true //false
0==false //true
0===false //false
0==undefined //false
0===undefined//false
undefined == null //true
undefined ===null //false
ES5规范中规定如果x是null,y是undefined结果是true,如果使用===比较则为false,因为 typeof null -> object, typeof undefined->undefined
NaN 不自等
NaN == NaN //false
NaN === NaN //false
如果判断某变量值为NaN
isNaN函数
isNaN(NaN) //true
isNaN(5) //false
但 isNan()也不好用,它的机理是:只要该变量传入Number()的执行结果是NaN,则isNaN()函数都会得到true
isNaN(undefined)//true
isNaN('3天') //true
isNaN(null) //false 因为Number(null)是0
不相等和不全等
!=表示不相等 !==表示不全等
5 != 6 //true
5 !== 6 //true
5 !=‘5’ //false
5 !=='5'//true
不相等判断的时候可以先判断是否相等,然后取反
例如 5 ==‘5’为true 则 5!='5'为false
JS中没有连比
3<=a<=15 //错误 比如a=100 3<a 为true 然后true等于1 1《=15
逻辑运算符 ! && ||
!true //false
!false //true
!0 //true
!undefined //true
!'' //true
!''imooc //false
短路计算
3 && 6
a && b 都真才真
a为真的时候 b真总结果就真,b假总结果就假
b为假的时候 不用看b了,被”短路“
a && 运算中: a真,表达式值为b;
a假,表达式值为a
a || b
a真 不用看b了,被短路
a假 b真总结过就真,b假总结过就假
a|| b 运算 a真,表达式值为a ;
a假,表达式值为b
逻辑运算顺序
非 ->与 ->或
!true || true //true
3 && 4 || 5 && 6 //4
3 && 4 结果是 4 4后面是|| 所以结果直接就是4
赋值运算符
赋值运算也产生值
var a;
console.log(a = 4); //4
这就意味着,可以连续使用赋值运算符
var a,b,c;
a = b = c = 15;
快捷赋值
快捷赋值运算符表示在原数值基础上进一步进行运算
var a = 3;
a+=5;
console.log(a) //8
综合运算的运算顺序
非运算 -》数学运算-》关系运算 -》 逻辑运算
5 < 3+3 //true 先计算3+3等于6 然后 5<6
3>2 && 8>3+4 // true
3>2 && 8>3+5 //false
!13 < 5-3 // true !13是0 0<8
!13<5-5 //false
闰年判断
1.能被4整除且不能被100整除 或者 2.能被100整除且也能400整除。
总结
表达式有哪几种,每种表达式分别有哪些运算符。
每种表达式中运算顺序是什么。综合运算顺序是什么
什么是短路计算 3 && 13的结果是什么
var a = 3
var b = 4
alert(a++ + b++ + ++a + ++b)
a++ 取值3
b++取值4
++a因为前面已经有a++了,所以这里取值是5
++b同理值是6
最终结果是18
流程控制语句
数组
var scoreArr = [96,97,76,87,87,90,91,100,78,56]
数组的定义
var arr = ['a','b']
var arr = new Array('A','B','C');
var arr = new Array(4);//定义了一个长度为4的数组
访问数组项
数组每一项都有下标 下标从0开始
下标越界
访问数组中不存在的项会返回undefined,不会报错
arr[-1]
这里是错误的,不会报错,返回的值是undefined
数组的长度 var arr = ['A','B']; arr.length;
更改数组项
var arr = [2,6,7,3];
arr[6] = 4;
console.log(arr);
结果是[2,6,7,3,empty,empty,4]
数组的遍历
var arr = ['a','b',,];
for(var i = 0; i<arr.length;i++){
console.log(arr[i]);
}
只有逗号的话是undefined
数组的类型检测
数组用typeof检测结果是object Array.isArray()方法可以用来检测数组 后面还有 ”鸭式辩型“
typeof[1,2,3] object
typeof{a:1,b:2} object
Array.isArray([]) true
数组的头尾操作
push() 在尾部插入新项
pop() 在尾部删除
unshift() 在头部插入新项
shift() 在头部删除
var arr = [22,33,44,55]
arr.push(66);
arr.push(77,88,99)
var item = arr.pop();//删除最后一项,并返回
arr.unshift(11)//头部插入
var item = shift()用来删除下标为0的项
splice() 方法 替换数组中的指定项
var arr = ['A','B','C','D','E','F','G']
arr.splice(3,2,'X','Y','Z')//从下标3的位置开始替换,连续替换两项
console.log(arr);
//['A','B','C','X','Y','Z','F','G']
splice()方法可以用于在指定位置插入新项
var arr = ['A','B','C','D'];
arr.splice(2,0,'X','Y','Z')
console.log(arr);
splice()方法可以用来删除指定项
var arr = ['A','B','C','D','E','F','G'];
arr.splice(2,4)//从2开始,删除4项
console.log(arr)
slice()方法
slice()方法用于得到子数组,类似于字符串的slice()方法 slice(a,b)截取的子数组从下标a的项开始,到下标为b(但是不包括下标为b的项)结束
slice()方法 如果不提供第二个参数,则表示从指定项开始,提取所有后续所有项为子数组
slice() 方法的参数允许为负数,表示数组的倒数的第几项
join和split方法
数组的join方法可以使数组转换为字符串方法,字符串的split方法可以使字符串转换为数组
join()的参数表示以什么字符作为连接符。如果留空则默认以逗号分隔,如同调用toString() 方法。
split()的参数表示以什么字符拆分字符串,一般不能留空
[22,33,44,55].join() //22,33,44,55
[22,33,44,55].toString() //22,33,44,55
[22,33,44,55].join('-') //22-33-44-55
'abcdefg'.split() //['abcdefg']
'abcdefg'.split('')//['a','b','c','d','e','f','g']
'a-b-c-d-e-f-g'.split('-')//['a','b','c','d','e','f','g']
字符串也可以使用方括号写下标的形式,访问某个字符,等价与charAt() 方法
’我爱慕课网‘[0] //'我'
字符串的一些算法问题有时候可以转换为数组解决
concat()方法
concat()方法可以合并链接多个数组
var arr1 = [1,2,3,4]
var arr2 = [5,6,7,8]
var arr = arr1.concat(arr2,arr3);
console.log(arr);
reverse() 方法
reverse() 方法用来将一个数组中的全部项顺序翻转
var arr = ["A","B","C","D"]
arr.reverse();
console.log(arr);
如何将字符翻转
'ABCDEFG'.split('').reverse().join('')
先将字符串转换为数组,然后翻转,然后转换成字符串
indexOf() 方法和 includes() 方法
indexof() 方法的功能是搜索数组中的元素,并赶回它所在的位置,如果元素不存在,则返回-1
includes() 方法的功能是判断一个数组是否包含一个指定的值,返回布尔值
['A','B','C','D','E'].indexOf('C') //2
['A','B','C','D','E'].indexOf('M')//-1
['A','B','C','D','E'].includes('C') //true
有关数组排序
数组有sort() 方法可以用来数组排序
什么是引用类型
基本类型 string number boolean null undefined
引用类型 array,object,function,regexp...
3==3 //true
[1,2,3] == [1,2,3] //false
[] ==[]//false
深克隆和浅克隆
使用arr1 =arr2的语法不会克隆数组
浅克隆:只克隆数组的第一层,如果是多维数组,或者数组中的项是其他引用类型值,则不克隆其他层
深克隆:克隆数组的所有层,要使用递归技术,
总结
数组是什么,应该如何定义 如何检测数组类型? Array.isArray()
函数的定义
function fun(){
//函数体语句
}
//匿名函数
var fun= function(){
//函数体
}
函数的调用
fun() 调用函数
函数声明的提升
fun();
function fun(){
alert("函数被执行")
}
fun() //引发错误 变量fun这时是undefined
var fun = function(){
}
## 函数优先提升
```js
fun();
var fun = function(){
alert('A')
}
function fun(){
alert('B')
}
fun()
优先一声函数的定义,然后才是变量的定义
先弹出B,在弹出A ,因为与解析的时候加载了function();运行时加载了var fun。 函数不会再次覆盖了,
函数的参数和返回值
function add(a,b){
var num = a+b;
}
add(1,2,3); //第三个参数无效
function add(a,b,c){
var num = a+b+c; //c是undefined,undefined运行任何运算结果都是NaN
}
add(1,2); //第三个参数无效
arguments
函数内arguments表示它接收到的实参列表,它是一个类数组对象
类数组对象:所有属性均为从0开始的自己数序列,并且有length属性,和数组类型可以使用方括号来书写下标访问对象的某个属性值,但是不能调用数组的方法。
function fun(){
var sum = 0;
for(var i = 0; i<arguments.length;i++){
sum += arguments[i];
}
}
fun(33,44,23,34);
递归
数据类型分基本类型值和引用类型值
深克隆
使用递归思想,如果遍历到项是基本类型值,则直接推入结果数组,如果遍历到的项又是数组,则重复执行浅克隆操作
//原数组
var arr1 =[33,44,11,22,[77,88]];
//函数,这个函数会被递归
function deepClone(arr){
var result = [];
//遍历数组的每一项
for(var i= 0;i<arr.length;i++){
if(Array.isArray(arr[i])){
deepClone(arr[i])
}else{
//如果遍历到的项不是数组,是基本类型值,就直接推入到结果数组中
//递归的出口
result.push(arr[i]);
}
}
return result;
}
变量作用域
Javascript是函数级作用域变成语言:变量只在其定义时所在的function内部有意义。
遮蔽效应
如果函数中也定义了和全局同名的变量。则函数内部的变量会将全局的变量”遮蔽“
变量声明提升
var a = 10;
function fun(){
a++;//局部变量a被自增1,a此时是undefined,自增1结果是NaN
var a = 5; //重新将a赋值给5
console.log(a);
}
fun()
console.log(a);
闭包
function fun(){
var name = '慕课网'
function innerFun(){
alert(name);
}
return innerFun;
}
var inn = fun();//返回了内部函数
inn();//内部函数被移动到了外部执行
闭包(closure),闭包是函数本身和该函数声明时所处的环境状态的组合。
函数能够 ”记忆住“ 其定义时所处的环境,即使函数不再其定义的环境中被调用,也能访问定义时所处环境的变量。
每次创建函数时都会创建闭包
但是,闭包特性往往需要将函数”换一个地方“执行,才能被观察出来。
闭包很有用,因为它允许我们将数据与操作该数据的函数关联起来。这与”面向对象编程“有少许相似之处。
闭包的功能:记忆性,模拟私有变量。
记忆性:当闭包产生时,函数所处的环境的状态会始终保持在内存中,不会在外层函数调用后被自动清除。这就是闭包的记忆性,
闭包私有变量
function fun(){
var a = 0;
return {
getA:function(){
return a;
},
add:function(){
a++;
}
pow:function(){
a*=2;
}
}
}
var obj = fun();
//如果想在fun函数外面使用变量a,唯一的方法就是调用getA()方法。
console.log(obj.getA());
使用闭包的注意点
不能滥用闭包,否则会造成页面的性能问题,严重时可能导致内存泄露。所谓内存泄露是指程序中已动态分配的内存由于某种原因未释放或无法释放。
闭包的一道面试题
function addCount(){
var count = 0;
return function(){
count = count + 1;
console.log(count);
}
}
var fun1 = addCount();
var fun2 = addCount();
fun1();//1
fun2();//1
fun2();//2
fun1();//2
立即执行函数 IIFE
IIFE(Immediately Invoked Function Expression,立刻调用函数表达式)是一种特殊的Javascript函数写法,一旦被定义,就立刻被调用。
(function(){
statements
})();
第一个圆括号将函数变为表达式
最后的圆括号的功能是运行函数。
还可以写成
+function(){
statements
}();
-function(){
statements
}();
IIFE的作用1 为变量赋值
var age = 12;
var sex = '男';
var title = (function(){
if(age < 18){
return '小朋友'
}else{
if(sex == '男'){
return '先生';
}else{
return '女士';
}
}
}){};
IIFE的作用2
var arr = [];
for(var i = 0; i<5;i++){
arr.push(function(){
alert(i);
})
}
arr[0]()// 这个弹出5,因为i是共享的,所以i都是5
var arr = [];
for(var i = 0; i<5;i++){
(function(i){
arr.push(function(){
alert(i);
});
})(i);
}
alert[2]();//弹出2
函数课程重点
什么是函数,函数为变成带来了哪些便利
函数的参数和返回值
函数相关算法
难点
递归,递归算法题
作用域和闭包
IIFE
DOM
如何改变元素节点的内容
改变元素节点的内容可以使用两个相关属性 1.innerHTML 2innerText
innerHTML 属性能以HTML语法设置节点中的内容
innerText属性只能以纯文本的形式设置节点中的内容
<div id = 'box'></div>
<script>
var oBox = document.getElementById('box');
//oBox.innerHTML = '慕课网';
oBox.innerHTML = '<ul><li>牛奶</li><li>咖啡</li></ul>';
</script>
节点的创建
document.createElement()方法用于创建一个指定tag name的HTML元素
var oDiv = document.createElement('div');
新创建出来的节点是”孤儿节点“,这意味着它并没有被挂在到DOM树上,我们无法看见它。
必须继续使用appendChild()或insertBefore() 方法将孤儿节点插入到DOM树上
父节点.appendChild(孤儿节点);
insertBefore() 任何已经在DOM书上的节点,都可以调用insertBefore()方法,它可以将孤儿节点挂载到它的内部,称为它标杆子节点之前的节点
父节点.insertBefore(孤儿节点,标杆节点);
<div id="box">
<p>我是原本的段落0</p>
<p>我是原本的段落1</p>
<p>我是原本的段落2</p>
</div>
<script>
var oBox = document.getElementById('box');
var oPs = oBox.getElementsByTagName('p');
//创建孤儿节点
var oP = document.createElement('p');
//设置内部文字
oP.innerText = '我是新来的';
//oBox.appendChild(oP);
oBox.insertBefore(oP,oPs[0]);
</script>
动态创建一个20行12列的表格
var mytable = document.getElementById('mytable');
for(var i = 0;i<20;i++){
var tr = document.createElement('tr');
for(var j =0;j<12;j++){
var td = document.createElement('td');
tr.appendChild(td);
}
mytable.appendChild(tr);
}
移动节点
如果将已经挂在到DOM树上的节点称为appendChild()或者insertBefore()的参数,这个节点将会被移动。
新父节点.appendChild(已经有父亲的节点); 新父节点.insertBefore(已经有父亲的节点,标杆子节点); 这意味着一个节点不能同时位于DOM树的两个位置。
删除节点
removeChild() 方法从DOM中删除了一个子节点
父节点.removeChild(要传出子节点);
节点不能主动删除自己,必须由父节点删除它。
克隆节点
cloneNode() 方法可以克隆节点,克隆出的节点是”孤儿节点“。
var 孤儿节点 = 老节点.cloneNode(); var 孤儿节点 = 老节点.cloneNode(true);
参数是一个布尔值,表示是否采用深度克隆:如果是true,则被节点的所有后代节点也都会被克隆,如果为false,则只克隆该节点本身
如何改变元素节点的CSS样式
oBox.style.backgroundColor = 'red';
oBox.style.backgroundImage = 'url(images/1.jpg)';
oBox.style.fontSize = '32px';
如何改变元素节点的HTML属性
oImg.scr = 'images/2.jpg';
//不符合W3C标准的属性,要使用setAttribute()和getAttribute()来设置,读取
oBox.setAttribute('data-n',10);
var n = oBox.getAttribute('data-n');
alert(n);
<div id="box"></div>
<script>
var box = document.getElementById('box');
box.setAttribute('data-n',10);
var n = box.getAttribute('data-n');
alert(n);
</script>
nodeType常用属性值
可以显示这个节点的具体类型
访问元素节点
认识document对象
document对象是DOM中最重要的东西,几乎所有的DOM的功能都封装在了document对象中。
document对象表示整个HTML文档,它是DOM节点树的根
document对象的nodeType属性值是9
访问元素的常用方法
document.getElementById();
document.getElementByTagName();
document.getElementByClassName();
document.getElementByClassName();
document.querySelector();
document.querySelectorAll();
如果页面上有相同id的元素,则只能得到第一个
延迟运行
在测试DOM代码时,通常JS代码一定要写在HTML节点的后面,否则JS无法找到相应HTML节点
可以使用window.onload = function(){}事件,使页面加载完毕后,在执行指定的代码
getElementsBytagName();通过标签名得到节点数组
querySelector()
通过选择器来获得元素
<div id="box1">
<p>我是段落</p>
<p class="spec">我是段落</p>
<p>我是段落</p>
</div>
JS代码
var the_p = document.querySelector('#box1 .spec')
querySelector() 方法只能得到页面上一个元素,如果有多个元素符合条件,则只能得到第一个元素
querySelector() 方法从IE8开始兼容,但从IE9开始支持CSS3的选择器,如nth-child(),:[src^='dog']等CSS3选择器都支持良好
querySelectorAll() 通过选择器得到数组
节点的关系
子节点 childNodes4
父节点 parentNode
第一个子节点 firstChild
最后一个子节点 lastChild
前一个兄弟节点 previousSibling
后一个兄弟节点 nextSibling
文本节点也属于节点
从IE9开始支持一些”只考虑元素节点“的属性
子节点 children
父节点 parentNode
第一个子节点 firstElementChild
最后一个子节点 lastElementChild
前一个兄弟节点 previousElementSibling
后一个兄弟节点 nextElementSibling
书写常见的节点关系函数
书写IE6也能兼容的 ”寻找所有元素子节点“的函数
//封装一个函数,这个函数可以返回元素所有子元素节点(兼容到IE6),类似与children功能
function getChildren(node){
//结果数组
var children = [];
//遍历node这个节点的所有子节点
//如果是1,就推入结果数组
for(var i = 0;i<node.childNodes.length;i++){
if(node.childNodes[i].nodeType == 1){
children.push(node.childNodes[i]);
}
}
return children;
}
//封装一个函数,这个函数可以返回元素的前一个元素兄弟节点(兼容到IE6),类似previousElementSlibing的功能
function getElementPrevSibling(node){
var o = node;
while(o.previousSibling!=null){
if(o.previousSibling.nodeType == 1){
return o.previousSibling;
}
o = o.previousSibling;
}
}
//封装第三个函数,这个函数可以返回所有的兄弟节点
function getAllElementSibling(node){
var prevs = [];
var nexts = [];
var o = node;
while(o.previousSibling!=null){
if(o.previousSibling.nodetype ==1){
prevs.unshift(o.previousSibling);
}
o = o.previousSibling;
}
o = node;
while(o.nextSibling!=null){
if(o.nextSibling.nodetype ==1){
nexts.unshift(o.nextSibling);
}
o = o.nextsSibling;
}
//将两个数组进行合并,然后返回
return prevs.concat(next);
}
事件监听
DOM允许我们书写Javascript代码以让HTML元素对事件做出反应
oBox.onclick = function(){
//点击盒子时,将执行这里的语句
}
常见的鼠标事件监听
onclick 当鼠标单击某个对象
ondblclick 当鼠标双击某个对象
onmousedown当鼠标按键在某个对象上被按下
onmouseup 当某个鼠标按键在某个对象上被松开
onmousemove 当某个鼠标按键在某个对象上被移动
onmouseenter 当鼠标进入某个对象
onmouseleave 当鼠标离开某个对象
常见的键盘事件监听
onkeypress 某个键盘的键被按下 (箭头和功能键盘无法被识别) onkeydown 某个键盘的键被按下 先于onkeypress发生 onkeyup 当某个键盘的键被松开
常见的表单事件监听
onchange 当用户改变域内容 onfocus 当某元素获得焦点 onblur 当某元素失去焦点 onsubmit 当表单被提交 onreset 当表单被重置
常见的页面事件监听
onload 页面或者图像被完成加载
onunload 当用户退出页面
当盒子嵌套时事件监听的执行顺序
实际上,事件的传播是:先从外到内,然后再从内到外。
从外到内是 捕获阶段(capturing phase)
从内到外 冒泡阶段(Bubbling phase)
onXXX(onclick)这样的写法只能监听冒泡阶段
addEventListener()
Dom0级事件监听:只能监听冒泡阶段
oBox.onclick = function(){
};
DOM2级事件监听:
oBox.addEventListener('click',function(){
//这是事件处理函数
},true)
click:时间名字不加on
true:监听捕获阶段,false监听冒泡阶段
最内层的盒子的书写顺序会影响他的执行顺序
都是冒泡阶段的话比如oBox.onclick和oBox.addEventListener('click',function(){},false)谁先写就先执行谁
最内部元素不再区分捕获和冒泡阶段,会先执行写在前面的监听,然后执行后写的监听。
如果给元素设置相同的两个或多个同名事件,则DOM0级写法后面写的会覆盖先写的,而DOM2级会按照顺序执行
什么是事件对象
事件处理函数提供了一个形式参数,他是一个对象,封装了本次事件的细节
这个参数通常用单词event或者字母e来表示
oBox.onmousemove = function(e){
//对象e就是这次事件的”事件对象“
}
鼠标位置
clientX 鼠标指针相对于浏览器的水平坐标
clineY 鼠标指针相当于浏览器的垂直坐标
pageX 鼠标指针相对于整张页面的水平坐标
pageY 鼠标指针相当于整张网页的垂直坐标
offsetX 鼠标指针相对于事件源的水平坐标
offsetY 鼠标指针相对事件源元素的垂直坐标
e.charCode和e.keyCode属性
e.charCode属性通常用于onkeypress事件中,表示用户输入的字符的”字符码“
e.keyCode属性通常用于onkeydown事件和onkeyup中,表示用户按下的按键的”键码“
charCode 字符码
字符 字符码
数字0~数字9 48~57
大写字母A~Z 65~90
小写字母a~z 97~122
keycode键码
按键 键码
数字0~9 48~57
字母部分大小a~z 65~90(同charCode键码的大写字母A~Z,而keycode部分大小写,一律为65~90)
四个方向键 左上右下 37,38,39,40
回车键 13
空格键 32
小案例
制造一个特效:按方向键可以控制页面上盒子移动
<div id="box"></div>
<script>
var oBox = document.getElementById('box');
//全局变量t l分别表示盒子的top属性值和left属性值
var t = 200;
var l = 200;
document.onkeydown = function(e){
switch(e.keyCode){
case 37:
l-=3;
break;
case 38:
l-=3;
break;
case 39:
l+=3;
break;
case 40:
t+=3;
break;
}
oBox.style.left = l +'px';
oBox.style.top = t+'px';
}
<script>
e.preventDefault() 方法
e.preventDefault()方法用来阻止事件产生的”默认动作“
一些特殊的业务需求,需要阻止事件的”默认动作“
小案例
制作一个文本框,只能让用户在其中输入小写字母和数字,其他字符输入没有效果
<input type="text" id="field">
var oField = document.getElementById('field');
oField.onkeyPress = function(e){
//根据用户的输入的字符的字符码(e.charCode)
//数字0-9,字符码48-57
//小写字母a-z,字符码97-122
if((e.charCode>=48 && e.charCode<=57 || e.charCode>=97 && e.charCode<=122)){
e.preventDefault();//阻止其他按键输入
}
}
小案例
鼠标滚轮事件,当鼠标在盒子中向下滚动时,数字+1,反之,数字减1
鼠标滚轮事件是onmousewheel,它的事件对象e提供deltaY属性表示鼠标滚动方向,向下滚动时返回正值,向上滚动时返回负值
<div id="box"></div>
<h1 id="info">0</h1>
<script>
var oBox = document.getElementById('box');
var oInfo = document.getElementById('info');
//全局变量就是info中显示的数字
var a = 0;
//给box盒子添加鼠标滚轮事件监听
oBox.onmousewheel = function(e){
//阻止默认事件:就是说用户在盒子里滚动鼠标滚动事件时,外部窗口就不会上下滚动
e.preventDefault();
if(e.deltaY >0){
a--;
}else{
a++;
}
oInfo.innerText = a
}
</script>
e.stopPropagation()方法
e.stopPropagation()方法用来阻止事件继续传播
在一些场合,非常有必要切断事件继续传播,否则会造成页面特效出bug
<div id="box">
<button id="btn">按我</button>
</div>
<script>
var oBox = document.getElementById('box');
var oBtn = document.getElementById('btn');
oBox.onclick = function(){
console.log('我是盒子')
}
oBtn.onclick = function(e){
e.stopPropagation();//阻止继续传播
console.log('我是按钮')
}
</script>
制作一个弹出层:点击按钮显示弹出层,点击网页任意地方,弹出层关闭
<button id="btn">按我弹出弹出层</button>
<div class="model" id ="model"></div>
<script>
var oBtn = document.getElementById('btn')
var oModel = document.getElementById('modal')
//点击按钮的时候,弹出层显示
oBtn.onclick = function(e){
//阻止事件继续传递到document上
e.stopPropagation();
oModel.style.display = 'block';
}
//点击页面任何部分的时候,弹出层关闭
document.onclick = function(){
oModal.style.display = 'none';
}
//点击弹出层内部的时候,不能关闭弹出层的,所以应阻止事件继续传播
oModal.onclick = function(e){
//阻止事件继续传播到document身上
e.stopPropagation();
}
</script>
批量添加事件监听
页面上有一个无序列表<ul>,它内部共有20个<li>元素,请批量给他们添加点击事件。点击哪个<li>哪个就变红
var oList = document.getElementById('list');
var lis = oList.getElementsByTagName('li');
书写循环语句,批量给元素添加监听
for(var i = 0; i 《 lis.length;i++){
lis[i].onclick = function(){
//this表示点击的元素,this涉及函数上下文的相关知识,我们在面向对象课程中介绍
this.style.color='red';
}
}
批量添加事件监听的性能
每一个事件监听注册都会消耗一定的系统内存,而批量添加事件会导致数量太多,内存消耗比较大
实际上,每个<li>的事件处理函数都是不同的函数,这些函数本身也会占用内存
新增元素动态绑定事件
在ul中添加li并绑定点击
<button id ='btn'>按我添加新的li列表项</button>
<ul id="list"></ul>
<script>
var oBtn = document.getElementById('btn');
var oList = document.getElementById('list');
oBtn.onClick = function(){
var oLi = document.createElement('li');
oLi.innerHTML = '我是列表项';
oList.appendChild(oList);
}
</script>
事件委托
利用事件冒泡机制,将后代元素事件委托给祖先元素
监听li事件的时候其实可以监听ul事件
事件委托通常需要结合使用e.target属性
target 触发此事件最早的元素,即事件源元素 currentTarget 事件处理程序附加到的元素
var oList = document.getElementById('list');
oList.onclick = function(e){
e.target.style.color = 'red';
};
使用事件委托时需要注意的事项
onmouseenter和onmouseover都表示”鼠标进入“,那么他们有什么区别
onmouseenter不冒泡
onmouseover冒泡
oList.onmouseenter = function(e){
//e.target表示用户真正点击的那个元素
e.target.style.color = 'red';//这里ul变成了红色,因为onmouseenter不冒泡,target是ul
}
使用事件委托 最内层元素不能再有额外的内层元素
因为target的值是最内层元素
定时器
setInterval()函数可以重复调用一个函数,在每次调用之间具有固定的时间间隔
setInterval(function(){
//这个函数会自动被以固定间隔时间调用
},2000);
函数的参数
setInterval() 函数可以接收第3,4。。个参数,他们将按照顺序传入函数
setInterval(function(a,b){
// 形式参数a的值是88,形式参数b的值是66
},2000,88,66);
具名函数也可以传入
var a = 0;
function fun(){
console.log(++a);
}
setInteval(fun,1000);
注意fun没有圆括号
清除定时器
clearInterval函数可以清除一个定时器
var timer = setinterval(function(){
},2000);
//点击按钮时,清除定时器
oBtn.onclick = function(){
clearInterval(timer);
}
var timer;
oBtn1.onClick = function(){
//为了防止定时器叠加,我们应该在设置定时器之前先清除定时器
clearInterval(timer);
timer = setInterval(function(){
oInfo.innerText = ++a;
},1000);
}
oBtn2.onclick = function(){
clearInterval(timer);
}
演示器
setTimeOut() 函数可以设置一个演示器,当指定时间到了之后,会执行函数一次,不会再重复执行
setTimeout(function(){
//这个函数会在2秒后执行一次
},2000);
clearTimeout() //清除演示器
初步认识异步语句
setInterval和setTimeout是两个异步语句
异步(asynchronous):不会阻塞CPU继续执行其他语句 当异步完成时,会执行”回调函数“(callback)
使用定时器实现动画
var left = 100;
btn.onclick = function(){
var timer = setInterval(function(){
//改变全局变量
left += 10;
if(left >= 1000){
clearinterval(timer);
}
//设置left属性
box.style.left = left + 'px';
},20);
}
JS和CSS3结合实现动画
css3的transition过渡属性可以实现动画
javascript可以利用css3 的transition属性轻松实现元素动画
JS和CSS3结合可以实现动画规避了定时器制作动画的缺点
var pos = 1//标识符 1代表左边 2代表右边
var lock = true;//函数节流锁
btn.onclick = function(){
if(!lock)return;
box.style.transition = 'all 2s linear 0'
if(pos ==1){
box.style.left = '1100px'
pos =2;
}else if(pos ==2){
box.style.left = '100px';
pos =1;
}
//关锁
lock = false
setTimeout(function(){
lock = true;
},2000);
}
函数节流
一个函数执行一次后,只有大于设定的执行周期后才允许执行第二次
函数节流非常容易实现,只要借助setTimeout()延时器
无缝连续滚动特效
BOM (browser object model)
BOM(Browser Object Model浏览器对象模型) 是js与浏览器窗口交互的接口
一些与浏览器改变尺寸。滚动条滚动相关的特效,都要借助BOM技术
Window对象
window对象是当前JS脚本运行所处的窗口,而这个窗口中包含DOM结构,window.document属性就是document对象
全局变量是window的属性
全局变量会变成window对象的属性
var a = 10;
console.log(window.a == a);//true
这意味着,多个js文件之间是共享全局作用域的,即js文件没有作用域格力功能
var a = 3;
console.log(window.hasOwnProperty('a'));//true
console.log(window.a);//3
内置函数普遍是window的方法
window.alert == alert //true;
window.setInterval == setInterval //true
窗口尺寸相关属性
innerHeight 浏览器窗口的内容区域的高度,包含水平滚动条(如果有的话) innerWidth 浏览器窗口的内容区域的宽度,包含垂直滚动条(如果有的话) outerHeight 浏览器窗口的外部高度 outerWidth 浏览器窗口的外部宽度
获得不包含滚动条的窗口宽度,要用document.documentElement.clientWidth
resize事件
在窗口大小改变时,就会触发resize事件,可以使用window.onresize或者window.addEventListener('resize')来绑定事件处理函数
window.onresize = function(){
var root = document.documentElement;
console.log('窗口改变尺寸了',root.clientWidth,root.clientHeight)
}
已卷动高度
window.scrollY属性表示在垂直方向已滚动的像素值。
已动高度
document.documentElement.scrollTop属性也表示窗口卷动高度
var scrollTop = window.scrollY || document.documentElement.scrollTop;
document.documentElement.scrollTop不是只读的,而window.scrollY是只读的。
scroll事件
在窗口被卷动之后,就会触发scroll事件,可以使用window.onscroll或者window。addEventListener('scroll') 来绑定事件处理函数
history对象
浏览器的会话历史接口
常用操作就是模拟浏览器回退按钮
history.back();//等同于点击浏览器的回退按钮
history.go(-1);//等同于history.back();
Location对象
通过给这个属性赋值命令浏览器进行页面跳转
window.location = 'www.imooc.com' window.location.href = 'www.imooc.com'
重新加载当前页面
可以调用location的reload方法来重新加载页面,参数true表示强制从服务器强制加载
GET请求查询参数
window.location.search属性即为当前浏览器的GET请求查询参数
比如网址 https://www.imooc.com/?a=1&b=2
console.log(window.location.search) //"?a=1&b=2"
返回顶部按钮
楼层导航小效果
DOM元素都有offsetTop属性,表示此元素到定位祖先元素的垂直距离
定位祖先元素:在祖先中,离自己最近的且拥有定位属性的元素。