javascript学习笔记
(所写博客来自网课视频、本网站或其他网站,只属于资料整理、用于个人学习,如有侵权行为可联系删除。)
程序运行
硬盘----内存条----cpu
- 打开某个程序,先把硬盘中的程序代码加载到内存中,
- cpu运行程序代码
一、初识JavaScript
JavaScript是脚本语言,既可以做前台也可以做后台,
脚本语言:不需要编译,运行过程由JS解释器逐步来进行解释并执行。
JavaScript的作用
- 表单动态校验(js的最初目的)
- 网页特效
- 服务端开发(Node.js)
- 桌面程序(Electron)
- app(Cordova)
- 控制硬件–物联网(Ruff)
- 游戏开发(cocos2d-js)
浏览器执行JS简介
浏览器本身不会执行js代码,而是通过内置的JavaScript引擎来执行js代码,JS引擎执行代码时逐行进行解释每一句源码,
js的组成
javascript语法:ECMAScript
页面文档对象模型:DOM
浏览器对象模型:BOM
js初体验
- 注意单双引号的使用:在HTML中推荐用双引号,js中推荐用单引号
注释:
- 单行注释:ctrl+/
- 多行注释;shift+alt+a
<script>
//这是一个输入框
prompt('请输入您的年纪');
//alert 弹出警示框
alert('计算');
console.log('这是控制台打印');
</script>
二、变量
什么是变量
通俗:变量是用于存放数据的容器,我们通过变量获取数据,
本质:变量是程序在内存中申请的一块用来存放数据的空间
使用变量
变量使用分两步;
-
申明变量
//申明了一个age变量 var age;
-
赋值
//给age赋值18 age=18;
变量初始化
//初始化
var age=18;
例子:产生输入值,存入变量,然后弹出内容。
<script>
var myname = prompt('请输入弹出内容:');
//prompt取出来的数据类型是字符
alert(typeof myname);
</script>
- 只申明不赋值,结果undefined
三、数据类型
// var num; //这里的num不确定是属于哪种数据类型的
var num=10; //这是一个数字型
//js 的变量数据类型是只有在程序运行过程中,根据等号右边的值来确定的;
var a='是的'; // a是字符串型
//js 是动态语言 变量的数据类型是可以变化的
简单数据类型
简单数据类型 | 说明 | 默认值 |
---|---|---|
Number | 数字型 | 0 |
Boolean | 布尔类型 | false |
String | 字符串类型 | ‘’ |
Undefined | var a;声明了变量a但没有给值,此时a=undefined | undefined |
Null | var a =null; 声明 了变量a 为空值 | object |
数字型
//isNaN() 用这个方法判断非数字, 并返回一个值,如果是数字返回false,不是则返回ture
console.log(isNaN(12));
String
-
字符串引号嵌套,(外双内单,外单内双)
var str='我是一个"高富帅"的程序员';
-
字符串转义字符 都是用\开头 但这些转义字符写到引号里面,
例子:
var str1="我是一个'高富帅'\n程序员"; console.log(str1);
-
通过字符串的length属性检测字符串的长度。
-
字符串的拼接 +;(字符串+任何类型=拼接后的新字符串)
console.log('沙漠'+'骆驼'); console.log('12'+12); //'1212' var age=18; //变量不要写道字符串里面,是通过字符串相连的方式实现的; console.log('我'+age+'岁');
口诀:数值相加,字符相连
布尔型
true参与加法运算当1来看;
false参与加法运算当0来看;
undefined
对数据类型的操作
检测变量的数据类型 typeof
var num=10;
console.log(typeof num); //number
var str='pink';
console.log(typeof str); //string
字符类型转换
- 转字符型
// 1.把数字型转换为字符串型 变量.toString()
var num = 10;
var str = num.toString();
console.log(str);
console.log(typeof str);
// 2.利用String(变量)
console.log(typeof String(num));
// 3. 利用+ 拼接字符串的方法实现转换效果 隐式转换
console.log(typeof(num + ''));
- 转数字型
// 1.parseInt(变量) 可以把字符型的转换成数字型, 得到的是整数
console.log(parseInt('3.14')); //3取整
console.log(parseInt('120px'));
//会去掉120这个的px单位
// 2.parseFloat(变量) 可以把字符型的转换为数字型, 得到的是小数
console.log(parseFloat('3.14'));
//3.利用Number(变量)
var str='123';
console.log(Number(str));
//4.利用算数运算符- * / 隐式转换
console.log('12'-0); //12
案例:
//计算年龄
var year =promt('请输入出生年份:');
var age=2021-year; //year取过来的是字符串型 但这里有隐式转换
alert('今年'+age+'岁了');
-
转布尔类型
console.log(Boolean('')); //false
代表空、否定的值会被转换为false,如’’、0、NaN、null、undefined.
课后拓展
解释型语言和编译型语言
编译语言----翻译器—机器语言
翻译器有两种翻译方式:一个是编译,一个是解释。
区别:编译器是代码开始之前进行编译,生成中间代码文件;解释器是在运行时进行及时解释,并立即执行。
四、javascript的运算符
注意:=== 和 ==的区别, == 表示先转换类型(自动)再比较。
=== 先判断数据类型,(类型不同时,不会自动转换类型)如果不是同一类型直接为false。如果类型相同,再判断其值,如果值也相同则返回true,否则返回false。表示的是绝对的相等。
运算符优先级练习
console.log(4>=6||'人'!='阿凡达'&&!(12*2==144)&& ture)
var num=10;
console.log(5==num/2&&(2+2*num).toString()==='2');
五、javascript的流程控制分支结构及循环
if else if 分支语句
if (表达式1){}
else if(表达式2){}
else if(表达式3){}
else{}
//注意最后一句没有判断表达式
switch的注意事项
var num = 1;
switch(num){
case 1:
console.log(1);
case 2:
console.log(2);
case 3:
console.log(3);
break;
}
- 开发里面表达式不能写成变量
- num的值和case里面的值相匹配的时候是全等,必须是值和数据类型一致才可以 num===1;
- break 如果当前的case里面没有break,则不会退出switch,继续执行case;
循环
for循环
案例:
//弹出输入框的输入的总人数
//依次输入学生成绩,
//累加求总成绩
var num=prompt('请输入班级总人数:');
var sum=0;//求和的变量
var average=0; //求平均值的变量
for(var i=1;i<=num;i++){
var score=prompt('请输入第' + i + '个学生成绩');
//prompt取出来的数据类型是字符
sum =sum +praseFloat(score);
}
average =sum/num;
alert('班级总的成绩是' +sum);
alert('班级的平均分是:' +average);
while循环 先执行,再判断
do while 循环 先判断,再执行
区别 :while与do while相对for 可以做更复杂的判断
断点调试
- 浏览器中按F12–>sources–>找到要调试的文件
- 点击行号,设置断点,
- 刷新浏览器,完成断点设置
- Watch:监视,可以监听变量值的变化
- F11:程序单步执行,一行一行的让程序执行。
js命名规范及语法格式
七、数组
创建数组
-
利用new创建数组\
var arr = new Array();``
-
利用数组字面量来创建数组[]
var arr = [1,2,3];
求数组中最大值
// 声明一个保存最大元素的变量 max
// 默认最大值可以取数组中的第一个元素
// 遍历这个数组,把里面的每一个数组元素和这个max相比较
// 如果这个数组元素大于max 就把这个元素存到max里面,否则继续下一轮比较
// 最后输出这个max
var arr = [2, 6, 4, 7, 8, 8];
var max = arr[0];
for (var i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
console.log('该数组里面的最大值是:' + max);
筛选数组的方法
// 方法1.创建一个新数组用来存放旧数据
// 遍历原来的旧数组,通过一定的逻辑筛选出需要的数据
// 依次追加给新数组newArr
// 方法2.
var arr=[2,45,8,4,3,7,6];
var newArr = [];
//刚开始newArr.length就是0
for (var i=0; i < arr.length;i++){
if(arr[i] >= 10){
//新数组索引号应该从0开始,依次递增
neweArr[newArr.length] = arr[i];
}
}
console.log(newArr);
数组排序(冒泡排序)
冒泡排序:是一种算法,把一系列的数据按照一定的顺序排列进行显示(一次比较两个元素,如果顺序错误就把他们交换过来)
案例
八、函数
函数的概念、使用及参数
函数:就是封装了一段可被重复调用执行的代码块,通过此代码块可以实现大量的代码的重复使用。
函数使用
1.声明函数
// function 函数名 (){
// 函数体
// }
- function声明函数的关键字 全部小写
- 函数是做某件事 ,函数名一般是动词
- 函数不调用自己不执行
-
调用函数
函数名(); //通过调用函数名来执行函数体代码
-
函数的封装
-
函数 的封装就是把一个或多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口
-
简单理解:类似于将电脑配件整合装到机箱。
-
-
函数的参数
- 声明函数的时候,函数名括号里的是形参,形参默认值undefined
- 调用函数的时候,函数名括号里面的是实参。
// function 函数名(形参1,形参2){ // } // 函数名(实参1,实参2); // 形参是接收实参的
参数的作用:在函数内部某些值不能固定,我们可以通过参数在调用函数时传递不同的值进去。
函数的返回值
// function 函数名(){
// return 需要返回的结果;
// }
//函数名();
// 函数名() = return后面的结果
return 终止函数,即return语句之后的代码不会被执行。
return、continue、break区别
arguments的使用
作用:当我们不确定有多少个参数传递,可以用arguments来获取。
在js中arguments实际上是当前函数的内置对象,所有函数都内置了这个对象,arguments 对象里面存储了所有传递过来的实参。
function fn() {
console.log(arguments);
console.log(arguments[2]);
// 我们可以按照数组的方式遍历arguments
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
fn(1, 2, 3, 4, 5);
//伪数组 并不是真正意义上的数组
// 1. 具有数组的length属性
// 2. 按照索引的方式进行存储
// 3. 它没有真正数组的一些方法 pop() push()等
函数的两种声明方式
- 利用函数关键字自定义函数(命名函数)
function fn(){
}
fn();
- 函数表达式(匿名函数)
// var 变量名 = function(){};
var fun = function(aru){
console.log('我是函数表达式');
console.log(aru);
}
fun('pink老师');
//fun是变量名,不是函数名
// 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值,而函数表达式里面存的是函数;
//函数表达式也可以进行传递参数
作用域
- js作用域:就是代码名字(变量) 在某个范围内起作用和效果,目的是为了提高程序的可靠性更重要的是减少命名冲突
- js的作用域(es6)之前:全局作用域 局部作用域
- 全局作用域:整个script标签或者是一个单独的js文件
var num =10;
// var num =30;
console.log(num);
- 局部作用域(函数作用域) 在函数内部就是局部作用域,这个代码的名字只在函数内部器效果和作用
function fn(){
// 局部作用域
var num = 20;
console.log(num);
}
fn();
因此变量有局部变量和全局变量
从执行效率来看全局变量和局部变量
- 全局变量只有浏览器关闭时才会销毁,比较占内存资源
- 局部变量 当我们程序执行完毕就会销毁,比较节约内存资源
- 没有var 声明的变量当全局变量
注:js 现阶段没有块级作用域,我们js也是在es6的时候新增的块级作用域
// 块级作用域{} if{} for{},用花括号包起来的就是块级作用域
//java
if(xx){
int num = 10;
}
// 外面的是不能调用num的
if(3 < 5){
var num = 10;
}
console.log(num);
// 所以在js中可以调用这个num
作用域链
// 作用域链:内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值,这种结构我们称作作用域链 就近原则
function f1(){ // 外部函数
var num = 123;
function f2(){ // 内部函数
console.log(num);
}
f2();
}
var num = 456;
fn();
预解析
- 我们js引擎运行分为两步: 预解析 代码执行
- 预解析js引擎会把js 里面所有的 var 还有 function 提升到当前作用域的最前面
- 代码执行 按照代码书写的顺序从上往下执行
-
预解析分为变量解析(变量提升)和函数预解析(函数提升)
- 变量提升 就是把所有的变量声明提升到当前的作用域最前面 不提升赋值操作
- 函数提升 就是把所有的函数声明提升到当前作用域的最前面 不调用函数
// (1) 变量提升 console.log(num); // undefined var num = 10; // 以上相当于执行下面的代码 // var num; // console.log(num); // num = 10; // (2) 函数提升 // 例1 fn(); function fn(){ console.log(11); } // 例2 fun(); var fun = function(){ console.log(22); } // 函数表达式 调用必须写在函数表达式的下面 //相当于执行了以下代码 // var fun; // fun(); // fun = function(){ // console.log(22); // }
案例:
var num =10; //变量提升
function fn(){ // 函数提升
console.log(num);
var num = 20; //变量提升
console.log(num);
}
fn();
// 相当于以下代码
// var num;
// function fn(){
// var num;
// console.log(num);
// num = 20;
// console.log(num);
// }
// num = 10;
// fn();
特例:
var a = b = c = 9;
// 相当于 var a =9;b = 9;c = 9;b和c直接赋值 没有 var声明 当全局变量看
// 集体声明 var a = 9,b = 9,c = 9;
九、对象
对象的概念及创建对象的方法
对象的概念:对象是一组无序的相关属性和方法的集合。 一个具体的事物
-
属性:事物的特征 (常用名词)
-
方法:事物的行为 (常用动词)
利用对象字面量创建对象{}
// var obj = {}; //创建了一个空对象
var obj = {
uname:'叶问',
age:18,
sex:'男',
sayHi:function(){
console.log('hi~');
}
}
// (1)里面的属性或者方法我们采取键值对的形式 键 属性名 : 属性值
// (2) 多个属性或方法中间用逗号隔开的
// (3) 方法冒号后面跟的是一个匿名函数
使用对象
// (1)调用对象的属性 我们采取 对象名.属性名
console.log(obj.uname);
// (2) 还可以用 对象名['属性名']
console.log(obj['age']);
// (3) 调用对象的方法 sayHi 对象名.方法名() 千万别忘记添加小括号
obj.sayHi();
变量、属性、函数、方法的区别
-
变量和属性的相同,他们都是用来存储数据的
var num = 10; var ogj = { age:18 } console.log(obj.age); // console.log(age); // 变量 单独声明并赋值 使用的时候直接写变量名 单独存在 // 属性 在对象里面的 ,不需要声明的 使用时必须是 对象.属性
-
函数和方法的相同点: 都是实现某种功能 做某件事
不同: 函数是单独声明 并且调用的 函数名() 单独存在的,
方法 在对象里面 调用的时候 对象.方法()
利用new Object 创建对象
var obj = new Object(); // 创建了一个空的对象
obj.uname = '叶问';
obj.age = 18;
obj.sayHi = function(){
console.log('hi~');
}
// (1)利用等号 = 赋值的方法 添加对象的属性和方法
// (2)每个属性和方法之间用 分号结束
console.log(obj.uname);
console.log(obj['age']);
obj.sayHi();
构造函数
构造函数的作用:一次创建一个对象,里面很多的属性和方法是大量相同的 ,为了避免重复写代码,我们通过构造函数来利用这些重复代码。
-
构造函数里面封装的不是普通代码,而是对象
-
构造函数就是把对象里面的一些相同的属性和方法抽象出来封装到函数里面
利用构造函数创建对象
// 构造函数 举例:明星 泛指一大类
function Star(uname,age,sex){
this.name=uname;
this.age=age;
this.sex=sex;
this.sing = function(sang){
console.log(sang);
}
}
// 对象 特指一个具体的事物 如:刘德华
varldh = new Star('刘德华','18','男'); // 调用函数返回的是一个对象
// console.log(typeog ldh);
ldh.sing('冰雨');
// 1.构造函数名字首字母要大写
// 2.我们构造函数不需要return就可以返回结果
// 3.调用构造函数 必须要使用new
// 4.new Star()调用函数就创建了一个对象ldh{}
// 5.我们的属性和方法前面必须添加this
new关键字执行过程
- new构造函数可以在内存中创建一个空 的对象
- this 就会指向这个新的对象
- 执行构造函数里面的代码,给这个新对象添加属性和方法
- 返回这个新对象
遍历对象属性
for…in语句用于对数组或对象的属性进行循环操作
var obj = {
name:'fjal',
age:18,
fn:function(){}
}
// for (变量 in 对象)
for(var k in obj){
console.log(k); // k 变量 输出 得到的是属性名
console.log(obj[k]); // obj[k]得到的是属性值
}
小结:
内置对象
对象类别:
- 自定义对象
- 内置对象
- 浏览器对象
作用:提供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)
内置对象值js 语言自带的一些对象,其中常用的有:
Math对象
日期对象
数组对象
字符串对象
查文档
通过MDN/W3C 来查询
MDN:htttp://developer.mozilla.org/zh-CN/
- 如何学习对象中的方法
常用的对象
Math数学对象,不是一个构造函数,不需要new,可以直接使用里面的属性和方法
console.log(Math.PI); // 一个属性 圆周率
console.log(Math.max(1,99,3)); //99
随机数案例:
// Math.random()方法生成随机数
function getRandom(min,max){
return Math.floor(Math.random()*(max - min + 1)) +min; // 这个公式得到一个随机整数
}
var random = getRandom(1,10);
while(true){
var num = prompt('你来猜 输入1~10之间的一个数字');
if(num > random){
alert('你猜大了');
}else if(num < random){
alert('你猜小了');
}else {
alert('你好帅哦,猜对了');
break; //退出整个循环结束程序
}
}
日期对象
// Date() 是一个构造函数 必须使用new 来调用创建我们的日期对象
var arr = new Array(); // 创建一个数组对象
var obj = new Object(); // 创建一个对象实例
// 1. 使用Data, 如果没有参数,返回当前系统的当前时间
var date = new Date();
console.log( date);
// 2.参数常用写法
var date1 = new Date(2019,10,1);
console.log(date1); // 返回的是11月 不是10月
var date2 = new Date('2019-10-1 8:8:8');
console.log(date2)
日期格式化
案例:
// 要求封装一个函数返回当前的时分秒 格式 08:08:08
function getTime(){
var time = new Date();
var h = time.getHours();
h = h < 10 ? '0' + h : h;
var m = time.getMinutes();
m = m < 10 ? '0' + m : m;
var s = time.getSeconds();
s = s < 10 ? '0' + s : s;
return h + ':' + m + ':' + s;
}
console.log(getTime());
获得Date总的毫秒数
// 不是当前的毫秒数, 而是距离1970年1月1日过了多少毫秒数
// 1. 通过valueOf() getTime()
var date = new Date();
console.log(date.valueOf()); // 就是我们现在时间距离1970.1.1总的毫秒数
console.log(date.getTime());
// 2.简单的写法(最常用的)
var date1 = +new Date(); // +new Date() 返回的就是总的毫秒数
console.log(date1);
// 3.H5新增的 获得总的毫秒数
console.log(Date.now());
倒计时效果
function countDown(time) {
var nowTime = +new Date();
var inputTime = +new Date(time);
var times = (inputTime - nowTime) / 1000; // times是剩余走时间
var d = parseInt(times / 60 / 60 / 24); //天
d = d <10 ? '0' + d : d;
var h = parseInt(times / 60 / 60 % 24); //时
h = h <10 ? '0' + h : h;
var m = parseInt(times / 60 % 60); //分
m = m <10 ? '0' + m : m;
var s = parseInt(times % 60); //当前秒
s = s <10 ? '0' + s : s;
return d + '天' + h + '时' + m + '分' + s + '秒';
}
console.log(countDown('2021-8-13 20:10:00'));
数组对象
检测是否为数组
- instanceof 运算符 可以用来检测
var arr = [];
console.log(arr instanceof Array); // ture
-
Array.isArray(参数); H5新增的方法 ie9以上的版本支持
console.log(Array.isArray(arr)); // ture
添加删除数组元素的方法
- push()在我们数组的末尾 添加一个或者多个数组的元素 push 推
var arr = [1,2,3]; arr.push(4,'pink');
console.log(arr);
// (1) push 是可以给数组追加新的元素
// (2) push() 参数直接写 数组元素就可以了
// (3) push完毕之后,返回的结果是 新数组的长度
// (4) 原数组也会发生变化
-
unshift() 在数组开头 添加一个或者多个数组元素
-
pop() 可以删除数组最后一个元素
console.log(arr.pop()); console.log(arr);
- pop() 没有参数
- pop完毕之后,返回的结果是删除的那个元素
-
shift() 可以删除数组的第一个元素
数组排序
// 1.翻转数组
var arr = ['pink', 'red', 'blue'];
arr.reverse();
console.log(arr);
// 2.数组排序(冒泡排序)
var arr1 = [12, 3, 77, 1, 7];
arr1.sort(function(a, b) {
return a - b; //升序排列
// return b-a; //降序排列
})
console.log(arr1);
数组索引
-
返回数组元素索引号方法 indexOf(数组元素) 作用是返回该数组元素的索引号从前面开始查找
- 它只返回第一个满足条件的索引号
- 它如果在该数组里面找不到元素,则返回-1
var arr = ['red','green','blue','pink','blue']; console.log(arr.indexOf('blue'));
- lastIndexOf(数组元素) 作用就是返回该数组元素的索引号 从后面开始查找
数组去重案例:
// 封装一个去重的函数 unique 独一无二的
function unique(arr){
var newArr = [];
for (var i =0;i < arr.length; i++){
if(newArr.indexOf(arr[i]) === -1){
newArr.push(arr[i]);
}
}
return newArr;
}
var demo = unique(['c','a','z','a','x','a','c']);
console.log(demo);
数组转换为字符串
// 1. toString()
var arr = [1,2,3];
console.log(arr.toString());
//2.join(分隔符)
console.log(arr.join('-')); // 1-2-3
数组连接、截取、删除(第几个开始,要删除的个数);
字符串对象
基本包装类型: 就是把简单数据类型 包装成为了复杂数据类型
//1. 生成临时变量,把简单类型包装为复杂数据类型
var temp = new String('andy');
// 2.赋值给我们声明的字符变量
str = temp;
// 3.销毁临时变量
temp = null;
字符串的不可变性:
根据字符查找
var str = '改革春风吹满地';
console.log(str.indexOf('春'));
经典案例:
var str = 'avcoefoxyfjoalef';
var num = 0;
var index = str.indexOf('o');
// console.log(index);
while (index !== -1) { //不是-1,即是找到了字符
console.log(index);
num++;
index = str.indexOf('o', index + 1);
}
console.log('o出现的次数是:' + num);
根据位置返回字符
// 1. charAt(index)
var str = 'andy';
console.log(str.charAt(3));
// 遍历所有的字符
for (var i = 0;i < str.length;i++){
console.log(str.charAt(i));
}
// 2.charCodeAt(index) 目的:判断用户按下了哪个键;
console.log(str.charCodeAt(0)); //97
// 3.str[index] H5新增的
console.log(str[0]); //a
统计出现最多的字符及其次数案例:
var str = 'fasefaewfsasdfjewo';
var a = {};
for (var i = 0;i < str.length;i++){
var chars = str.charAt(i);
// console.log(chars);
//chars 是字符串的每一个字符
if (a[chars]){
// a[chars]得到的是属性值
a[chars]++;
}else {
a[chars] = 1;
}
}
console.log(a);
// 2. 遍历对象
var max = 0 ;
var ch = '';
for(var k in a){
// k得到是属性名
// a[k]得到的是属性值
if (a[k] > max){
max = a[k];
ch = k;
}
}
console.log(max);
console.log('最多的字符是:' + ch);
字符串操作方法
- 字符拼接
- 字符截取
- 字符转数组
- 字符替换
// 字符串操作方法
// 1. concat('字符串1','字符串2'......)
var str = 'andy';
console.log(str.concat('red'));
//2.substr('截取的起始位置','截取的几个字符');
var str1 = '尬死了干净啊是垃圾';
console.log(str1.substr(2,2)); //第一个2是索引号的2 从第几个开始 第二个2是取几个字符
数据类型
一个特殊的简单数据类型
// 简单数据类型 null 返回的是一个空对象 object
var timer = null;
console.log(typeof timer);
//如果有个变量我们以后打算存储为对象,暂时没想好放啥,这个时候就给null;
堆和栈
- 栈:简单数据类型放到栈里面,
- 堆:复杂数据类型放到堆里面,
简单数据类型饭放在栈里面,直接开辟一个空间
复杂数据类型
复杂数据类型的传参
函数的形参也可以看作一个变量,当我们把引用类型变量传给形参时,其实时把变量在栈空间保持的堆地址复制给了形参,形参和实参保存同一个堆地址,所以操作的是同一个对象。
十、web APIs
API和 web API
DOM
DOM: 文档对象模型,是W3C组织推荐的处理可扩展标记语言的标准编程接口
DOM树:
- 文档:一个页面就是一个文档,DOM中使用document表示
- 元素:页面中的的所有标签都是元素,DOM中使用element表示
- 节点:网页中的所有内容都是节点(标签, 属性, 文本, 注释等), DOM中使用node表示
DOM把以上内容都可以看作是对象
获取元素
- 根据ID获取
- 根据标签名获取
- 通过HTML5新增的方法获取
- 特殊元素获取
- getElementById()方法获取id
<div id="time">2021-8-14</div>
<script>
//1.因为我们文档页面从上往下加载,所以得先有标签,所以我们的script写在标签下面
//2.get 获得element 元素 by通过驼峰命名法
//3.参数id是大小写敏感的字符串
//4.返回的是一个元素对象
var timer = document.getElementById('time');
console.log(timer);
console.log(typeof timer);
// 5. console.dir 打印我们返回的元素对象 更好的查看属性和方法
console.dir(timer);
timer.innerHTML = '2014'; //修改了文本的内容
</script>
- 根据标签名获取
使用 getElementsByTagName() 获取标签名
<ul id="ul">
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
<li>生僻字</li>
</ul>
<script>
// 1. 返回的是 获取过来元素对象的集合, 以为数组的形式存储
var lis = document.getElementsByTagName('li');
console.log(lis);
console.log(lis[0]);
// 2.我们想要依次打印 里面的元素对象我们可以采取遍历的方式
for (var i = 0; i < lis.length; i++) {
console.log(lis[i]);
}
//3.页面返回的是伪数组的形式
// 4.也可以父元素的形式获取子元素的标签
var ul = document.getElementById('ul'); //父元素必须是唯一的 指定的单个元素
console.log(ul.getElementsByTagName('li'));
</script>
-
通过HTML5新增的方法获取
- 根据类名
- 根据指定选择器返回第一个元素对象
- 根据指定选择器返回
<div class = 'box'>
盒子
</div>
<div class = 'box'>
盒子
</div>
<div id='nav'>
<ul>
<li>首页</li>
<li>产品</li>
</ul>
</div>
<script>
// 1.getElementsByClassName 根据类名获得某些元素集合
// 2. querySelector 返回指定选择器的第一个元素对象
var firstBox = document.querySelector('.box');
console.log(firstBox);
var nav = document.querySelector('#nav');
</script>
获取特殊元素
//1. 获取body元素
var bodyEle = document.body;
console.log(bodyEle);
console.log(bodyEle);
//2.获取html元素
// var htmlEle = document.html;
var htmlEle = document.documentElement;
console.log(htmlEle);
事件
事件:由三部分组成,事件源 事件类型 事件处理程序 ,这是事件三要素
- 事件源 事件被触发
- 事件类型 如何触发
- 事件处理
事件执行的步骤
- 获取事件源
- 注册事件(绑定事件)
- 添加事件处理程序(采取函数赋值的形式)
操作 元素
DOM操作可以改变网页的内容,结构,样式.
改变元素内容
案例:
<button>
显示当前系统时间
</button>
<div>
某个时间
</div>
<p>asfa</p>
<script>
// 当我们点击了按钮,div里面的文字就会发生变化
// 1. 获取元素
var btn = document.querySelector('button');
var div = document.querySelector('div');
// 2.注册事件
btn.onclick = function() {
// div.innerText = '2019-6-6';
div.innerText = getTime();
}
function getTime() {
var time = new Date();
var h = time.getHours();
h = h < 10 ? '0' + h : h;
var m = time.getMinutes();
m = m < 10 ? '0' + m : m;
var s = time.getSeconds();
s = s < 10 ? '0' + s : s;
return h + ':' + m + ':' + s;
}
// 我们元素可以不用添加事件
var p = document.querySelector('p');
p.innerText = getTime();
</script>
innerText 和 innerHTML的区别
<div></div>
<p>
我是文字
<span>sljf</span>
</p>
<script>
// 1.innerText不识别html标签 非标准 去除空格和换行
var div = document.querySelector('div');
// div.innerText = '<strong>今天是:</strong> 2019';
// 2.innerHTML 识别html W3C标准 保留空格和换行的
// 这两个是可读写的 可以获取元素里面的内容
var p = document.querySelector('p');
console.log(p.innerText);
console.log(p.innerHTML);
</script>
常用元素的属性操作
- innerText、innerHTML改变元素内容
- src、href
- id、alt、title
案例:
分时显示不同在图片,显示不同问候语
思路
<img src="img/s中午好.gif" alt="">
<div>
中午好
</div>
<script>
//1.获取元素
var img = document.querySelector('img');
var div = document.querySelector('div');
//2.得到当前的小时数
var date = new Date();
var h = date.getHours();
// 3.判断小时数改变图片和文字信息
if (h > 12) {
img.src = 'img/s中午好.gif';
div.innerHTML = '中午好';
} else {
img.src = 'img/上午好.gif';
div.innerHTML = '亲,上午好'
}
</script>
表单元素的属性操作
<button>
按钮
</button>
<input type="text" value="输入内容">
<script>
// 1.获取元素
var btn = document.querySelector('button');
var input = document.querySelector('input');
// 2.注册事件 处理程序
btn.onclick = function() {
//input.innerHTML = '点击了';这是个普通盒子 比如div 标签里面的内容
// 表单里面的值 文字内容是通过value来修改的
input.value = '被点击了';
//如果想要某个表单被禁用 不能在点击 用disabled来达到这个按钮button禁用的效果
//btn.disabled = true;
this.disabled = true;
//this指向的是事件函数的调用者 btn
}
</script>
仿京东密码显示隐藏案例:
<div class="box">
<label for="">
<img src="img/yan.jpg" alt="" id="eye">
</label>
<input type="password" name="" id="pwd">
</div>
<script>
// 1.获取元素
var eye = document.getElementById('eye');
var pwd = document.getElementById('pwd');
//2.注册事件 处理程序
var flag = 0;
eye.onclick = function() {
// 点击一次之后 ,flag一定要变化
if (flag == 0) {
pwd.type = 'text';
eye.src = 'img/s中午好.gif';
flag = 1;
} else {
pwd.type = 'password';
eye.src = 'img/yan.jpg';
flag = 0;
}
}
</script>
样式属性操作
<style>
div{
width: 200px;
height:200px;
background-color:pink;
}
</style>
<div>
</div>
<script>
//1.获取元素
var div = document.querySelector('div');
//2.注册事件 处理程序
div.onclick = function(){
//div.style里面的属性采取驼峰命名法
this.style.backgroundColor = 'purple';
this.style.width = '250px';
}
</script>
循环精灵图案例:
<style>
.box {
width: 250px;
margin: 100 auto;
}
.box li {
background-color: firebrick;
width: 24px;
height: 24px;
margin: 15px auto;
background: url(img/精灵图.png) no-repeat;
}
</style>
<div class="box">
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</div>
<script>
//1.获取元素 所有的小li
var lis = document.querySelectorAll('li');
for (var i = 0; i < lis.length; i++) {
//让索引号乘以44,就是每个li背景y坐标, index就是我们的y 坐标
var index = i * 44;
lis[i].style.backgroundPosition = '0 -' + index + 'px';
}
</script>
显示隐藏文本框内容
<input type="text" value="手机">
<script>
// 1.获取元素
var text = document.querySelector('input');
//2.注册事件 获得焦点事件 onfocus
text.onfocus = function() {
// console.log('得到了焦点');
if (this.value === '手机') {
this.value = '';
}
// 获得焦点文本框文字变黑
this.style.color = '#333';
}
// 3. 注册事件 失去焦点事件 onblur
text.onblur = function() {
if (this.value === '') {
this.value = '手机';
}
//失去焦点文本框颜色变浅
this.style.color = '#999';
}
</script>
className更元素样式
总结
操作元素
- 操作元素内容
- innerText
- innerHTML
- 操作常见元素属性
- src , href , title ,alt等
- 操作表单元素属性
- type, value , disabled等
- 操作元素样式属性
- element.style
- className
排他算法
<button>按钮1</button>
<button>按钮2</button>
<button>按钮3</button>
<button>按钮4</button>
<script>
// 1. 获取所有按钮元素
var btns = document.getElementsByTagName('button');
// btns是伪数组 里面每一个元素 btns[i]
for (var i = 0; i < btns.length; i++) {
btns[i].onclick = function() {
//(1)我们先把所有的按钮背景色去掉, 干掉所有人
for (var i = 0; i < btns.length; i++) {
btns[i].style.backgroundColor = '';
}
// (2)然后才让当前的元素背景颜色为pink 留下我自己
this.style.background = 'pink';
}
}
</script>
百度换肤案例:
表格经过变色案例
thead是不参与操作的
表单全选取消全选案例:
<div class="wrap">
<table>
<thead>
<tr>
<th>
<input type="checkbox" id="j_cbAll">
</th>
<th>商品</th>
<th>价钱</th>
</tr>
</thead>
<tbody id="j_tb">
<tr>
<td>
<input type="checkbox">
</td>
<td>sadf</td>
<td>sdaf</td>
</tr>
<tr>
<td>
<input type="checkbox">
</td>
<td>dsf</td>
<td>sfsa</td>
</tr>
<tr>
<td>
<input type="checkbox">
</td>
<td>dfs</td>
<td>sdfasd</td>
</tr>
</tbody>
</table>
</div>
<script>
var j_cbAll = document.getElementById('j_cbAll'); //全选按钮
var j_tbs = document.getElementById('j_tb').getElementsByTagName('input'); //下面所有的复选框
j_cbAll.onclick = function() {
// this.checked 可以得到当前复选框的选中状态,flase未选中,ture选中
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].checked = this.checked;
}
}
// 2. 下面复选框需要全部选中, 上面全选才能选中做法: 给下面所有复选框绑定点击事件,每次点击,都要循环查看下面所有的复选框是否有没选中的,如果有一个没选中的, 上面全选就不选中。
for (var i = 0; i < j_tbs.length; i++) {
j_tbs[i].onclick = function() {
// flag 控制全选按钮是否选中
var flag = true;
// 每次点击下面的复选框都要循环检查者4个小按钮是否全被选中
for (var i = 0; i < j_tbs.length; i++) {
if (!j_tbs[i].checked) {
flag = false;
break; // 退出for循环 这样可以提高执行效率 因为只要有一个没有选中,剩下的就无需循环判断了
}
}
j_cbAll.checked = flag;
}
}
</script>
自定义属性操作
区别:
- element.属性 获取的是内置属性值(元素本身自带的属性)
- element.getAttribute(‘属性’); 主要获得自定义的属性(标准) 我们程序员自定义的属性
<div id="demo" index="1" class="nav"></div>
<script>
var div = document.querySelector('div');
// 1. 获取元素的属性值
// (1) element.属性
console.log(div.id);
//(2) element.getAttribute('属性') get得到获取 attribute 属性的意思 我们程序员自己添加的属性我们称为自定义属性 index
console.log(div.getAttribute('id'));
console.log(div.getAttribute('index'));
// 2. 设置元素属性值
// (1) element.属性= '值'
div.id = 'test';
div.className = 'navs';
// (2) element.setAttribute('属性', '值'); 主要针对于自定义属性
div.setAttribute('index', 2);
div.setAttribute('class', 'footer'); // class 特殊 这里面写的就是class 不是className
// 3 移除属性 removeAttribute(属性)
div.removeAttribute('index');
</script>
重点案例:
tab栏切换
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
.tab {
width: 978px;
margin: 100px auto;
}
.tab_list {
height: 39px;
border: 1px solid #ccc;
background-color: #f1f1f1;
}
.tab_list li {
float: left;
height: 39px;
line-height: 39px;
padding: 0 20px;
text-align: center;
cursor: pointer;
}
.tab_list .current {
background-color: #c81623;
color: #fff;
}
.item_info {
padding: 20px 0 0 20px;
}
.item {
display: none;
}
</style>
//-----------------------------
<div class="tab">
<div class="tab_list">
<ul>
<li class="current">商品介绍</li>
<li>规格与包装</li>
<li>售后保障</li>
<li>商品评价(50000)</li>
<li>手机社区</li>
</ul>
</div>
<div class="tab_con">
<div class="item" style="display: block;">
商品介绍模块内容
</div>
<div class="item">
规格与包装模块内容
</div>
<div class="item">
售后保障模块内容
</div>
<div class="item">
商品评价(50000)模块内容
</div>
<div class="item">
手机社区模块内容
</div>
</div>
</div>
<script>
// 获取元素
var tab_list = document.querySelector('.tab_list');
var lis = tab_list.querySelectorAll('li');
var items = document.querySelectorAll('.item');
// for循环绑定点击事件
for (var i = 0; i < lis.length; i++) {
// 开始给5个小li 设置索引号
lis[i].setAttribute('index', i);
lis[i].onclick = function() {
// 1. 上的模块选项卡,点击某一个,当前这一个底色会是红色,其余不变(排他思想) 修改类名的方式
// 干掉所有人 其余的li清除 class 这个类
for (var i = 0; i < lis.length; i++) {
lis[i].className = '';
}
// 留下我自己
this.className = 'current';
// 2. 下面的显示内容模块
var index = this.getAttribute('index');
console.log(index);
// 干掉所有人 让其余的item 这些div 隐藏
for (var i = 0; i < items.length; i++) {
items[i].style.display = 'none';
}
// 留下我自己 让对应的item 显示出来
items[index].style.display = 'block';
}
}
</script>
-
设置H5自定义属性
H5规定自定义属性data-开头作为属性名并且赋值。
比如
<div data-index = "1"></div> //或者js设置 element.setAttribute('data-time',20);
节点操作
- 利用DOM提供的方法获取元素
- document.getElementById()
- document.getElementsByTagName()
- document.querySelector等
- 逻辑性不强
- 利用节点层级关系获取元素
- 利用父子兄节点关系获取元素
- 逻辑性强,但兼容性差
节点概述
- 元素节点nodeType为1;
- 属性节点nodeType为2
- 文本节点nodeType为3
<!-- 节点的优点 -->
<div>我是div</div>
<span>我是span</span>
<ul>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
<li>我是li</li>
</ul>
<div class="demo">
<div class="box">
<span class="erweima">×</span>
</div>
</div>
<script>
// 1. 父节点 parentNode
var erweima = document.querySelector('.erweima');
// var box = document.querySelector('.box');
// 得到的是离元素最近的父级节点(亲爸爸) 如果找不到父节点就返回为 null
console.log(erweima.parentNode);
//2.子节点
// DOM 提供的方法(API)获取
var ul = document.querySelector('ul');
var lis = ul.querySelectorAll('li');
// (1)子节点 childNodes 所有的子节点 包含 元素节点 文本节点等等
console.log(ul.childNodes);
console.log(ul.childNodes[0].nodeType);
console.log(ul.childNodes[1].nodeType);
//(2) children 获取所有的子元素节点 也是我们实际开发常用的
console.log(ul.children);
</script>
新浪下拉菜单案例:
<style>
* {
margin: 0;
padding: 0;
}
li {
list-style-type: none;
}
a {
text-decoration: none;
font-size: 14px;
}
.nav {
margin: 100px;
}
.nav>li {
position: relative;
float: left;
width: 80px;
height: 41px;
text-align: center;
}
.nav li a {
display: block;
width: 100%;
height: 100%;
line-height: 41px;
color: #333;
}
.nav>li>a:hover {
background-color: #eee;
}
.nav ul {
display: none;
position: absolute;
top: 41px;
left: 0;
width: 100%;
border-left: 1px solid #FECC5B;
border-right: 1px solid #FECC5B;
}
.nav ul li {
border-bottom: 1px solid #FECC5B;
}
.nav ul li a:hover {
background-color: #FFF5DA;
}
</style>
<ul class="nav">
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
<li>
<a href="#">微博</a>
<ul>
<li>
<a href="">私信</a>
</li>
<li>
<a href="">评论</a>
</li>
<li>
<a href="">@我</a>
</li>
</ul>
</li>
</ul>
<script>
//1. 获取元素
var nav = document.querySelector('.nav');
var lis = nav.children; //得到4个li
for(var i = 0;i < lis.length;i++){
lis[i].onmouseover = function(){
this.children[1].style.display = 'block';
}
lis[i].onmouseout = function(){
this.children[1].style.display = 'none'
}
}
</script>
兄弟节点
<div>我是div</div>
<span>我是span</span>
<script>
var div = document.querySelector('div');
// 1.nextSibling 下一个兄弟节点 包含元素节点或者 文本节点等等
console.log(div.nextSibling);
console.log(div.previousSibling);
// 2. nextElementSibling 得到下一个兄弟元素节点 (区分兄弟节点与兄弟元素节点)
console.log(div.nextElementSibling);
console.log(div.previousElementSibling);
</script>
element.nextElementSibling有兼容性问题
创建节点和添加节点
<ul>
<li>123</li>
</ul>
<script>
// 1. 创建节点元素节点
var li = document.createElement('li');
// 2. 添加节点 node.appendChild(child) node 父级 child 是子级 后面追加元素 类似于数组中的push
var ul = document.querySelector('ul');
ul.appendChild(li);
// 3. 添加节点 node.insertBefore(child, 指定元素);
var lili = document.createElement('li');
ul.insertBefore(lili, ul.children[0]);
// 4. 我们想要页面添加一个新的元素 : 1. 创建元素 2. 添加元素
</script>
简易版发布留言案例:
<textarea name="" id=""></textarea>
<button>
发布
</button>
<ul>
</ul>
<script>
var btn = document.querySelector('button');
var text = document.querySelector('textarea');
var ul = document.querySelector('ul');
btn.onclick = function() {
if (text.value == '') {
alert('您没有输入');
return false;
} else {
var li = document.createElement('li');
li.innerHTML = text.value + "<a href='javascript:;'>删除</a>"
ul.insertBefore(li, ul.children[0]);
var as = document.querySelectorAll('a');
for(var i = 0;i < as.length;i++){
as[i].onclick = function(){
ul.removeChild(this.parsetNode);
}
}
}
}
</script>
删除节点
node.removeChild(children),从DOM中删除一个子节点,返回删除的节点
删除留言案例,在上面
复制节点
node.cloneNode();
步骤:复制----添加
<ul>
<li>1111</li>
<li>2</li>
<li>3</li>
</ul>
<script>
var ul = document.querySelector('ul');
// 1. node.cloneNode(); 括号为空或者里面是false 浅拷贝 只复制标签不复制里面的内容
// 2. node.cloneNode(true); 括号为true 深拷贝 复制标签复制里面的内容
var lili = ul.children[0].cloneNode(true);
ul.appendChild(lili);
</script>
动态生成表格
- 准备好模拟的数据,用对象形式存储
- 往tbody里面创建行:(通过数组的长度)
- 创建有删除2个字的单元格
<table cellspacing="0">
<thead>
<tr>
<th>姓名</th>
<th>科目</th>
<th>成绩</th>
<th>操作</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<script>
// 1.先去准备好学生的数据
var datas = [{
name: '魏璎珞',
subject: 'JavaScript',
score: 100
}, {
name: '弘历',
subject: 'JavaScript',
score: 98
}, {
name: '傅恒',
subject: 'JavaScript',
score: 99
}, {
name: '明玉',
subject: 'JavaScript',
score: 88
}, {
name: '大猪蹄子',
subject: 'JavaScript',
score: 0
}];
// 2. 往tbody 里面创建行: 有几个人(通过数组的长度)我们就创建几行
var tbody = document.querySelector('tbody');
for (var i = 0; i < datas.length; i++) { // 外面的for循环管行 tr
// 1. 创建 tr行
var tr = document.createElement('tr');
tbody.appendChild(tr);
// 2. 行里面创建单元格(跟数据有关系的3个单元格) td 单元格的数量取决于每个对象里面的属性个数 for循环遍历对象 datas[i]
for (var k in datas[i]) { // 里面的for循环管列 td
// 创建单元格
var td = document.createElement('td');
// 把对象里面的属性值 datas[i][k] 给 td
// console.log(datas[i][k]);
td.innerHTML = datas[i][k];
tr.appendChild(td);
}
// 3. 创建有删除2个字的单元格
var td = document.createElement('td');
td.innerHTML = '<a href="javascript:;">删除 </a>';
tr.appendChild(td);
}
// 4. 删除操作 开始
var as = document.querySelectorAll('a');
for (var i = 0; i < as.length; i++) {
as[i].onclick = function() {
// 点击a 删除 当前a 所在的行(链接的爸爸的爸爸) node.removeChild(child)
// tbody是行的父节点,这个行是当前a链接所在行 父节点.removeChild(子节点); 这个父节点是相对于括号里的子节点而言的
tbody.removeChild(this.parentNode.parentNode)
}
}
// for(var k in obj) {
// k 得到的是属性名
// obj[k] 得到是属性值
// }
</script>
三种动态创建元素的区别:
- document.write是直接将内容写入页面的内容流,但文档流执行完毕,则它会导致页面全部重绘
- innerHTML是将内容写入某个DOM节点,不会导致页面重绘
- innerHTML创建多个元素效率更高(不要拼接字符串,采取数组形式拼接),结构稍微复杂
- createElement() 创建多个元素效率稍低一点点,但结构更清晰
总结:不同浏览器下,innerHTML比createElement的效率高
DOM核心
事件高级
注册事件
- 传统的注册事件
- 唯一性
- 同一个元素同一个事件只能设置一个处理函数,最后注册的处理函数将会覆盖之前注册的函数
- addEventListener事件监听方式注册事件
- IE9之前的浏览器不支持此方法,可使用attachEvent()代替
- 特点:同一个元素同一个事件可以注册多个监听器
- 按照顺序依次执行
- addEventListener它是一个方法
<button>
传统的注册事件
</button>
<button>
方法监听注册事件
</button>
<script>
var btns = document.querySelectorAll('button');
//1.传统的注册事件
btns[0].onclick = function() {
alert('hi');
}
btns[0].onclick = function() {
alert('hao a u');
}
// 2.方法监听注册事件
//(1)里面的事件类型是字符串,必定加引号 而且不带on
//(2)同一个元素 同一个事件可以添加多个侦听器(事件处理程序)
btns[1].addEventListener('click', function() {
alert(22);
})
btns[1].addEventListener('click', function() {
alert(33);
})
</script>
删除事件
<div>1</div>
<div>2</div>
<div>3</div>
<script>
var divs = document.querySelectorAll('div');
divs[0].onclick = function() {
alert(11);
// 1. 传统方式删除事件
divs[0].onclick = null;
}
// 2. removeEventListener 删除事件
divs[1].addEventListener('click', fn) // 里面的fn 不需要调用加小括号
function fn() {
alert(22);
divs[1].removeEventListener('click', fn);
}
// 3. detachEvent
divs[2].attachEvent('onclick', fn1);
function fn1() {
alert(33);
divs[2].detachEvent('onclick', fn1);
}
DOM事件流
DOM事件流分为3个阶段:
- 捕获阶段
- 当前目标阶段
- 冒泡阶段
概念:事件发生时会在元素节点之间按照特定的顺序传播这个传播过程及DOM事件流。
注意:
<div class="father">
<div class="son">son盒子</div>
</div>
<script>
// dom 事件流 三个阶段
// 1. JS 代码中只能执行捕获或者冒泡其中的一个阶段。
// 2. onclick 和 attachEvent(ie) 只能得到冒泡阶段。
// 3. 捕获阶段 如果addEventListener 第三个参数是 true 那么则处于捕获阶段 document -> html -> body -> father -> son
// var son = document.querySelector('.son');
// son.addEventListener('click', function() {
// alert('son');
// }, true);
// var father = document.querySelector('.father');
// father.addEventListener('click', function() {
// alert('father');
// }, true);
// 4. 冒泡阶段 如果addEventListener 第三个参数是 false 或者 省略 那么则处于冒泡阶段 son -> father ->body -> html -> document
var son = document.querySelector('.son');
son.addEventListener('click', function() {
alert('son');
}, false);
var father = document.querySelector('.father');
father.addEventListener('click', function() {
alert('father');
}, false);
document.addEventListener('click', function() {
alert('document');
})
</script>
事件对象
<div>123</div>
<script>
// 事件对象
var div = document.querySelector('div');
div.onclick = function(e) {
// console.log(e);
// console.log(window.event);
// e = e || window.event;
console.log(e);
}
// div.addEventListener('click', function(e) {
// console.log(e);
// })
// 1. event 就是一个事件对象 写到我们侦听函数的 小括号里面 当形参来看
// 2. 事件对象只有有了事件才会存在,它是系统给我们自动创建的,不需要我们传递参数
// 3. 事件对象 是 我们事件的一系列相关数据的集合 跟事件相关的 比如鼠标点击里面就包含了鼠标的相关信息,鼠标坐标啊,如果是键盘事件里面就包含的键盘事件的信息 比如 判断用户按下了那个键
// 4. 这个事件对象我们可以自己命名 比如 event 、 evt、 e
// 5. 事件对象也有兼容性问题 ie678 通过 window.event 兼容性的写法 e = e || window.event;
</script>
常见事件对象的属性和方法
区别:e.target指向我们点击的那个对象,我们点击li e.target指向的就是li
this返回的是绑定事件的对象(元素)
阻止默认行为
<div>
132
</div>
<a href = "http://www.baidu.com">百度</a>
<form action="http://www.biadu.com">
<input type="submit" value="提交" name = "sub">
</form>
<script>
//常见事件对象的属性和方法
//返回事件类型
var div = document.querySelector('div');
div.addEventListener('click',fn);
div.addEventListener('mouseout',fn);
div.addEventListener('mouseover',fn);
function fn(e){
console.log(e.type);
}
//2. 阻止默认行为(事件) 让链接不跳转 或者让提交按钮不提交
var a = document.querySelectot('a');
a.addEventListener('click',function(e){
e.prevertD
})
</script>
阻止事件冒泡
事件委托
也称事件代理,(常在面试问到)
原理:不是每个子节点单独设置事件监听器,而是事件监听器设置在其父节点上,然后利用冒泡原理影响设置每个子节点。
<ul>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
<li>知否知否,点我应有弹框在手!</li>
</ul>
<script>
// 事件委托的核心原理:给父节点添加侦听器, 利用事件冒泡影响每一个子节点
var ul = document.querySelector('ul');
ul.addEventListener('click', function(e) {
// alert('知否知否,点我应有弹框在手!');
// e.target 这个可以得到我们点击的对象
e.target.style.backgroundColor = 'pink';
})
</script>
常见鼠标事件
鼠标事件对象
案例:跟随鼠标的天使
<style>
img {
position: absolute;
top: 2px;
}
</style>
<img src="img/s中午好.gif" alt="">
<script>
var pic = document.querySelector('img');
document.addEventListener('mousemove',function(e){
//mousemove只要移动鼠标就会触发这个事件
// console.log(11);
var x = e.pageX;
var y = e.pageY;
pic.style.left = x + 'px';
pic.style.top = y + 'px';
})
</script>
常见键盘事件
键盘事件对象
<script>
// 键盘事件对象中的keyCode属性可以得到相应键的ASCII码值
// 1. 我们的keyup 和keydown事件不区分字母大小写 a 和 A 得到的都是65
// 2. 我们的keypress 事件 区分字母大小写 a 97 和 A 得到的是65
document.addEventListener('keyup', function(e) {
// console.log(e);
console.log('up:' + e.keyCode);
// 我们可以利用keycode返回的ASCII码值来判断用户按下了那个键
if (e.keyCode === 65) {
alert('您按下的a键');
} else {
alert('您没有按下a键')
}
})
document.addEventListener('keypress', function(e) {
// console.log(e);
console.log('press:' + e.keyCode);
})
</script>
案例:模拟京东按键输入案例
<input type = "text">
<script>
var search = document.querySelector('input');
document.addEventListener('keyup',function(e){
if(e.keyCode == 83){
search.focus();
}
})
</script>
模拟京东快递查询单号:
<div class="search">
<div class="con">123</div>
<input type="text" placeholder="请输入您的快递单号" class="jd">
</div>
<script>
// 快递单号输入内容时, 上面的大号字体盒子(con)显示(这里面的字号更大)
// 表单检测用户输入: 给表单添加键盘事件
// 同时把快递单号里面的值(value)获取过来赋值给 con盒子(innerText)做为内容
// 如果快递单号里面内容为空,则隐藏大号字体盒子(con)盒子
var con = document.querySelector('.con');
var jd_input = document.querySelector('.jd');
jd_input.addEventListener('keyup', function() {
// console.log('输入内容啦');
if (this.value == '') {
con.style.display = 'none';
} else {
con.style.display = 'block';
con.innerText = this.value;
}
})
// 当我们失去焦点,就隐藏这个con盒子
jd_input.addEventListener('blur', function() {
con.style.display = 'none';
})
//完美做法 当我们获得焦点,就显示这个con盒子
jd_input.addEventListener('focus', function() {
if (this.value !== '') {
con.style.display = 'block';
}
})
</script>
BOM
BOM概念
BOM是浏览器对象模型,它提供了独立于内容而与浏览器 ,它提供了独立于内容而与浏览器窗口进行交互的对象,其核心是window.
BOM的构成
window对象是浏览器的顶级对象,它具有双重角色
-
它是js访问浏览器窗口的一个接口;
-
它是一个全局对象,定义在作用域中的变量、函数都会变成window对象的属性和方法。
-
调用时可以省略window,前面学习的对话框都属于window对象方法,如alert()、prompt();
注意:window下的一个特殊属性window.name。
window对象的常见事件
- 窗口加载事件
<script>
//(1)传统注册事件
// window.onload = function() {
// var btn = document.querySelector('button');
// btn.addEventListener('click', function() {
// alert('点击我');
// })
// }
// window.onload = function() {
// alert(22);
// }
//(2)新的注册事件方法
window.addEventListener('load', function() {
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
alert('点击我');
})
})
window.addEventListener('load', function() {
alert(22);
})
document.addEventListener('DOMContentLoaded', function() {
alert(33);
})
// load 等页面内容全部加载完毕,包含页面dom元素 图片 flash css 等等
// DOMContentLoaded 是DOM 加载完毕,不包含图片 falsh css 等就可以执行 加载速度比 load更快一些
</script>
调整窗口大小事件
定时器
- setTimeout
- setin
<script>
// 1. setTimeout
// 语法规范: window.setTimeout(调用函数, 延时时间);
// 1. 这个window在调用的时候可以省略
// 2. 这个延时时间单位是毫秒 但是可以省略,如果省略默认的是0
// 3. 这个调用函数可以直接写函数 还可以写 函数名 还有一个写法 '函数名()'
// 4. 页面中可能有很多的定时器,我们经常给定时器加标识符 (名字)
// setTimeout(function() {
// console.log('时间到了');
// }, 2000);
function callback() {
console.log('爆炸了');
}
var timer1 = setTimeout(callback, 3000);
var timer2 = setTimeout(callback, 5000);
// setTimeout('callback()', 3000); // 我们不提倡这个写法
</script>
回调函数
停止定时器
<button>点击停止定时器</button>
<script>
var btn = document.querySelector('button');
var timer = setTimeout(function() {
console.log('爆炸了');
}, 5000);
btn.addEventListener('click', function() {
clearTimeout(timer);
})
</script>
- window.setInterval(调用函数,延时时间);
区别:setTimeout 延时时间到了, 就去调用这个回调函数,只调用依次
setInterval 每隔这个延时时间, 就去调用这个回调函数,会调用很多次,重复调用这个函数。
案例:
定时器
<div>
<span class="hour"></span>
<span class="minute"></span>
<span class="second"></span>
</div>
<script>
var hour = document.querySelector('.hour');
var minute = document.querySelector('.minute');
var second = document.querySelector('.second');
var inputTime = +new Date('2021-8-17 18:00:00');
countDown(); // 我们先调用一次这个函数,防止第一次刷新页面有空白
//开启定时器
setInterval(countDown, 1000);
function countDown() {
var nowTime = +new Date(); // 返回的是当前时间总的毫秒数
var times = (inputTime - nowTime) / 1000; // times是剩余时间总的秒数
var h = parseInt(times / 60 / 60 % 24); //时
h = h < 10 ? '0' + h : h;
hour.innerHTML = h; // 把剩余的小时给 小时黑色盒子
var m = parseInt(times / 60 % 60); // 分
m = m < 10 ? '0' + m : m;
minute.innerHTML = m;
var s = parseInt(times % 60); // 当前的秒
s = s < 10 ? '0' + s : s;
second.innerHTML = s;
}
</script>
停止定时器clearInterval
发送短信案例:
手机号码: <input type="number"> <button>发送</button>
<script>
// 按钮点击之后,会禁用 disabled 为true
// 同时按钮里面的内容会变化, 注意 button 里面的内容通过 innerHTML修改
// 里面秒数是有变化的,因此需要用到定时器
// 定义一个变量,在定时器里面,不断递减
// 如果变量为0 说明到了时间,我们需要停止定时器,并且复原按钮初始状态
var btn = document.querySelector('button');
var time = 3; // 定义剩下的秒数
btn.addEventListener('click', function() {
btn.disabled = true;
var timer = setInterval(function() {
if (time == 0) {
// 清除定时器和复原按钮
clearInterval(timer);
btn.disabled = false;
btn.innerHTML = '发送';
} else {
btn.innerHTML = '还剩下' + time + '秒';
time--;
}
}, 1000);
})
</script>
this指向问题
this 指向问题 一般情况下this的最终指向的时调用它的对象
- 全局作用域或者普通函数中this指向全局对象window( 特殊:定时器里面的this指向window)
- 方法调用中谁调用this指向谁
- 构造函数中this指向构造函数的实例
<button>
点击
</button>
<script>
console.log(this);
function fn() {
console.log(this);
}
window.fn();
window.setTimeout(function() {
console.log(this);
}, 1000);
// 2. 方法调用中谁调用this指向谁
var o = {
sayHi: function() {
console.log(this); // this指向的是 o 这个对象
}
}
o.sayHi();
var btn = document.querySelector('button');
// btn.onclick = function() {
// console.log(this); // this指向的是btn这个按钮对象
// }
btn.addEventListener('click', function() {
console.log(this); // this指向的是btn这个按钮对象
})
// 3. 构造函数中this指向构造函数的实例
function Fun() {
console.log(this); // this 指向的是fun 实例对象,而不是Fun;
}
var fun = new Fun();
</script>
js执行机制
同步和异步
同步任务:在主线程里面执行,形成一个执行栈
异步任务:js的异步任务通过回调函数实现
异步类型:
1. 普通事件,如click 、resize等
2. 资源加载,如load、error等
3. 定时器,包括setInterval、setTimeout等
异步任务相关回调函数添加 到任务队列中。
location对象
什么是location对象
url概念:
location对象的属性
获取URL参数
//1.log.html
<form action = "index.html">
用户名:<input type = "text" name="uname">
<input type="submit" value="登录">
</form>
//2.index.html
<div>
</div>
<script>
console.log('location.search');
var params = location.search.substr(1);
var arr = params.split('=');
var div= document.querySelector('div');
div.innerHTML=arr[1] +'欢迎你'
</script>
location常见的方法
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 记录浏览历史,所以可以实现后退功能
// location.assign('http://www.itcast.cn');
// 不记录浏览历史,所以不可以实现后退功能
// location.replace('http://www.itcast.cn');
location.reload(true);
})
</script>
navigator对象
history对象
//index.html
<a href="list.html">点击我去往列表页</a>
<button>前进</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// history.forward();
history.go(1);
})
</script>
//list.html
<a href="index.html">点击我去往首页</a>
<button>后退</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// history.back();
history.go(-1);
})
</script>
function fn() {
console.log(this);
}
window.fn();
window.setTimeout(function() {
console.log(this);
}, 1000);
// 2. 方法调用中谁调用this指向谁
var o = {
sayHi: function() {
console.log(this); // this指向的是 o 这个对象
}
}
o.sayHi();
var btn = document.querySelector('button');
// btn.onclick = function() {
// console.log(this); // this指向的是btn这个按钮对象
// }
btn.addEventListener('click', function() {
console.log(this); // this指向的是btn这个按钮对象
})
// 3. 构造函数中this指向构造函数的实例
function Fun() {
console.log(this); // this 指向的是fun 实例对象,而不是Fun;
}
var fun = new Fun();
</script>
#### js执行机制
同步和异步
[外链图片转存中...(img-gn0e1YnE-1629369807301)]
同步任务:在主线程里面执行,形成一个执行栈
异步任务:js的异步任务通过回调函数实现
异步类型:
1. 普通事件,如click 、resize等
2. 资源加载,如load、error等
3. 定时器,包括setInterval、setTimeout等
异步任务相关回调函数添加 到任务队列中。
[外链图片转存中...(img-n0fPME7U-1629369807303)]
[外链图片转存中...(img-A2Zftvd3-1629369807306)]
#### location对象
什么是location对象
[外链图片转存中...(img-KE2TSPuM-1629369807307)]
url概念:
[外链图片转存中...(img-VnSd6iQB-1629369807309)]
location对象的属性
[外链图片转存中...(img-SQJPiEjI-1629369807311)]
获取URL参数
```html
//1.log.html
<form action = "index.html">
用户名:<input type = "text" name="uname">
<input type="submit" value="登录">
</form>
//2.index.html
<div>
</div>
<script>
console.log('location.search');
var params = location.search.substr(1);
var arr = params.split('=');
var div= document.querySelector('div');
div.innerHTML=arr[1] +'欢迎你'
</script>
location常见的方法
[外链图片转存中…(img-UZ2B6PSP-1629369807316)]
<button>点击</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// 记录浏览历史,所以可以实现后退功能
// location.assign('http://www.itcast.cn');
// 不记录浏览历史,所以不可以实现后退功能
// location.replace('http://www.itcast.cn');
location.reload(true);
})
</script>
navigator对象
[外链图片转存中…(img-HNFFwAoD-1629369807318)]
history对象
[外链图片转存中…(img-ybHaFp4q-1629369807321)]
//index.html
<a href="list.html">点击我去往列表页</a>
<button>前进</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// history.forward();
history.go(1);
})
</script>
//list.html
<a href="index.html">点击我去往首页</a>
<button>后退</button>
<script>
var btn = document.querySelector('button');
btn.addEventListener('click', function() {
// history.back();
history.go(-1);
})
</script>